@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.
- package/.env.development +6 -0
- package/.env.test +7 -0
- package/README.md +11 -0
- package/context_system.md +498 -0
- package/dist/agent/src/agent/agent.js +169 -87
- package/dist/agent/src/agent/agentUtils.js +24 -18
- package/dist/agent/src/agent/compressingContextManager.js +10 -14
- package/dist/agent/src/agent/context.js +101 -127
- package/dist/agent/src/agent/contextWithWorkspace.js +133 -0
- package/dist/agent/src/agent/documentSummarizer.js +126 -0
- package/dist/agent/src/agent/dummyLLM.js +25 -22
- package/dist/agent/src/agent/imageGenLLM.js +22 -25
- package/dist/agent/src/agent/imageGenerator.js +2 -10
- package/dist/agent/src/agent/llm.js +1 -1
- package/dist/agent/src/agent/openAILLM.js +15 -12
- package/dist/agent/src/agent/openAILLMStreaming.js +73 -39
- package/dist/agent/src/agent/repeatLLM.js +16 -7
- package/dist/agent/src/agent/sudoMcpServerManager.js +21 -9
- package/dist/agent/src/agent/tokenCounter.js +390 -0
- package/dist/agent/src/agent/tokenCounter.test.js +206 -0
- package/dist/agent/src/agent/toolSettings.js +17 -0
- package/dist/agent/src/agent/tools/calculatorTool.js +45 -0
- package/dist/agent/src/agent/tools/contentExtractors/pdfToText.js +55 -0
- package/dist/agent/src/agent/tools/datetimeTool.js +38 -0
- package/dist/agent/src/agent/tools/fileManager/fileManagerTool.js +156 -0
- package/dist/agent/src/agent/tools/fileManager/index.js +31 -0
- package/dist/agent/src/agent/tools/fileManager/memoryFileManager.js +102 -0
- package/dist/agent/src/{chat/data → agent/tools/fileManager}/mimeTypes.js +3 -1
- package/dist/agent/src/agent/tools/fileManager/prompt.js +33 -0
- package/dist/agent/src/{chat/data/dbSessionFileModels.js → agent/tools/fileManager/types.js} +7 -0
- package/dist/agent/src/agent/tools/index.js +64 -0
- package/dist/agent/src/agent/tools/openUrlTool.js +57 -0
- package/dist/agent/src/agent/tools/renderTool.js +89 -0
- package/dist/agent/src/agent/tools/utils.js +61 -0
- package/dist/agent/src/{chat/utils/search.js → agent/tools/webSearch.js} +1 -2
- package/dist/agent/src/agent/tools/webSearchTool.js +40 -0
- package/dist/agent/src/chat/client/chatClient.js +63 -2
- package/dist/agent/src/chat/client/connection.js +6 -1
- package/dist/agent/src/chat/client/index.js +4 -1
- package/dist/agent/src/chat/client/sessionClient.js +28 -9
- package/dist/agent/src/chat/constants.js +8 -0
- package/dist/agent/src/chat/data/dbSessionFiles.js +11 -6
- package/dist/agent/src/chat/data/dbSessionMessages.js +11 -0
- package/dist/agent/src/chat/protocol/messages.js +9 -0
- package/dist/agent/src/chat/server/chatContextManager.js +186 -156
- package/dist/agent/src/chat/server/conversation.js +3 -0
- package/dist/agent/src/chat/server/imageGeneratorTools.js +39 -16
- package/dist/agent/src/chat/server/openAIRouterLLM.js +111 -0
- package/dist/agent/src/chat/server/openSession.js +253 -91
- package/dist/agent/src/chat/server/promptRefiner.js +86 -0
- package/dist/agent/src/chat/server/server.js +10 -2
- package/dist/agent/src/chat/server/sessionFileManager.js +22 -221
- package/dist/agent/src/chat/server/sessionRegistry.js +152 -6
- package/dist/agent/src/chat/server/sessionRegistry.test.js +1 -1
- package/dist/agent/src/chat/server/titleGenerator.js +112 -0
- package/dist/agent/src/chat/server/titleGenerator.test.js +113 -0
- package/dist/agent/src/chat/server/tools.js +64 -253
- package/dist/agent/src/chat/utils/approvalManager.js +6 -3
- package/dist/agent/src/chat/utils/multiAsyncQueue.js +3 -0
- package/dist/agent/src/test/agent.test.js +16 -17
- package/dist/agent/src/test/chatContextManager.test.js +44 -30
- package/dist/agent/src/test/clientServerConnection.test.js +1 -2
- package/dist/agent/src/test/compressingContextManager.test.js +22 -36
- package/dist/agent/src/test/context.test.js +55 -17
- package/dist/agent/src/test/contextTestTools.js +87 -0
- package/dist/agent/src/test/dbMcpServerConfigs.test.js +4 -4
- package/dist/agent/src/test/dbSessionFiles.test.js +17 -17
- package/dist/agent/src/test/testTools.js +6 -1
- package/dist/agent/src/test/tools.test.js +27 -9
- package/dist/agent/src/tool/agentChat.js +5 -2
- package/dist/agent/src/tool/chatMain.js +56 -15
- package/dist/agent/src/tool/commandPrompt.js +2 -2
- package/dist/agent/src/tool/files.js +7 -8
- package/package.json +4 -1
- package/scripts/test_chat +195 -173
- package/src/agent/agent.ts +257 -137
- package/src/agent/agentUtils.ts +32 -20
- package/src/agent/compressingContextManager.ts +13 -44
- package/src/agent/context.ts +165 -159
- package/src/agent/contextWithWorkspace.ts +162 -0
- package/src/agent/documentSummarizer.ts +157 -0
- package/src/agent/dummyLLM.ts +27 -23
- package/src/agent/imageGenLLM.ts +28 -32
- package/src/agent/imageGenerator.ts +3 -18
- package/src/agent/llm.ts +2 -2
- package/src/agent/openAILLM.ts +17 -13
- package/src/agent/openAILLMStreaming.ts +99 -43
- package/src/agent/repeatLLM.ts +19 -7
- package/src/agent/sudoMcpServerManager.ts +41 -20
- package/src/agent/test_data/harrypotter.txt +6065 -0
- package/src/agent/tokenCounter.test.ts +243 -0
- package/src/agent/tokenCounter.ts +483 -0
- package/src/agent/toolSettings.ts +24 -0
- package/src/agent/tools/calculatorTool.ts +50 -0
- package/src/agent/tools/contentExtractors/pdfToText.ts +60 -0
- package/src/agent/tools/datetimeTool.ts +41 -0
- package/src/agent/tools/fileManager/fileManagerTool.ts +199 -0
- package/src/agent/tools/fileManager/index.ts +50 -0
- package/src/agent/tools/fileManager/memoryFileManager.ts +120 -0
- package/src/{chat/data → agent/tools/fileManager}/mimeTypes.ts +3 -1
- package/src/agent/tools/fileManager/prompt.ts +38 -0
- package/src/{chat/data/dbSessionFileModels.ts → agent/tools/fileManager/types.ts} +76 -0
- package/src/agent/tools/index.ts +49 -0
- package/src/agent/tools/openUrlTool.ts +62 -0
- package/src/agent/tools/renderTool.ts +92 -0
- package/src/agent/tools/utils.ts +74 -0
- package/src/{chat/utils/search.ts → agent/tools/webSearch.ts} +0 -1
- package/src/agent/tools/webSearchTool.ts +44 -0
- package/src/chat/client/chatClient.ts +92 -3
- package/src/chat/client/connection.ts +11 -1
- package/src/chat/client/index.ts +3 -0
- package/src/chat/client/sessionClient.ts +40 -11
- package/src/chat/client/sessionFiles.ts +1 -1
- package/src/chat/constants.ts +6 -0
- package/src/chat/data/dataModels.ts +12 -0
- package/src/chat/data/dbSessionFiles.ts +12 -4
- package/src/chat/data/dbSessionMessages.ts +34 -0
- package/src/chat/protocol/messages.ts +94 -14
- package/src/chat/server/chatContextManager.ts +255 -221
- package/src/chat/server/connectionManager.ts +1 -1
- package/src/chat/server/conversation.ts +3 -0
- package/src/chat/server/imageGeneratorTools.ts +62 -30
- package/src/chat/server/openAIRouterLLM.ts +168 -0
- package/src/chat/server/openSession.ts +381 -138
- package/src/chat/server/promptRefiner.ts +106 -0
- package/src/chat/server/server.ts +9 -2
- package/src/chat/server/sessionFileManager.ts +35 -306
- package/src/chat/server/sessionRegistry.test.ts +0 -1
- package/src/chat/server/sessionRegistry.ts +228 -4
- package/src/chat/server/titleGenerator.test.ts +103 -0
- package/src/chat/server/titleGenerator.ts +143 -0
- package/src/chat/server/tools.ts +92 -281
- package/src/chat/utils/approvalManager.ts +9 -3
- package/src/chat/utils/multiAsyncQueue.ts +4 -0
- package/src/test/agent.test.ts +25 -30
- package/src/test/chatContextManager.test.ts +68 -38
- package/src/test/clientServerConnection.test.ts +0 -2
- package/src/test/compressingContextManager.test.ts +29 -34
- package/src/test/context.test.ts +59 -15
- package/src/test/contextTestTools.ts +95 -0
- package/src/test/dbMcpServerConfigs.test.ts +4 -4
- package/src/test/dbSessionFiles.test.ts +16 -16
- package/src/test/testTools.ts +8 -3
- package/src/test/tools.test.ts +30 -5
- package/src/tool/agentChat.ts +12 -3
- package/src/tool/chatMain.ts +59 -18
- package/src/tool/commandPrompt.ts +2 -2
- package/src/tool/files.ts +1 -3
- package/dist/agent/src/agent/tools.js +0 -44
- package/src/agent/tools.ts +0 -57
- /package/dist/agent/src/{chat/utils → agent/tools/contentExtractors}/htmlToText.js +0 -0
- /package/src/{chat/utils → agent/tools/contentExtractors}/htmlToText.ts +0 -0
package/.env.development
ADDED
|
@@ -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) |
|