Spaces:
No application file
No application file
| # Freeplay Traces Implementation Plan | |
| ## Overview | |
| This document outlines the implementation plan for integrating Freeplay Traces into the existing Huge League Soccer application. Traces provide enhanced observability by grouping LLM interactions within a session, allowing us to track input questions, LLM responses, and associated metadata. | |
| ## Current Architecture | |
| ### Existing Freeplay Integration Points | |
| 1. **Session Management** (`api/server_gradio.py`) | |
| - `AppState.ensure_sessions()` - Creates Freeplay session on first user interaction | |
| - Session ID preserved across state changes | |
| 2. **Prompt Management** (`api/workflows/base.py`) | |
| - `call_model()` - Retrieves persona-specific prompts via `get_prompt_by_persona()` | |
| - Uses Freeplay prompt templates (casual_fan_prompt, super_fan_prompt) | |
| 3. **Session Recording** (`api/workflows/base.py`) | |
| - `should_continue()` - Records final LLM responses to Freeplay session | |
| - Uses `record_session()` method | |
| ## Proposed Traces Implementation | |
| ### AppState Enhancement | |
| The `AppState` class will be enhanced to store the actual Freeplay session object, allowing direct access to `session.create_trace()` as shown in the original documentation. | |
| ### Modified Methods | |
| ```python | |
| # api/utils/freeplay_helpers.py - Modified method | |
| def record_session(self, state, end: Optional[float] = time.time(), | |
| formatted_prompt: Optional[FormattedPrompt] = None, | |
| prompt_vars: Optional[dict] = None, | |
| trace_info: Optional[TraceInfo] = None): # NEW PARAMETER | |
| # ... existing code ... | |
| payload = RecordPayload( | |
| # ... existing fields ... | |
| trace_info=trace_info # NEW FIELD | |
| ) | |
| ``` | |
| ## Implementation Flow | |
| ### 1. AppState Enhancement | |
| **Location:** `api/server_gradio.py` - `AppState` class | |
| ```python | |
| class AppState(BaseModel): | |
| # ... existing fields ... | |
| freeplay_session_id: str = "" | |
| freeplay_session: Optional[Any] = None # NEW: Store the actual session object | |
| def ensure_sessions(self): | |
| if not self.zep_session_id: | |
| self.zep_session_id = ZepClient() \ | |
| .get_or_create_user(self.email, self.first_name, self.last_name) \ | |
| .create_session() \ | |
| .session_id | |
| if not self.freeplay_session_id: | |
| freeplay_client = FreeplayClient() | |
| self.freeplay_session = freeplay_client.create_session() # Store session object | |
| self.freeplay_session_id = self.freeplay_session.session_id | |
| ``` | |
| ### 2. User Input & Trace Creation | |
| **Location:** `api/server_gradio.py` - `submit_helper()` | |
| ```python | |
| def submit_helper(state, handler, user_query): | |
| state.ensure_sessions() # Freeplay session already exists | |
| # Create trace directly on the session object | |
| trace_info = state.freeplay_session.create_trace( | |
| input=user_query, # optional metadata not included | |
| ) | |
| # Pass trace_info to workflow | |
| workflow_bundle, workflow_state = build_workflow_with_state( | |
| handler=handler, | |
| zep_session_id=state.zep_session_id, | |
| freeplay_session_id=state.freeplay_session_id, | |
| email=state.email, | |
| first_name=state.first_name, | |
| last_name=state.last_name, | |
| persona=state.persona, | |
| messages=state.history, | |
| trace_info=trace_info, # NEW: Pass trace_info to workflow | |
| ) | |
| ``` | |
| ### 3. Workflow State Enhancement | |
| **Location:** `api/workflows/base.py` - `AgentState` | |
| ```python | |
| class AgentState(TypedDict): | |
| # ... existing fields ... | |
| trace_info: Optional[TraceInfo] = None # NEW | |
| ``` | |
| ### 4. Workflow Builder Enhancement | |
| **Location:** `api/workflows/base.py` - `build_workflow_with_state()` | |
| ```python | |
| def build_workflow_with_state(handler: AsyncCallbackHandler, | |
| zep_session_id: Optional[str] = None, | |
| freeplay_session_id: Optional[str] = None, | |
| email: Optional[str] = None, | |
| first_name: Optional[str] = None, | |
| last_name: Optional[str] = None, | |
| persona: Optional[str] = None, | |
| messages: Optional[List[BaseMessage]] = None, | |
| trace_info: Optional[TraceInfo] = None) -> Tuple[WorkflowBundle, AgentState]: # NEW PARAMETER | |
| """ | |
| Utility to build workflow and initial state in one step. | |
| """ | |
| bundle = build_workflow(handler) | |
| state = { | |
| "zep_session_id": zep_session_id, | |
| "freeplay_session_id": freeplay_session_id, | |
| "email": email, | |
| "first_name": first_name, | |
| "last_name": last_name, | |
| "persona": persona, | |
| "messages": messages or [], | |
| "start_time": time.time(), | |
| "zep_memory": None, | |
| "trace_info": trace_info, # NEW: Populate trace_info in AgentState | |
| } | |
| return bundle, state | |
| ``` | |
| ### 5. LLM Processing with Trace Association | |
| **Location:** `api/workflows/base.py` - `call_model()` | |
| ```python | |
| async def call_model(state: AgentState, | |
| handler: AsyncCallbackHandler, | |
| zep_client: ZepClient, | |
| freeplay_client: FreeplayClient) -> dict: | |
| # ... existing prompt and LLM logic ... | |
| # Record trace output with LLM response | |
| if state.get("trace_info"): | |
| final_response = response.content if hasattr(response, 'content') else str(response) | |
| state["trace_info"].record_output( | |
| project_id=FREEPLAY_PROJECT_ID, | |
| output=final_response | |
| ) | |
| return {'messages': [response], 'zep_memory': memory} | |
| ``` | |
| ### 6. Session Recording with Trace | |
| **Location:** `api/workflows/base.py` - `should_continue()` | |
| ```python | |
| async def should_continue(state: AgentState, | |
| handler: AsyncCallbackHandler, | |
| zep_client: ZepClient, | |
| freeplay_client: FreeplayClient) -> str: | |
| # ... existing logic ... | |
| if 'tool_calls' not in last_message.additional_kwargs: | |
| # Record session with trace association | |
| freeplay_client.record_session(state, trace_info=state.get("trace_info")) | |
| return 'end' | |
| return 'continue' | |
| ``` | |
| ## Data Flow Diagram | |
| ``` | |
| βββββββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ | |
| β User Input β β submit_helper β β AppState β | |
| β β β β β β | |
| β "Tell me about βββββΆβ 1. ensure_sessionsβββββΆβ freeplay_sessionβ | |
| β Ryan Martinez" β β 2. create_trace() β β .create_trace() β | |
| βββββββββββββββββββ β 3. pass trace_infoβ β β | |
| ββββββββββββββββββββ βββββββββββββββββββ | |
| β β | |
| βΌ βΌ | |
| ββββββββββββββββββββ βββββββββββββββββββ | |
| β build_workflow_ β β Trace Info β | |
| β with_state() β β β | |
| β β β - trace_id β | |
| β - trace_info β β - input β | |
| β - user_query β β - metadata β | |
| ββββββββββββββββββββ βββββββββββββββββββ | |
| β | |
| βΌ | |
| ββββββββββββββββββββ | |
| β AgentState β | |
| β β | |
| β - trace_info β | |
| β - messages β | |
| β - persona β | |
| ββββββββββββββββββββ | |
| β | |
| βΌ | |
| ββββββββββββββββββββ | |
| β Workflow β | |
| β Execution β | |
| β β | |
| β call_model() β | |
| β - get_prompt() β | |
| β - LLM call β | |
| β - record_output()β | |
| ββββββββββββββββββββ | |
| β | |
| βΌ | |
| ββββββββββββββββββββ | |
| β should_continue()β | |
| β β | |
| β record_session() β | |
| β with trace_info β | |
| ββββββββββββββββββββ | |
| β | |
| βΌ | |
| ββββββββββββββββββββ | |
| β Freeplay Session β | |
| β Recording β | |
| β β | |
| β - Session ID β | |
| β - Trace Info β | |
| β - Input/Output β | |
| ββββββββββββββββββββ | |
| ``` | |
| ## Trace Lifecycle | |
| ### 1. **Creation Phase** | |
| - **Trigger:** User submits question | |
| - **Location:** `submit_helper()` | |
| - **Action:** Create trace with user input and metadata | |
| - **Output:** `TraceInfo` object with `trace_id` | |
| ### 2. **Association Phase** | |
| - **Trigger:** Workflow initialization | |
| - **Location:** `build_workflow_with_state()` | |
| - **Action:** Pass `trace_info` to workflow state | |
| - **Output:** `AgentState` with trace context | |
| ### 3. **Processing Phase** | |
| - **Trigger:** LLM interaction | |
| - **Location:** `call_model()` | |
| - **Action:** Record LLM output to trace | |
| - **Output:** Trace with input/output pair | |
| ### 4. **Recording Phase** | |
| - **Trigger:** Workflow completion | |
| - **Location:** `should_continue()` | |
| - **Action:** Associate trace with session recording | |
| - **Output:** Complete session with trace linkage | |
| ## Benefits | |
| ### Enhanced Observability | |
| - **Input/Output Tracking:** Complete visibility of user questions and LLM responses | |
| - **Metadata Association:** Persona, user info, and interaction context | |
| - **Performance Metrics:** Response times, tool usage, and evaluation results | |
| ### Debugging & Analysis | |
| - **Trace Isolation:** Individual interactions can be analyzed separately | |
| - **Session Context:** Traces maintain session-level context | |
| - **Evaluation Support:** Built-in support for feedback and evaluation metrics | |
| ### Backward Compatibility | |
| - **Optional Implementation:** Traces are opt-in, existing functionality unchanged | |
| - **Graceful Degradation:** System works without traces if disabled | |
| - **Incremental Rollout:** Can be enabled per user or session | |
| ## Implementation Phases | |
| ### Phase 1: AppState Enhancement | |
| 1. Add `freeplay_session` property to `AppState` class | |
| 2. Modify `ensure_sessions()` to store session object | |
| 3. Test session object storage and retrieval | |
| ### Phase 2: Workflow Integration | |
| 1. Update `AgentState` to include `trace_info` field | |
| 2. Modify `build_workflow_with_state()` to accept `trace_info` parameter | |
| 3. Update `call_model()` to record trace outputs | |
| 4. Update `should_continue()` to associate traces with sessions | |
| ### Phase 3: Server Integration | |
| 1. Update `submit_helper()` to create traces using session object | |
| 2. Pass `trace_info` through workflow initialization | |
| 3. Test complete trace lifecycle | |
| ### Phase 4: Session Recording Enhancement | |
| 1. Modify `record_session()` to accept `trace_info` parameter | |
| 2. Update `RecordPayload` to include trace information | |
| 3. Test session recording with trace association | |
| ### Phase 5: Testing & Validation | |
| 1. Unit tests for trace creation and recording | |
| 2. Integration tests for workflow trace integration | |
| 3. End-to-end tests for complete trace lifecycle | |
| 4. Performance impact assessment | |
| ## Risk Mitigation | |
| ### High Risk Areas | |
| 1. **Session State Management** | |
| - **Risk:** Breaking existing session flow | |
| - **Mitigation:** Optional trace parameters, backward compatibility | |
| 2. **Workflow State Changes** | |
| - **Risk:** Breaking existing state structure | |
| - **Mitigation:** Optional fields with defaults, thorough testing | |
| ### Medium Risk Areas | |
| 1. **Performance Impact** | |
| - **Risk:** Slowing down workflow execution | |
| - **Mitigation:** Lazy trace creation, optional features | |
| 2. **Data Consistency** | |
| - **Risk:** Trace/recording mismatches | |
| - **Mitigation:** Validation and error handling | |
| ## Success Criteria | |
| 1. **Functionality:** Traces created and recorded for all user interactions | |
| 2. **Performance:** No measurable impact on workflow execution time | |
| 3. **Compatibility:** All existing functionality continues to work | |
| 4. **Observability:** Complete trace data available in Freeplay dashboard | |
| 5. **Reliability:** Graceful handling of trace creation/recording failures | |
| ## Next Steps | |
| 1. **User Approval:** Review and approve implementation plan | |
| 2. **Phase 1 Implementation:** Begin with core infrastructure | |
| 3. **Testing Strategy:** Validate each phase before proceeding | |
| 4. **Documentation:** Update API documentation with trace features | |
| 5. **Monitoring:** Implement trace-specific logging and metrics |