Data Flow & State Management
Relevant source files
The following files were used as context for generating this wiki page:
- server/services/conversation/log.py
- server/services/conversation/summarization/working_memory_log.py
- server/agents/interaction_agent/runtime.py
- server/services/conversation/summarization/summarizer.py
- web/app/page.tsx
- server/services/conversation/summarization/prompt_builder.py
- web/app/api/chat/route.ts
OpenPoke employs a distributed data flow architecture that synchronizes state between a Next.js frontend, a FastAPI backend, and persistent local storage. The system manages two primary forms of state: a full, append-only conversation transcript used for historical reference and a refined "working memory" summary that provides condensed context for the Large Language Model (LLM).
Data flows from the user interface through a proxy layer to the interaction agent, which manages an execution loop involving multiple tool calls. State is persisted using structured log files that utilize XML-like tagging to differentiate between user messages, agent results, and internal orchestration markers.
Frontend to Backend Communication
The web interface utilizes optimistic updates and polling to manage the asynchronous nature of agent execution. When a user sends a message, it is immediately rendered in the UI while a POST request is dispatched to the backend.
Request Flow
The frontend proxies requests through Next.js API routes to the Python-based FastAPI server. Because agent responses may take time (due to multi-step tool iterations), the frontend implements a polling mechanism to fetch the latest chat history and update the message list.
Backend State Persistence
State is managed primarily through two classes: ConversationLog and WorkingMemoryLog. Both systems use a file-based persistence strategy located in server/data/conversation/.
Conversation Logging
The ConversationLog is an append-only store that records every interaction turn. It uses specific tags to categorize entries, which allows the system to filter orchestration metadata (like wait markers) from user-facing history.
| Tag | Purpose | User Visible |
|---|---|---|
user_message | Direct input from the human user. | Yes |
poke_reply | Direct response from the assistant to the user. | Yes |
agent_message | Results or status updates from execution agents. | No |
wait | Internal marker to prevent duplicate processing. | No |
Sources: server/services/conversation/log.py:126-160, server/agents/interaction_agent/system_prompt.md:65-78
Working Memory & Summarization
To handle long-running conversations without exceeding LLM context limits, OpenPoke implements a "Working Memory" system. This system periodically compresses older parts of the conversation into a structured briefing.
Interaction Agent Data Loop
The InteractionAgentRuntime manages the internal data flow of a single request. It operates in a loop, processing tool calls and updating its internal message history until a final response is ready for the user.
Execution Loop Logic
- Transcript Loading: The agent loads either the full
ConversationLogor theWorkingMemoryLog(if summarization is enabled) to build the<conversation_history>block. - LLM Call: It sends the history, active agent roster, and new message to OpenRouter.
- Tool Parsing: If the LLM returns
tool_calls, the runtime parses the arguments (validating JSON structures). - Tool Execution: Tools like
send_message_to_agentorsend_message_to_userare executed.send_message_to_agenttriggers a background task via theExecutionBatchManager. - Iteration: The results of tool calls are appended to the internal message list, and the LLM is queried again (up to a limit of 8 iterations).
Sources: server/agents/interaction_agent/runtime.py:91-137, server/agents/interaction_agent/runtime.py:168-202
Data Models and Schemas
Structured Messaging
Messages are stored and transmitted using structured formats to ensure consistency between the Python backend and TypeScript frontend.
| Component | Format | Description |
|---|---|---|
LogEntry | Python Dataclass | Represents a single line in the log files with tag, payload, and timestamp. |
SummaryState | Python Dataclass | Holds the current summarized text and the list of entries not yet processed. |
ChatBubble | TypeScript Interface | The frontend representation of a message for rendering. |
Sources: server/services/conversation/summarization/state.py, web/app/page.tsx:29-37
Log File Format
Logs are saved as plain text with XML tags. Payloads are escaped to prevent corruption from special characters.
<user_message timestamp="2024-05-20 10:00:00">Hello, check my email.</user_message>
<agent_message timestamp="2024-05-20 10:00:05">Found 3 new emails.</agent_message>
Sources: server/services/conversation/log.py:38-45, server/services/conversation/summarization/working_memory_log.py:27-38
Conclusion
Data flow in OpenPoke is designed to be resilient and context-aware. By separating the raw conversation log from a refined working memory summary, the system maintains a perfect record of interactions while providing the LLM with a highly dense, actionable state. This dual-track state management ensures that even as conversations grow in length, the assistant remains efficient and accurate in its execution.