@xalia/agent 0.6.8 → 0.6.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/.env.development +6 -0
  2. package/.env.test +7 -0
  3. package/README.md +11 -0
  4. package/context_system.md +498 -0
  5. package/dist/agent/src/agent/agent.js +169 -87
  6. package/dist/agent/src/agent/agentUtils.js +24 -18
  7. package/dist/agent/src/agent/compressingContextManager.js +10 -14
  8. package/dist/agent/src/agent/context.js +101 -127
  9. package/dist/agent/src/agent/contextWithWorkspace.js +133 -0
  10. package/dist/agent/src/agent/documentSummarizer.js +126 -0
  11. package/dist/agent/src/agent/dummyLLM.js +25 -22
  12. package/dist/agent/src/agent/imageGenLLM.js +22 -25
  13. package/dist/agent/src/agent/imageGenerator.js +2 -10
  14. package/dist/agent/src/agent/llm.js +1 -1
  15. package/dist/agent/src/agent/openAILLM.js +15 -12
  16. package/dist/agent/src/agent/openAILLMStreaming.js +73 -39
  17. package/dist/agent/src/agent/repeatLLM.js +16 -7
  18. package/dist/agent/src/agent/sudoMcpServerManager.js +21 -9
  19. package/dist/agent/src/agent/tokenCounter.js +390 -0
  20. package/dist/agent/src/agent/tokenCounter.test.js +206 -0
  21. package/dist/agent/src/agent/toolSettings.js +17 -0
  22. package/dist/agent/src/agent/tools/calculatorTool.js +45 -0
  23. package/dist/agent/src/agent/tools/contentExtractors/pdfToText.js +55 -0
  24. package/dist/agent/src/agent/tools/datetimeTool.js +38 -0
  25. package/dist/agent/src/agent/tools/fileManager/fileManagerTool.js +156 -0
  26. package/dist/agent/src/agent/tools/fileManager/index.js +31 -0
  27. package/dist/agent/src/agent/tools/fileManager/memoryFileManager.js +102 -0
  28. package/dist/agent/src/{chat/data → agent/tools/fileManager}/mimeTypes.js +3 -1
  29. package/dist/agent/src/agent/tools/fileManager/prompt.js +33 -0
  30. package/dist/agent/src/{chat/data/dbSessionFileModels.js → agent/tools/fileManager/types.js} +7 -0
  31. package/dist/agent/src/agent/tools/index.js +64 -0
  32. package/dist/agent/src/agent/tools/openUrlTool.js +57 -0
  33. package/dist/agent/src/agent/tools/renderTool.js +89 -0
  34. package/dist/agent/src/agent/tools/utils.js +61 -0
  35. package/dist/agent/src/{chat/utils/search.js → agent/tools/webSearch.js} +1 -2
  36. package/dist/agent/src/agent/tools/webSearchTool.js +40 -0
  37. package/dist/agent/src/chat/client/chatClient.js +63 -2
  38. package/dist/agent/src/chat/client/connection.js +6 -1
  39. package/dist/agent/src/chat/client/index.js +4 -1
  40. package/dist/agent/src/chat/client/sessionClient.js +28 -9
  41. package/dist/agent/src/chat/constants.js +8 -0
  42. package/dist/agent/src/chat/data/dbSessionFiles.js +11 -6
  43. package/dist/agent/src/chat/data/dbSessionMessages.js +11 -0
  44. package/dist/agent/src/chat/protocol/messages.js +9 -0
  45. package/dist/agent/src/chat/server/chatContextManager.js +186 -156
  46. package/dist/agent/src/chat/server/conversation.js +3 -0
  47. package/dist/agent/src/chat/server/imageGeneratorTools.js +39 -16
  48. package/dist/agent/src/chat/server/openAIRouterLLM.js +111 -0
  49. package/dist/agent/src/chat/server/openSession.js +253 -91
  50. package/dist/agent/src/chat/server/promptRefiner.js +86 -0
  51. package/dist/agent/src/chat/server/server.js +10 -2
  52. package/dist/agent/src/chat/server/sessionFileManager.js +22 -221
  53. package/dist/agent/src/chat/server/sessionRegistry.js +152 -6
  54. package/dist/agent/src/chat/server/sessionRegistry.test.js +1 -1
  55. package/dist/agent/src/chat/server/titleGenerator.js +112 -0
  56. package/dist/agent/src/chat/server/titleGenerator.test.js +113 -0
  57. package/dist/agent/src/chat/server/tools.js +64 -253
  58. package/dist/agent/src/chat/utils/approvalManager.js +6 -3
  59. package/dist/agent/src/chat/utils/multiAsyncQueue.js +3 -0
  60. package/dist/agent/src/test/agent.test.js +16 -17
  61. package/dist/agent/src/test/chatContextManager.test.js +44 -30
  62. package/dist/agent/src/test/clientServerConnection.test.js +1 -2
  63. package/dist/agent/src/test/compressingContextManager.test.js +22 -36
  64. package/dist/agent/src/test/context.test.js +55 -17
  65. package/dist/agent/src/test/contextTestTools.js +87 -0
  66. package/dist/agent/src/test/dbMcpServerConfigs.test.js +4 -4
  67. package/dist/agent/src/test/dbSessionFiles.test.js +17 -17
  68. package/dist/agent/src/test/testTools.js +6 -1
  69. package/dist/agent/src/test/tools.test.js +27 -9
  70. package/dist/agent/src/tool/agentChat.js +5 -2
  71. package/dist/agent/src/tool/chatMain.js +56 -15
  72. package/dist/agent/src/tool/commandPrompt.js +2 -2
  73. package/dist/agent/src/tool/files.js +7 -8
  74. package/package.json +4 -1
  75. package/scripts/test_chat +195 -173
  76. package/src/agent/agent.ts +257 -137
  77. package/src/agent/agentUtils.ts +32 -20
  78. package/src/agent/compressingContextManager.ts +13 -44
  79. package/src/agent/context.ts +165 -159
  80. package/src/agent/contextWithWorkspace.ts +162 -0
  81. package/src/agent/documentSummarizer.ts +157 -0
  82. package/src/agent/dummyLLM.ts +27 -23
  83. package/src/agent/imageGenLLM.ts +28 -32
  84. package/src/agent/imageGenerator.ts +3 -18
  85. package/src/agent/llm.ts +2 -2
  86. package/src/agent/openAILLM.ts +17 -13
  87. package/src/agent/openAILLMStreaming.ts +99 -43
  88. package/src/agent/repeatLLM.ts +19 -7
  89. package/src/agent/sudoMcpServerManager.ts +41 -20
  90. package/src/agent/test_data/harrypotter.txt +6065 -0
  91. package/src/agent/tokenCounter.test.ts +243 -0
  92. package/src/agent/tokenCounter.ts +483 -0
  93. package/src/agent/toolSettings.ts +24 -0
  94. package/src/agent/tools/calculatorTool.ts +50 -0
  95. package/src/agent/tools/contentExtractors/pdfToText.ts +60 -0
  96. package/src/agent/tools/datetimeTool.ts +41 -0
  97. package/src/agent/tools/fileManager/fileManagerTool.ts +199 -0
  98. package/src/agent/tools/fileManager/index.ts +50 -0
  99. package/src/agent/tools/fileManager/memoryFileManager.ts +120 -0
  100. package/src/{chat/data → agent/tools/fileManager}/mimeTypes.ts +3 -1
  101. package/src/agent/tools/fileManager/prompt.ts +38 -0
  102. package/src/{chat/data/dbSessionFileModels.ts → agent/tools/fileManager/types.ts} +76 -0
  103. package/src/agent/tools/index.ts +49 -0
  104. package/src/agent/tools/openUrlTool.ts +62 -0
  105. package/src/agent/tools/renderTool.ts +92 -0
  106. package/src/agent/tools/utils.ts +74 -0
  107. package/src/{chat/utils/search.ts → agent/tools/webSearch.ts} +0 -1
  108. package/src/agent/tools/webSearchTool.ts +44 -0
  109. package/src/chat/client/chatClient.ts +92 -3
  110. package/src/chat/client/connection.ts +11 -1
  111. package/src/chat/client/index.ts +3 -0
  112. package/src/chat/client/sessionClient.ts +40 -11
  113. package/src/chat/client/sessionFiles.ts +1 -1
  114. package/src/chat/constants.ts +6 -0
  115. package/src/chat/data/dataModels.ts +12 -0
  116. package/src/chat/data/dbSessionFiles.ts +12 -4
  117. package/src/chat/data/dbSessionMessages.ts +34 -0
  118. package/src/chat/protocol/messages.ts +94 -14
  119. package/src/chat/server/chatContextManager.ts +255 -221
  120. package/src/chat/server/connectionManager.ts +1 -1
  121. package/src/chat/server/conversation.ts +3 -0
  122. package/src/chat/server/imageGeneratorTools.ts +62 -30
  123. package/src/chat/server/openAIRouterLLM.ts +168 -0
  124. package/src/chat/server/openSession.ts +381 -138
  125. package/src/chat/server/promptRefiner.ts +106 -0
  126. package/src/chat/server/server.ts +9 -2
  127. package/src/chat/server/sessionFileManager.ts +35 -306
  128. package/src/chat/server/sessionRegistry.test.ts +0 -1
  129. package/src/chat/server/sessionRegistry.ts +228 -4
  130. package/src/chat/server/titleGenerator.test.ts +103 -0
  131. package/src/chat/server/titleGenerator.ts +143 -0
  132. package/src/chat/server/tools.ts +92 -281
  133. package/src/chat/utils/approvalManager.ts +9 -3
  134. package/src/chat/utils/multiAsyncQueue.ts +4 -0
  135. package/src/test/agent.test.ts +25 -30
  136. package/src/test/chatContextManager.test.ts +68 -38
  137. package/src/test/clientServerConnection.test.ts +0 -2
  138. package/src/test/compressingContextManager.test.ts +29 -34
  139. package/src/test/context.test.ts +59 -15
  140. package/src/test/contextTestTools.ts +95 -0
  141. package/src/test/dbMcpServerConfigs.test.ts +4 -4
  142. package/src/test/dbSessionFiles.test.ts +16 -16
  143. package/src/test/testTools.ts +8 -3
  144. package/src/test/tools.test.ts +30 -5
  145. package/src/tool/agentChat.ts +12 -3
  146. package/src/tool/chatMain.ts +59 -18
  147. package/src/tool/commandPrompt.ts +2 -2
  148. package/src/tool/files.ts +1 -3
  149. package/dist/agent/src/agent/tools.js +0 -44
  150. package/src/agent/tools.ts +0 -57
  151. /package/dist/agent/src/{chat/utils → agent/tools/contentExtractors}/htmlToText.js +0 -0
  152. /package/src/{chat/utils → agent/tools/contentExtractors}/htmlToText.ts +0 -0
@@ -0,0 +1,6 @@
1
+ LLM_API_KEY_MAP={"openrouter":"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","together":"5928479bc38fd315acc8359ba42587f8efc804e01b06eb02eb5ee97e044afaa1","openai":"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"}
2
+
3
+ # Internal API secret for sending emails
4
+ SEND_EMAIL_API_SECRET=73f52358f5741e2467d0ca13733b03f34ed334589c878c28c442f8a08abf85a6
5
+
6
+ XALIA_URL=http://localhost:3000
package/.env.test ADDED
@@ -0,0 +1,7 @@
1
+ # Test environment configuration
2
+ # Copy API keys from .env.development and add test-specific settings
3
+
4
+ LLM_API_KEY_MAP={"openrouter":"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","together":"5928479bc38fd315acc8359ba42587f8efc804e01b06eb02eb5ee97e044afaa1","openai":"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"}
5
+
6
+ # Disable LLM-generated titles for deterministic Playwright tests
7
+ DISABLE_LLM_TITLES=true
package/README.md CHANGED
@@ -25,6 +25,17 @@ Example of running agent can be found in [test script](../mcppro/scripts/test_sc
25
25
 
26
26
  ## Architecture
27
27
 
28
+ For a detailed explanation of the context system architecture, including how context is formed, compressed, and managed during agent execution, see:
29
+
30
+ **📚 [Context System Architecture Documentation](../context_system.md)**
31
+
32
+ This document covers:
33
+ - Context window structure and composition
34
+ - System prompt fragment injection
35
+ - Automatic context compression
36
+ - Session file handling
37
+ - Transaction-based message flow
38
+
28
39
  ### Core Components
29
40
 
30
41
  #### Agent (`src/agent/`)
@@ -0,0 +1,498 @@
1
+ # Agent Context System
2
+
3
+ ## Overview
4
+
5
+ This document describes how the agent's context system works, including context formation, compression, fragment injection, and message flow during agent execution.
6
+
7
+ ## High-Level Architecture
8
+
9
+ The context system uses a **layered architecture** with:
10
+ 1. **Fragment-based system prompts** for modularity
11
+ 2. **Transaction-based updates** for atomicity
12
+ 3. **Automatic compression** for long conversations
13
+ 4. **Dynamic context injection** for tools and files
14
+
15
+ ### Context Window Structure
16
+
17
+ ```
18
+ ┌─────────────────────────────────────────────────────────────────┐
19
+ │ CONTEXT WINDOW (MessageParam[]) │
20
+ ├─────────────────────────────────────────────────────────────────┤
21
+ │ Index 0: SYSTEM MESSAGE (Always present, dynamically generated) │
22
+ ├─────────────────────────────────────────────────────────────────┤
23
+ │ Index 1+: CONVERSATION MESSAGES │
24
+ │ - May start with checkpoint message (if compressed) │
25
+ │ - User, Assistant, and Tool messages │
26
+ │ - Workspace message at end (if ContextManagerWithWorkspace) │
27
+ └─────────────────────────────────────────────────────────────────┘
28
+ ```
29
+
30
+ ## Core Components
31
+
32
+ ### 1. System Prompt Composition (Index 0)
33
+
34
+ The system message is **never stored in the database**. It's dynamically composed from three sources:
35
+
36
+ ```
37
+ SystemPromptProvider.computePrompt():
38
+ ├── Global Prompt (static, shared by all agents)
39
+ ├── Agent Prompt (per-agent, from AgentProfile)
40
+ └── Fragments (dynamic, tool-specific context)
41
+ ├── "file_manager" → Available files list
42
+ ├── "participants" → User UUID to name mapping
43
+ └── [Custom fragments...]
44
+
45
+ Composition: global + "\n" + agent + "\n" + fragments.join("\n")
46
+ ```
47
+
48
+ The full prompt is lazily created and cached on every call to `getLLMContext()`.
49
+
50
+ **Key files:**
51
+ - `agent/src/agent/promptProvider.ts` - System prompt composition
52
+ - `agent/src/agent/context.ts` - Base context manager
53
+
54
+ ### 2. Conversation Messages (Index 1+)
55
+
56
+ Messages are stored in the database and loaded on session start. All messages are stored, whether or not the conversation has been compressed. Compressed conversations also have "checkpoints" (which include a message index).
57
+ In this way, the (compressed) LLM context can be recreated and historical messages can still be sent to clients.
58
+
59
+ The LLM structure varies depending on compression state:
60
+
61
+ #### Without Compression (< 80 messages)
62
+
63
+ ```
64
+ Index 0: System Message
65
+ Index 1: User Message
66
+ Index 2: Assistant Message (with tool_calls)
67
+ Index 3: Tool Message (results, with content deduplication)
68
+ Index 4: Assistant Message
69
+ ...
70
+ Index N: Workspace Message (optional, special position)
71
+ ```
72
+
73
+ #### With Compression (≥ 80 messages)
74
+ ```
75
+ Index 0: System Message
76
+ Index 1: Checkpoint Message (summarizes old messages)
77
+ Index 2+: Recent messages (20-30 most recent)
78
+ Index N: Workspace Message (if applicable)
79
+ ```
80
+
81
+ **Key files:**
82
+ - `agent/src/agent/compressingContextManager.ts` - Compression logic
83
+ - `agent/src/agent/contextWithWorkspace.ts` - Workspace message handling
84
+ - `agent/src/chat/server/chatContextManager.ts` - Chat-specific coordination
85
+
86
+ ## Context Formation During Agent Session
87
+
88
+ ### Initial Setup
89
+
90
+ ```typescript
91
+ // chatContextManager.ts:229-269
92
+ constructor(
93
+ systemPrompt: string,
94
+ sessionMessages: SessionMessage[],
95
+ checkpoint: SessionCheckpoint | undefined
96
+ ) {
97
+ // Resolve messages with checkpoint (if compressed)
98
+ const { messages: llmMessages } = resolveConversationWithCheckpoint(
99
+ sessionMessages,
100
+ checkpoint
101
+ );
102
+
103
+ // Create compressing context manager
104
+ this.llmContext = new CompressingContextManager(
105
+ systemPrompt,
106
+ llmMessages,
107
+ getLLM
108
+ );
109
+ }
110
+ ```
111
+
112
+ ### Transaction-Based Message Flow
113
+
114
+ ```
115
+ User sends messages
116
+
117
+ startTx(userMessages) → Creates ChatContextTransaction
118
+
119
+ Transaction context = [
120
+ System (with fragments: files, participants),
121
+ ...Committed messages,
122
+ ...New user messages,
123
+ Workspace message (if set)
124
+ ]
125
+
126
+ Agent executes (tool calls, reasoning, responses)
127
+
128
+ commit(tx) → Appends agent messages to committed history
129
+
130
+ checkCompression() → Triggers if > 80 messages
131
+ ```
132
+
133
+ **Key files:**
134
+ - `agent/src/agent/agent.ts:472-479` - Transaction pattern
135
+ - `agent/src/chat/server/chatContextManager.ts` - Transaction implementation
136
+
137
+ ## Context Compression
138
+
139
+ ### Trigger Mechanism
140
+
141
+ Compression activates when committed messages exceed **80 messages** (configurable via `COMPRESSION_TRIGGER_NUM_MESSAGES`).
142
+
143
+ ### Compression Process
144
+
145
+ ```typescript
146
+ // compressingContextManager.ts:99-128
147
+ async compress(): Promise<string> {
148
+ // Step 1: Extract messages to compress
149
+ const messagesToCompress = this.leadingMessages(numToCompress);
150
+
151
+ // Step 2: Create summary with specialized LLM
152
+ const llm = await this.getLLM();
153
+ const summary = await createSummary(llm, messagesToCompress);
154
+
155
+ // Step 3: Replace with checkpoint message
156
+ const checkpointMessage = {
157
+ role: "user",
158
+ content: "We are continuing an earlier conversation. " +
159
+ "The remainder of this message is a summary: " + summary
160
+ };
161
+ this.replaceLeadingMessages(numToCompress, checkpointMessage);
162
+
163
+ // Step 4: Save checkpoint to database
164
+ await checkpointWriter.createCheckpoint({
165
+ summary,
166
+ num_messages_compressed: numToCompress,
167
+ session_uuid: sessionUUID
168
+ });
169
+
170
+ return summary;
171
+ }
172
+ ```
173
+
174
+ The compression agent uses a specialized prompt:
175
+ ```
176
+ "You are a context summarizer, creating MINIMAL conversation digests
177
+ which can be used to CONTINUE the conversation at a later date.
178
+ TOKEN EFFICIENCY is a HIGH PRIORITY. Summaries will only be seen by
179
+ LLMs and should USE ANY AND ALL ABBREVIATIONS to keep them as CONCISE
180
+ as possible, while PRESERVING IMPORTANT DETAILS of the CONVERSATION."
181
+ ```
182
+
183
+ **Result:** Token savings of ~50-70% while preserving conversational context.
184
+
185
+ **Key files:**
186
+ - `agent/src/agent/compressingContextManager.ts` - Compression implementation
187
+ - `agent/src/chat/server/chatContextManager.ts:535-548` - Trigger logic
188
+
189
+ ## Tool-Specific Context Injection
190
+
191
+ The system uses **prompt fragments** to inject dynamic context. Fragments are identified by string IDs and can be updated independently.
192
+
193
+ ### Fragment Injection Pattern
194
+
195
+ ```typescript
196
+ // Lazy-update pattern (chatContextManager.ts:272-281)
197
+ getLLMContext(): MessageParam[] {
198
+ if (this.fileManagerDescriptionsDirty) { // Check dirty flag
199
+ // Regenerate the file list prompt
200
+ const prompt = createSessionFilesManagerPrompt(this.fileManager);
201
+
202
+ // Update the system prompt fragment
203
+ this.llmContext.setPromptFragment("file_manager", prompt);
204
+
205
+ this.fileManagerDescriptionsDirty = false; // Clear flag
206
+ }
207
+
208
+ return this.llmContext.getLLMContext();
209
+ }
210
+ ```
211
+
212
+ ### Key Injection Points
213
+
214
+ #### A. File Manager Context
215
+
216
+ ```typescript
217
+ // sessionFileManager.ts:271-287
218
+ function createSessionFilesManagerPrompt(fm: ISessionFileManager): string {
219
+ const files = fm.listFiles();
220
+ if (files.length === 0) return "";
221
+
222
+ let prompt =
223
+ "Files can be read/written as required. Create new files conservatively, " +
224
+ "usually when complex content is requested. Use base64 for binary (image," +
225
+ "pdf), ascii for text formats (html,markdown). " +
226
+ "Available files:\nname,type,summary\n";
227
+
228
+ for (const f of files) {
229
+ prompt += `${f.name},${f.mime_type},${f.summary || ""}\n`;
230
+ }
231
+ return prompt;
232
+ }
233
+ ```
234
+
235
+ **Event-driven updates:**
236
+ ```typescript
237
+ // When files change, mark dirty
238
+ onFileChanged(_entry: SessionFileEntry): void {
239
+ this.fileManagerDescriptionsDirty = true;
240
+ }
241
+ ```
242
+
243
+ #### B. Participants Context
244
+
245
+ ```typescript
246
+ // openSession.ts:1532-1547
247
+ private updateParticipantsPrompt(): void {
248
+ const prompt =
249
+ "The following map is from user_uuids to real names. In user " +
250
+ "messages, real names will be used...\n" +
251
+ participants.map(([uuid, name]) => `${uuid}: ${name}`).join("\n");
252
+
253
+ this.contextManager.setPromptFragment("participants", prompt);
254
+ }
255
+ ```
256
+
257
+ #### C. MCP Tool Definitions
258
+
259
+ MCP tools are passed as a separate parameter to the LLM, not as system prompt fragments:
260
+
261
+ ```typescript
262
+ // agent.ts:245-254
263
+ async chatCompletion(context: MessageParam[]) {
264
+ const mcpTools = this.mcpServerManager.getOpenAITools();
265
+ const enabledTools = this.tools.concat(mcpTools);
266
+
267
+ return await this.llm.getConversationResponse(
268
+ context,
269
+ enabledTools, // ← Tool schemas passed here
270
+ eventHandler
271
+ );
272
+ }
273
+ ```
274
+
275
+ **Key files:**
276
+ - `agent/src/agent/promptProvider.ts` - Fragment management
277
+ - `agent/src/chat/server/sessionFileManager.ts` - File manager integration
278
+ - `agent/src/chat/server/openSession.ts` - Participants management
279
+
280
+ ## Session Files Handling
281
+
282
+ Session files use an **event-driven architecture** with **lazy-update prompt injection**.
283
+
284
+ ### File Storage
285
+
286
+ Two implementations:
287
+ - **MemoryFileManager**: In-memory storage for testing
288
+ - **ChatSessionFileManager**: Database-backed with two-tier caching
289
+ - Metadata cache: `fileMap: Map<string, SessionFileDescriptor>`
290
+ - Content cache: `fileDataCache: Map<string, string>`
291
+
292
+ ### Event Flow
293
+
294
+ ```
295
+ User/Agent modifies file
296
+
297
+ SessionFileManager.putFileContent() / deleteFile()
298
+
299
+ Update internal state (fileMap, DB)
300
+
301
+ Trigger event handlers
302
+
303
+ ChatContextManager.onFileChanged() / onFileDeleted()
304
+
305
+ Set fileManagerDescriptionsDirty = true
306
+
307
+ Next getLLMContext() call regenerates prompt fragment
308
+ ```
309
+
310
+ ### Content Deduplication
311
+
312
+ File tool calls use a special optimization to prevent context bloat:
313
+
314
+ ```typescript
315
+ // sessionFileManager.ts:361-369
316
+ const getFileContentFn: ToolHandler = async (_, args) => {
317
+ const { name } = parseName(args);
318
+ const response = await fileManager.getFileContent(name);
319
+
320
+ // Replace full data URL with session file reference
321
+ const overwriteResponse = fileManager.getSessionFileRelativeUrl(name);
322
+
323
+ return { response, overwriteResponse };
324
+ };
325
+ ```
326
+
327
+ **Result:**
328
+ - **Initial response**: `data:image/png;base64,iVBORw0KGg...` (large)
329
+ - **Overwritten to**: `file+session://./chart.png` (compact)
330
+
331
+ **Key files:**
332
+ - `agent/src/chat/server/sessionFileManager.ts` - File management
333
+ - `agent/src/chat/server/chatContextManager.ts:271-315` - File event handling
334
+
335
+ ## Workspace Message
336
+
337
+ The workspace message is a **special trailing user message** that provides persistent context across all agent responses in a session.
338
+
339
+ ### Special Handling
340
+
341
+ ```typescript
342
+ // contextWithWorkspace.ts:142-149
343
+ setWorkspace(userMessage: UserMessageParam | undefined) {
344
+ if (!userMessage) {
345
+ userMessage = { role: "user", content: "" };
346
+ }
347
+ super.popMessage(); // Remove old workspace
348
+ super.pushMessage(userMessage); // Add new workspace
349
+ }
350
+ ```
351
+
352
+ ### Transaction Behavior
353
+
354
+ During transactions, the workspace message is:
355
+ 1. Moved from the end of committed messages
356
+ 2. Positioned **before** agent responses
357
+ 3. Restored to the end after commit
358
+
359
+ ```
360
+ Committed: [U1, A1, U2, A2, Workspace]
361
+ Transaction: [U1, A1, U2, A2, NewUser, Workspace, NewAgent]
362
+ After commit: [U1, A1, U2, A2, NewUser, NewAgent, Workspace]
363
+ ```
364
+
365
+ **Key files:**
366
+ - `agent/src/agent/contextWithWorkspace.ts` - Workspace implementation
367
+
368
+ ## Dynamic Todo/Task Tracking
369
+
370
+ **Result: NOT IMPLEMENTED**
371
+
372
+ The current agent does not have a dynamic todo/task tracking system during execution. There is no equivalent to Claude Code's TodoWrite tool.
373
+
374
+ What exists:
375
+ - Message history tracking
376
+ - Tool call result tracking
377
+ - File metadata tracking
378
+ - Checkpoint tracking
379
+
380
+ This could be a future enhancement.
381
+
382
+ ## Complete Data Flow
383
+
384
+ ```
385
+ ┌────────────────────────────────────────────────────────────┐
386
+ │ 1. User Message Received │
387
+ └────────────────────────────────────────────────────────────┘
388
+
389
+ ┌────────────────────────────────────────────────────────────┐
390
+ │ 2. ChatContextManager.processUserMessage() │
391
+ │ → Assigns message_idx │
392
+ └────────────────────────────────────────────────────────────┘
393
+
394
+ ┌────────────────────────────────────────────────────────────┐
395
+ │ 3. ChatContextManager.startAgentResponse() │
396
+ │ → Creates ChatContextTransaction │
397
+ │ → Injects: user messages + workspace + file list │
398
+ │ + participants │
399
+ └────────────────────────────────────────────────────────────┘
400
+
401
+ ┌────────────────────────────────────────────────────────────┐
402
+ │ 4. Agent.userMessagesRaw() │
403
+ │ → Loop: LLM call → Tool calls → LLM call → ... │
404
+ └────────────────────────────────────────────────────────────┘
405
+
406
+ ┌────────────────────────────────────────────────────────────┐
407
+ │ 5. ChatContextManager.endAgentResponse() │
408
+ │ → Commits transaction │
409
+ │ → Checks compression trigger │
410
+ └────────────────────────────────────────────────────────────┘
411
+ ↓ (if > 80 messages)
412
+ ┌────────────────────────────────────────────────────────────┐
413
+ │ 6. Background: CompressingContextManager.compress() │
414
+ │ → Summarizes old messages │
415
+ │ → Creates checkpoint │
416
+ │ → Saves to DB │
417
+ └────────────────────────────────────────────────────────────┘
418
+ ```
419
+
420
+ ## Architecture Layers
421
+
422
+ ```
423
+ ┌─────────────────────────────────────────────┐
424
+ │ Agent (agent.ts) │
425
+ │ - Execution loop │
426
+ │ - Tool orchestration │
427
+ └─────────────────┬───────────────────────────┘
428
+
429
+ ┌─────────────────▼───────────────────────────┐
430
+ │ ChatContextManager (chatContextManager.ts) │
431
+ │ - Transaction management │
432
+ │ - Compression triggering │
433
+ │ - Fragment coordination │
434
+ └─────────────────┬───────────────────────────┘
435
+
436
+ ┌─────────┴─────────┐
437
+ ▼ ▼
438
+ ┌───────────────────┐ ┌────────────────────────┐
439
+ │ CompressingContext│ │ SessionFileManager │
440
+ │ Manager │ │ (sessionFileManager.ts)│
441
+ │ (compressing...ts)│ │ - File tracking │
442
+ │ - Summarization │ │ - Prompt generation │
443
+ └───────┬───────────┘ └────────────────────────┘
444
+
445
+
446
+ ┌──────────────────────┐
447
+ │ ContextWithWorkspace │
448
+ │ (contextWith...ts) │
449
+ │ - Workspace msg │
450
+ └──────────┬───────────┘
451
+
452
+
453
+ ┌──────────────────────┐
454
+ │ ContextManager │
455
+ │ (context.ts) │
456
+ │ - Base messages │
457
+ │ - SystemPromptProvider│
458
+ └──────────────────────┘
459
+ ```
460
+
461
+ ## Key Design Principles
462
+
463
+ 1. **System message is never stored** - Regenerated on every context request
464
+ 2. **Fragments use lazy evaluation** - Only recomputed when dirty flags are set
465
+ 3. **Workspace has special handling** - Always at end, moved during transactions
466
+ 4. **Content is deduplicated** - Large data URLs replaced with compact references
467
+ 5. **Compression is one-way** - Old messages summarized, originals kept in DB for audit
468
+ 6. **Checkpoints are user messages** - Special prefix indicates it's a summary
469
+ 7. **Transactions ensure atomicity** - All-or-nothing commits with rollback
470
+
471
+ ## Performance Optimizations
472
+
473
+ - **Lazy fragment updates**: Only regenerate when dirty
474
+ - **Content deduplication**: File contents replaced with references
475
+ - **Automatic compression**: Keeps context window manageable
476
+ - **Two-tier file caching**: Metadata + content caches
477
+ - **Event-driven updates**: Minimizes unnecessary recomputation
478
+
479
+ ## References
480
+
481
+ ### Core Context Files
482
+
483
+ | Function | File |
484
+ |----------|------|
485
+ | Base context | [`src/agent/context.ts`](src/agent/context.ts) |
486
+ | Workspace support | [`src/agent/contextWithWorkspace.ts`](src/agent/contextWithWorkspace.ts) |
487
+ | Compression logic | [`src/agent/compressingContextManager.ts`](src/agent/compressingContextManager.ts) |
488
+ | System prompt fragments | [`src/agent/promptProvider.ts`](src/agent/promptProvider.ts) |
489
+ | Agent execution | [`src/agent/agent.ts`](src/agent/agent.ts) |
490
+
491
+ ### Chat System Files
492
+
493
+ | Function | File |
494
+ |----------|------|
495
+ | Chat coordination | [`src/chat/server/chatContextManager.ts`](src/chat/server/chatContextManager.ts) |
496
+ | File context | [`src/chat/server/sessionFileManager.ts`](src/chat/server/sessionFileManager.ts) |
497
+ | Participants context | [`src/chat/server/openSession.ts`](src/chat/server/openSession.ts) |
498
+ | Message transformation | [`src/chat/server/conversation.ts`](src/chat/server/conversation.ts) |