@xalia/agent 0.6.10 → 0.6.11
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/package.json +5 -2
- package/.env.development +0 -6
- package/.env.test +0 -7
- package/.prettierrc.json +0 -11
- package/context_system.md +0 -498
- package/eslint.config.mjs +0 -38
- package/scripts/chat_server +0 -8
- package/scripts/git_message +0 -31
- package/scripts/git_wip +0 -21
- package/scripts/pr_message +0 -18
- package/scripts/pr_review +0 -16
- package/scripts/setup_chat +0 -90
- package/scripts/shutdown_chat_server +0 -42
- package/scripts/start_chat_server +0 -24
- package/scripts/sudomcp_import +0 -23
- package/scripts/test_chat +0 -327
- package/src/agent/agent.ts +0 -699
- package/src/agent/agentUtils.ts +0 -286
- package/src/agent/compressingContextManager.ts +0 -129
- package/src/agent/context.ts +0 -265
- package/src/agent/contextWithWorkspace.ts +0 -162
- package/src/agent/documentSummarizer.ts +0 -157
- package/src/agent/dummyLLM.ts +0 -130
- package/src/agent/iAgentEventHandler.ts +0 -64
- package/src/agent/imageGenLLM.ts +0 -101
- package/src/agent/imageGenerator.ts +0 -45
- package/src/agent/iplatform.ts +0 -18
- package/src/agent/llm.ts +0 -74
- package/src/agent/mcpServerManager.ts +0 -541
- package/src/agent/nullAgentEventHandler.ts +0 -26
- package/src/agent/nullPlatform.ts +0 -13
- package/src/agent/openAI.ts +0 -123
- package/src/agent/openAILLM.ts +0 -99
- package/src/agent/openAILLMStreaming.ts +0 -648
- package/src/agent/promptProvider.ts +0 -87
- package/src/agent/repeatLLM.ts +0 -62
- package/src/agent/sudoMcpServerManager.ts +0 -361
- package/src/agent/test_data/harrypotter.txt +0 -6065
- package/src/agent/tokenAuth.ts +0 -50
- package/src/agent/tokenCounter.test.ts +0 -243
- package/src/agent/tokenCounter.ts +0 -483
- package/src/agent/toolSettings.ts +0 -24
- package/src/agent/tools/calculatorTool.ts +0 -50
- package/src/agent/tools/contentExtractors/htmlToText.ts +0 -61
- package/src/agent/tools/contentExtractors/pdfToText.ts +0 -60
- package/src/agent/tools/datetimeTool.ts +0 -41
- package/src/agent/tools/fileManager/fileManagerTool.ts +0 -199
- package/src/agent/tools/fileManager/index.ts +0 -50
- package/src/agent/tools/fileManager/memoryFileManager.ts +0 -120
- package/src/agent/tools/fileManager/mimeTypes.ts +0 -60
- package/src/agent/tools/fileManager/prompt.ts +0 -38
- package/src/agent/tools/fileManager/types.ts +0 -189
- package/src/agent/tools/index.ts +0 -49
- package/src/agent/tools/openUrlTool.ts +0 -62
- package/src/agent/tools/renderTool.ts +0 -92
- package/src/agent/tools/utils.ts +0 -74
- package/src/agent/tools/webSearch.ts +0 -138
- package/src/agent/tools/webSearchTool.ts +0 -44
- package/src/chat/client/chatClient.ts +0 -967
- package/src/chat/client/connection.test.ts +0 -241
- package/src/chat/client/connection.ts +0 -286
- package/src/chat/client/constants.ts +0 -1
- package/src/chat/client/index.ts +0 -21
- package/src/chat/client/interfaces.ts +0 -34
- package/src/chat/client/sessionClient.ts +0 -574
- package/src/chat/client/sessionFiles.ts +0 -142
- package/src/chat/client/teamManager.ts +0 -29
- package/src/chat/constants.ts +0 -6
- package/src/chat/data/apiKeyManager.ts +0 -76
- package/src/chat/data/dataModels.ts +0 -107
- package/src/chat/data/database.ts +0 -997
- package/src/chat/data/dbMcpServerConfigs.ts +0 -59
- package/src/chat/data/dbSessionFiles.ts +0 -107
- package/src/chat/data/dbSessionMessages.ts +0 -102
- package/src/chat/protocol/connectionMessages.ts +0 -49
- package/src/chat/protocol/constants.ts +0 -55
- package/src/chat/protocol/errors.ts +0 -16
- package/src/chat/protocol/messages.ts +0 -899
- package/src/chat/server/README.md +0 -127
- package/src/chat/server/chatContextManager.ts +0 -660
- package/src/chat/server/connectionManager.test.ts +0 -246
- package/src/chat/server/connectionManager.ts +0 -506
- package/src/chat/server/conversation.ts +0 -319
- package/src/chat/server/errorUtils.ts +0 -28
- package/src/chat/server/imageGeneratorTools.ts +0 -179
- package/src/chat/server/openAIRouterLLM.ts +0 -168
- package/src/chat/server/openSession.ts +0 -1945
- package/src/chat/server/openSessionMessageSender.ts +0 -4
- package/src/chat/server/promptRefiner.ts +0 -106
- package/src/chat/server/server.ts +0 -178
- package/src/chat/server/sessionFileManager.ts +0 -151
- package/src/chat/server/sessionRegistry.test.ts +0 -137
- package/src/chat/server/sessionRegistry.ts +0 -1553
- package/src/chat/server/test-utils/mockFactories.ts +0 -422
- package/src/chat/server/titleGenerator.test.ts +0 -103
- package/src/chat/server/titleGenerator.ts +0 -143
- package/src/chat/server/tools.ts +0 -170
- package/src/chat/utils/agentSessionMap.ts +0 -76
- package/src/chat/utils/approvalManager.ts +0 -189
- package/src/chat/utils/asyncLock.ts +0 -43
- package/src/chat/utils/asyncQueue.ts +0 -62
- package/src/chat/utils/multiAsyncQueue.ts +0 -66
- package/src/chat/utils/responseAwaiter.ts +0 -181
- package/src/chat/utils/userResolver.ts +0 -48
- package/src/chat/utils/websocket.ts +0 -16
- package/src/index.ts +0 -0
- package/src/test/agent.test.ts +0 -584
- package/src/test/approvalManager.test.ts +0 -141
- package/src/test/chatContextManager.test.ts +0 -552
- package/src/test/clientServerConnection.test.ts +0 -205
- package/src/test/compressingContextManager.test.ts +0 -77
- package/src/test/context.test.ts +0 -150
- package/src/test/contextTestTools.ts +0 -95
- package/src/test/conversation.test.ts +0 -109
- package/src/test/db.test.ts +0 -363
- package/src/test/dbMcpServerConfigs.test.ts +0 -112
- package/src/test/dbSessionFiles.test.ts +0 -258
- package/src/test/dbSessionMessages.test.ts +0 -85
- package/src/test/dbTestTools.ts +0 -157
- package/src/test/imageLoad.test.ts +0 -15
- package/src/test/mcpServerManager.test.ts +0 -114
- package/src/test/multiAsyncQueue.test.ts +0 -183
- package/src/test/openaiStreaming.test.ts +0 -177
- package/src/test/prompt.test.ts +0 -27
- package/src/test/promptProvider.test.ts +0 -33
- package/src/test/responseAwaiter.test.ts +0 -103
- package/src/test/sudoMcpServerManager.test.ts +0 -63
- package/src/test/testTools.ts +0 -176
- package/src/test/tools.test.ts +0 -64
- package/src/tool/agentChat.ts +0 -203
- package/src/tool/agentMain.ts +0 -180
- package/src/tool/chatMain.ts +0 -621
- package/src/tool/commandPrompt.ts +0 -264
- package/src/tool/files.ts +0 -82
- package/src/tool/main.ts +0 -25
- package/src/tool/nodePlatform.ts +0 -73
- package/src/tool/options.ts +0 -144
- package/src/tool/prompt.ts +0 -101
- package/test_data/background_test_profile.json +0 -6
- package/test_data/background_test_script.json +0 -11
- package/test_data/dummyllm_script_crash.json +0 -32
- package/test_data/dummyllm_script_image_gen.json +0 -19
- package/test_data/dummyllm_script_image_gen_fe.json +0 -29
- package/test_data/dummyllm_script_invoke_image_gen_tool.json +0 -37
- package/test_data/dummyllm_script_render_tool.json +0 -29
- package/test_data/dummyllm_script_simplecalc.json +0 -28
- package/test_data/dummyllm_script_test_auto_approve.json +0 -81
- package/test_data/dummyllm_script_test_simplecalc_addition.json +0 -29
- package/test_data/frog.png +0 -0
- package/test_data/frog.png.b64 +0 -1
- package/test_data/git_message_profile.json +0 -4
- package/test_data/git_wip_system.txt +0 -5
- package/test_data/image_gen_test_profile.json +0 -5
- package/test_data/pr_message_profile.json +0 -4
- package/test_data/pr_review_profile.json +0 -4
- package/test_data/prompt_simplecalc.txt +0 -1
- package/test_data/simplecalc_profile.json +0 -4
- package/test_data/sudomcp_import_profile.json +0 -4
- package/test_data/test_script_profile.json +0 -8
- package/tsconfig.json +0 -13
- package/vitest.config.ts +0 -39
package/src/agent/agentUtils.ts
DELETED
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
import { McpServerSettings, getLogger } from "@xalia/xmcp/sdk";
|
|
2
|
-
import { Configuration as SudoMcpConfiguration } from "@xalia/xmcp/sdk";
|
|
3
|
-
|
|
4
|
-
import { Agent, AgentProfile } from "./agent";
|
|
5
|
-
import { IAgentEventHandler } from "./iAgentEventHandler";
|
|
6
|
-
import { IPlatform } from "./iplatform";
|
|
7
|
-
import { SkillManager } from "./sudoMcpServerManager";
|
|
8
|
-
import { OpenAILLM } from "./openAILLM";
|
|
9
|
-
import { OpenAILLMStreaming } from "./openAILLMStreaming";
|
|
10
|
-
import { DummyLLM } from "./dummyLLM";
|
|
11
|
-
import { ContentPartImage, ILLM, MessageParam } from "./llm";
|
|
12
|
-
import { strict as assert } from "assert";
|
|
13
|
-
import { RepeatLLM } from "./repeatLLM";
|
|
14
|
-
import { ContextManager, IContextManager } from "./context";
|
|
15
|
-
|
|
16
|
-
const logger = getLogger();
|
|
17
|
-
|
|
18
|
-
export async function createAgentWithoutSkills(
|
|
19
|
-
llmUrl: string,
|
|
20
|
-
model: string,
|
|
21
|
-
eventHandler: IAgentEventHandler,
|
|
22
|
-
platform: IPlatform,
|
|
23
|
-
contextManager: IContextManager,
|
|
24
|
-
llmApiKey: string | undefined,
|
|
25
|
-
sudomcpConfig: SudoMcpConfiguration,
|
|
26
|
-
authorizedUrl: string | undefined,
|
|
27
|
-
stream: boolean = false
|
|
28
|
-
): Promise<[Agent, SkillManager]> {
|
|
29
|
-
// Init SudoMcpServerManager
|
|
30
|
-
logger.debug("[createAgentWithSkills] creating SudoMcpServerManager.");
|
|
31
|
-
const sudoMcpServerManager = await SkillManager.initialize(
|
|
32
|
-
(url: string, authResultP: Promise<boolean>, displayName: string) => {
|
|
33
|
-
platform.openUrl(url, authResultP, displayName);
|
|
34
|
-
},
|
|
35
|
-
sudomcpConfig.backend_url,
|
|
36
|
-
sudomcpConfig.api_key,
|
|
37
|
-
authorizedUrl
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
// Create agent using the event handler
|
|
41
|
-
const agent = await createAgentFromSkillManager(
|
|
42
|
-
llmUrl,
|
|
43
|
-
model,
|
|
44
|
-
eventHandler,
|
|
45
|
-
platform,
|
|
46
|
-
contextManager,
|
|
47
|
-
llmApiKey,
|
|
48
|
-
sudoMcpServerManager,
|
|
49
|
-
stream
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
return [agent, sudoMcpServerManager];
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Create and initialize an Agent given an AgentProfile using the
|
|
57
|
-
* IAgentEventHandler interface. This is the preferred way to create
|
|
58
|
-
* agents.
|
|
59
|
-
*/
|
|
60
|
-
export async function createAgentWithSkills(
|
|
61
|
-
llmUrl: string,
|
|
62
|
-
model: string,
|
|
63
|
-
eventHandler: IAgentEventHandler,
|
|
64
|
-
platform: IPlatform,
|
|
65
|
-
contextManager: IContextManager,
|
|
66
|
-
llmApiKey: string | undefined,
|
|
67
|
-
sudomcpConfig: SudoMcpConfiguration,
|
|
68
|
-
mcpSettings: McpServerSettings,
|
|
69
|
-
authorizedUrl: string | undefined,
|
|
70
|
-
stream: boolean = false
|
|
71
|
-
): Promise<[Agent, SkillManager]> {
|
|
72
|
-
const [agent, sudoMcpServerManager] = await createAgentWithoutSkills(
|
|
73
|
-
llmUrl,
|
|
74
|
-
model,
|
|
75
|
-
eventHandler,
|
|
76
|
-
platform,
|
|
77
|
-
contextManager,
|
|
78
|
-
llmApiKey,
|
|
79
|
-
sudomcpConfig,
|
|
80
|
-
authorizedUrl,
|
|
81
|
-
stream
|
|
82
|
-
);
|
|
83
|
-
|
|
84
|
-
logger.debug(
|
|
85
|
-
`[createAgentWithSkills] skilles: ${JSON.stringify(mcpSettings)}`
|
|
86
|
-
);
|
|
87
|
-
await sudoMcpServerManager.restoreMcpSettings(mcpSettings);
|
|
88
|
-
|
|
89
|
-
return [agent, sudoMcpServerManager];
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export async function createAgentFromSkillManager(
|
|
93
|
-
llmUrl: string,
|
|
94
|
-
model: string,
|
|
95
|
-
eventHandler: IAgentEventHandler,
|
|
96
|
-
platform: IPlatform,
|
|
97
|
-
contextManager: IContextManager,
|
|
98
|
-
llmApiKey: string | undefined,
|
|
99
|
-
skillManager: SkillManager | undefined,
|
|
100
|
-
stream: boolean = false
|
|
101
|
-
): Promise<Agent> {
|
|
102
|
-
// Create agent
|
|
103
|
-
logger.debug("[createAgentFromSkillManager] creating agent ...");
|
|
104
|
-
const llm = await createLLM(llmUrl, llmApiKey, model, stream, platform);
|
|
105
|
-
const agent = Agent.initializeWithLLM(
|
|
106
|
-
eventHandler,
|
|
107
|
-
llm,
|
|
108
|
-
contextManager,
|
|
109
|
-
skillManager
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
logger.debug("[createAgentFromSkillManager] done");
|
|
113
|
-
return agent;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Interpret the `model` string to create a specialized agent (dummy, repeat,
|
|
118
|
-
* etc) or return undefined if a specialized agent has not been requested.
|
|
119
|
-
*/
|
|
120
|
-
export async function createSpecializedLLM(
|
|
121
|
-
model: string,
|
|
122
|
-
platform: IPlatform
|
|
123
|
-
): Promise<ILLM | undefined> {
|
|
124
|
-
let llm: ILLM | undefined;
|
|
125
|
-
|
|
126
|
-
if (model && model.startsWith("dummy:")) {
|
|
127
|
-
llm = await DummyLLM.initFromModelUrl(model, platform);
|
|
128
|
-
} else if (model && model.startsWith("repeat")) {
|
|
129
|
-
const prefix = model.startsWith("repeat:") ? model.slice(7) : "";
|
|
130
|
-
llm = new RepeatLLM(prefix);
|
|
131
|
-
}
|
|
132
|
-
return llm;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
export async function createLLM(
|
|
136
|
-
llmUrl: string | undefined,
|
|
137
|
-
llmApiKey: string | undefined,
|
|
138
|
-
model: string,
|
|
139
|
-
stream: boolean = false,
|
|
140
|
-
platform: IPlatform
|
|
141
|
-
): Promise<ILLM> {
|
|
142
|
-
let llm = await createSpecializedLLM(model, platform);
|
|
143
|
-
if (llm) {
|
|
144
|
-
return llm;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Regular Agent
|
|
148
|
-
if (!llmApiKey) {
|
|
149
|
-
throw new Error("Missing OpenAI API Key");
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
logger.debug(`Initializing Agent: ${llmUrl ?? "unknown"} - ${model}`);
|
|
153
|
-
if (stream) {
|
|
154
|
-
llm = new OpenAILLMStreaming(llmApiKey, llmUrl, model);
|
|
155
|
-
} else {
|
|
156
|
-
llm = new OpenAILLM(llmApiKey, llmUrl, model);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
assert(llm);
|
|
160
|
-
return llm;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* An "non-interactive" agent is one which is not intended to be used
|
|
165
|
-
* interactively (settings cannot be dyanmically adjusted, intermediate
|
|
166
|
-
* messages are not used by the caller, the user does not need to approve tool
|
|
167
|
-
* calls, etc).
|
|
168
|
-
*/
|
|
169
|
-
export async function createNonInteractiveAgent(
|
|
170
|
-
url: string,
|
|
171
|
-
agentProfile: AgentProfile,
|
|
172
|
-
defaultModel: string,
|
|
173
|
-
conversation: MessageParam[] | undefined,
|
|
174
|
-
platform: IPlatform,
|
|
175
|
-
openaiApiKey: string | undefined,
|
|
176
|
-
sudomcpConfig: SudoMcpConfiguration,
|
|
177
|
-
approveToolsUpTo: number
|
|
178
|
-
): Promise<Agent> {
|
|
179
|
-
let remainingToolCalls = approveToolsUpTo;
|
|
180
|
-
const eventHandler: IAgentEventHandler = {
|
|
181
|
-
onCompletion: () => {},
|
|
182
|
-
onImage: () => {},
|
|
183
|
-
onAgentMessage: async () => {},
|
|
184
|
-
onReasoning: async () => {},
|
|
185
|
-
// eslint-disable-next-line @typescript-eslint/require-await
|
|
186
|
-
onToolCall: async () => {
|
|
187
|
-
if (remainingToolCalls !== 0) {
|
|
188
|
-
--remainingToolCalls;
|
|
189
|
-
return true;
|
|
190
|
-
}
|
|
191
|
-
return false;
|
|
192
|
-
},
|
|
193
|
-
onToolCallResult: () => {},
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
const contextManager = new ContextManager(
|
|
197
|
-
agentProfile.system_prompt,
|
|
198
|
-
conversation || []
|
|
199
|
-
);
|
|
200
|
-
const [agent, _] = await createAgentWithSkills(
|
|
201
|
-
url,
|
|
202
|
-
agentProfile.model || defaultModel,
|
|
203
|
-
eventHandler,
|
|
204
|
-
platform,
|
|
205
|
-
contextManager,
|
|
206
|
-
openaiApiKey,
|
|
207
|
-
sudomcpConfig,
|
|
208
|
-
agentProfile.mcp_settings,
|
|
209
|
-
undefined
|
|
210
|
-
);
|
|
211
|
-
|
|
212
|
-
return agent;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* Create an Agent (from the AgentProfile), pass it a single prompt and output
|
|
217
|
-
* the response.
|
|
218
|
-
*/
|
|
219
|
-
export async function runOneShot(
|
|
220
|
-
url: string,
|
|
221
|
-
agentProfile: AgentProfile,
|
|
222
|
-
defaultModel: string,
|
|
223
|
-
conversation: MessageParam[] | undefined,
|
|
224
|
-
platform: IPlatform,
|
|
225
|
-
prompt: string,
|
|
226
|
-
image: string | undefined,
|
|
227
|
-
llmApiKey: string | undefined,
|
|
228
|
-
sudomcpConfig: SudoMcpConfiguration,
|
|
229
|
-
approveToolsUpTo: number
|
|
230
|
-
): Promise<{
|
|
231
|
-
response: string;
|
|
232
|
-
conversation: MessageParam[];
|
|
233
|
-
images: ContentPartImage[] | undefined;
|
|
234
|
-
}> {
|
|
235
|
-
logger.debug("[runOneShot]: start");
|
|
236
|
-
|
|
237
|
-
// Create a non-interactive agent and pass any prompt/ image to it. Return
|
|
238
|
-
// the first answer.
|
|
239
|
-
|
|
240
|
-
const agent = await createNonInteractiveAgent(
|
|
241
|
-
url,
|
|
242
|
-
agentProfile,
|
|
243
|
-
defaultModel,
|
|
244
|
-
conversation,
|
|
245
|
-
platform,
|
|
246
|
-
llmApiKey,
|
|
247
|
-
sudomcpConfig,
|
|
248
|
-
approveToolsUpTo
|
|
249
|
-
);
|
|
250
|
-
|
|
251
|
-
const agentResponse = await agent.userMessageEx(prompt, image);
|
|
252
|
-
await agent.shutdown();
|
|
253
|
-
logger.debug("[runOneShot]: shutdown done");
|
|
254
|
-
|
|
255
|
-
if (!agentResponse) {
|
|
256
|
-
throw new Error("No message returned from agent");
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
// Handle different content types
|
|
260
|
-
const response = agentResponse.message;
|
|
261
|
-
let responseText = "";
|
|
262
|
-
if (typeof response.content === "string") {
|
|
263
|
-
responseText = response.content;
|
|
264
|
-
} else if (response.content === null || response.content === undefined) {
|
|
265
|
-
responseText = "";
|
|
266
|
-
} else if (Array.isArray(response.content)) {
|
|
267
|
-
// Handle array of content parts
|
|
268
|
-
responseText = response.content
|
|
269
|
-
.map((part) => {
|
|
270
|
-
if ("text" in part) {
|
|
271
|
-
return part.text;
|
|
272
|
-
}
|
|
273
|
-
return "";
|
|
274
|
-
})
|
|
275
|
-
.join("");
|
|
276
|
-
} else {
|
|
277
|
-
// Fallback for other types
|
|
278
|
-
responseText = String(response.content);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
return {
|
|
282
|
-
response: responseText,
|
|
283
|
-
conversation: agent.getConversation(),
|
|
284
|
-
images: agentResponse.images,
|
|
285
|
-
};
|
|
286
|
-
}
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import { strict as assert } from "assert";
|
|
2
|
-
import { getLogger } from "@xalia/xmcp/sdk";
|
|
3
|
-
|
|
4
|
-
import { Agent } from "./agent";
|
|
5
|
-
import { UserMessageParam, MessageParam, ILLM } from "./llm";
|
|
6
|
-
import { ContextManager } from "./context";
|
|
7
|
-
import { NULL_AGENT_EVENT_HANDLER } from "./nullAgentEventHandler";
|
|
8
|
-
import { ContextManagerWithWorkspace } from "./contextWithWorkspace";
|
|
9
|
-
|
|
10
|
-
const logger = getLogger();
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* System prompt used to generate a conversation summary.
|
|
14
|
-
*/
|
|
15
|
-
const COMPRESSION_SYSTEM_PROMPT =
|
|
16
|
-
// eslint-disable-next-line max-len
|
|
17
|
-
"You are a context summarizer, creating MINIMAL conversation digests which can be used to CONTINUE the conversation at a later date. TOKEN EFFICIENCY is a HIGH PRIORITY. Summaries will only be seen by LLMs and should USE ANY AND ALL ABBREVIATIONS to keep them as CONCISE as possible, while PRESERVING IMPORTANT DETAILS of the CONVERSATION.";
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Text prepended to a summary to create the checkpoint message
|
|
21
|
-
*/
|
|
22
|
-
const CHECKPOINT_MESSAGE_PREFIX =
|
|
23
|
-
// eslint-disable-next-line max-len
|
|
24
|
-
"We are continuing an earlier conversation. The remainder of this message is a summary of the conversation so far: ";
|
|
25
|
-
|
|
26
|
-
export function createCheckpointMessage(summary: string): UserMessageParam {
|
|
27
|
-
return {
|
|
28
|
-
role: "user",
|
|
29
|
-
content: CHECKPOINT_MESSAGE_PREFIX + summary,
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function createCompressionAgent(llm: ILLM): Agent {
|
|
34
|
-
return Agent.initializeWithLLM(
|
|
35
|
-
NULL_AGENT_EVENT_HANDLER,
|
|
36
|
-
llm,
|
|
37
|
-
new ContextManager(COMPRESSION_SYSTEM_PROMPT, [])
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export async function createSummary(
|
|
42
|
-
llm: ILLM,
|
|
43
|
-
conversation: MessageParam[]
|
|
44
|
-
): Promise<string> {
|
|
45
|
-
const agent = createCompressionAgent(llm);
|
|
46
|
-
const agentResp = await agent.userMessageEx(JSON.stringify(conversation));
|
|
47
|
-
if (!agentResp) {
|
|
48
|
-
throw new Error("compression agent returned null");
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const resp = agentResp.message;
|
|
52
|
-
assert(resp.role === "assistant");
|
|
53
|
-
assert(
|
|
54
|
-
typeof resp.content === "string",
|
|
55
|
-
"expected string content from compression agent"
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
return resp.content;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Can perform compression on the committed part of the context. Caller (not
|
|
63
|
-
* the Agent) is responsible for committing the conversation and triggering
|
|
64
|
-
* compression.
|
|
65
|
-
*/
|
|
66
|
-
export class CompressingContextManager extends ContextManagerWithWorkspace {
|
|
67
|
-
readonly getLLM: () => Promise<ILLM>;
|
|
68
|
-
compressingMessages: number | undefined;
|
|
69
|
-
|
|
70
|
-
constructor(
|
|
71
|
-
systemPrompt: string,
|
|
72
|
-
messages: MessageParam[],
|
|
73
|
-
getLLM: () => Promise<ILLM>
|
|
74
|
-
) {
|
|
75
|
-
super(systemPrompt, messages);
|
|
76
|
-
this.getLLM = getLLM;
|
|
77
|
-
this.compressingMessages = undefined;
|
|
78
|
-
|
|
79
|
-
// Sanity check the conversation form.
|
|
80
|
-
//
|
|
81
|
-
// Ordinarily, the committed context should end with an "assistant"
|
|
82
|
-
// message (i.e. user messages, an agent loop terminating in a final agent
|
|
83
|
-
// response). However, if a conversation has been compressed, we may have
|
|
84
|
-
// only the summary, which is a "user" message. In this case, this should
|
|
85
|
-
// be the only message.
|
|
86
|
-
|
|
87
|
-
const numMessages = this.numMessages();
|
|
88
|
-
const lastMessage = this.lastMessage();
|
|
89
|
-
if (lastMessage) {
|
|
90
|
-
const finalRole = lastMessage.role;
|
|
91
|
-
if (finalRole === "user") {
|
|
92
|
-
assert(numMessages === 1);
|
|
93
|
-
} else {
|
|
94
|
-
assert(finalRole === "assistant", `unexpected final role ${finalRole}`);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
async compress(): Promise<string> {
|
|
100
|
-
const numToCompress = super.numMessages();
|
|
101
|
-
const messagesToCompress = this.leadingMessages(numToCompress);
|
|
102
|
-
assert(messagesToCompress.length === numToCompress);
|
|
103
|
-
this.compressingMessages = numToCompress;
|
|
104
|
-
assert(this.compressingMessages > 1, "<2 messages commited in the context");
|
|
105
|
-
|
|
106
|
-
logger.debug(
|
|
107
|
-
`[CompressingContextManager] start (${String(this.compressingMessages)})`
|
|
108
|
-
);
|
|
109
|
-
|
|
110
|
-
try {
|
|
111
|
-
const llm = await this.getLLM();
|
|
112
|
-
const summary = await createSummary(llm, messagesToCompress);
|
|
113
|
-
|
|
114
|
-
logger.debug(`[CompressingContextManager] summary: ${summary}`);
|
|
115
|
-
|
|
116
|
-
// Replace the context `messages` and update `lastCommittedMessage`
|
|
117
|
-
// index.
|
|
118
|
-
|
|
119
|
-
const checkpointMessage = createCheckpointMessage(summary);
|
|
120
|
-
assert(typeof checkpointMessage.content === "string");
|
|
121
|
-
this.replaceLeadingMessages(numToCompress, checkpointMessage);
|
|
122
|
-
|
|
123
|
-
return summary;
|
|
124
|
-
} finally {
|
|
125
|
-
this.compressingMessages = undefined;
|
|
126
|
-
logger.debug(`[CompressingContextManager] compression done`);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
package/src/agent/context.ts
DELETED
|
@@ -1,265 +0,0 @@
|
|
|
1
|
-
import { strict as assert } from "assert";
|
|
2
|
-
import { MessageParam, UserMessageParam } from "./llm";
|
|
3
|
-
import { SystemPromptProvider } from "./promptProvider";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* ContextWriter
|
|
7
|
-
*/
|
|
8
|
-
export interface IContextTransaction {
|
|
9
|
-
/**
|
|
10
|
-
* Add messages to the context. Return handle to the first message.
|
|
11
|
-
*/
|
|
12
|
-
addMessages(messages: MessageParam[]): number;
|
|
13
|
-
/**
|
|
14
|
-
* Add a single message to the context. Returns a handle which can be used to
|
|
15
|
-
* overwrite the message before it it committed.
|
|
16
|
-
*/
|
|
17
|
-
addMessage(message: MessageParam): number;
|
|
18
|
-
/**
|
|
19
|
-
* Retrieve message by handle. Returns a reference to the message itself,
|
|
20
|
-
* so changes made by the caller will be committed.
|
|
21
|
-
*/
|
|
22
|
-
getMessage(handle: number): MessageParam;
|
|
23
|
-
/**
|
|
24
|
-
* Get all LLM messages including system message (for LLM calls). Owned by
|
|
25
|
-
* the transaction.
|
|
26
|
-
*/
|
|
27
|
-
getLLMContext(): MessageParam[];
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Length of context, including messages in this tx
|
|
31
|
-
*/
|
|
32
|
-
getLLMContextLength(): number;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Implementations of IContextManager manage the context, exposing it as an
|
|
37
|
-
* array of `ChatCompletionMessageParam[]`. The system prompt is managed
|
|
38
|
-
* elsewhere, and set to this object by the caller.
|
|
39
|
-
*/
|
|
40
|
-
export interface IContextManager {
|
|
41
|
-
/**
|
|
42
|
-
* Get all LLM messages including system message (for LLM calls).
|
|
43
|
-
*/
|
|
44
|
-
getLLMContext(): MessageParam[];
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Get the "fixed" part of the system prompt
|
|
48
|
-
*/
|
|
49
|
-
getAgentPrompt(): string;
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Set the "fixed" part of the system prompt
|
|
53
|
-
*/
|
|
54
|
-
setAgentPrompt(prompt: string): void;
|
|
55
|
-
|
|
56
|
-
setPromptFragment(fragmentID: string, prompt: string): void;
|
|
57
|
-
|
|
58
|
-
removePromptFragment(fragmentID: string): void;
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Start a transaction
|
|
62
|
-
*/
|
|
63
|
-
startTx(userMessages: UserMessageParam[]): Promise<IContextTransaction>;
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Commit
|
|
67
|
-
*/
|
|
68
|
-
commit(writer: IContextTransaction): Promise<void>;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export class ContextTransaction implements IContextTransaction {
|
|
72
|
-
private messages: MessageParam[];
|
|
73
|
-
private origLength: number;
|
|
74
|
-
|
|
75
|
-
constructor(baseMessages: MessageParam[], userMessages: UserMessageParam[]) {
|
|
76
|
-
assert(baseMessages[0].role === "system");
|
|
77
|
-
assert(baseMessages[1]?.role !== "system");
|
|
78
|
-
|
|
79
|
-
this.messages = baseMessages;
|
|
80
|
-
this.origLength = this.messages.length;
|
|
81
|
-
this.messages.push(...userMessages);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// IContextTransaction.addMessages
|
|
85
|
-
addMessages(messages: MessageParam[]): number {
|
|
86
|
-
assert(messages.every((m) => m.role !== "user"));
|
|
87
|
-
const handle = this.messages.length;
|
|
88
|
-
for (const message of messages) {
|
|
89
|
-
this.messages.push(message);
|
|
90
|
-
}
|
|
91
|
-
return handle;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// IContextTransaction.addMessage
|
|
95
|
-
addMessage(message: MessageParam): number {
|
|
96
|
-
assert(message.role !== "user");
|
|
97
|
-
const handle = this.messages.length;
|
|
98
|
-
this.messages.push(message);
|
|
99
|
-
return handle;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// IContextTransaction.getMessage
|
|
103
|
-
getMessage(handle: number): MessageParam {
|
|
104
|
-
assert(handle < this.messages.length);
|
|
105
|
-
return this.messages[handle];
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// IContextTransaction.getLLMContext
|
|
109
|
-
getLLMContext(): MessageParam[] {
|
|
110
|
-
return this.messages;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// IContextTransaction.getLLMContextLength
|
|
114
|
-
getLLMContextLength(): number {
|
|
115
|
-
return this.messages.length;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
newMessages(): MessageParam[] {
|
|
119
|
-
return this.messages.slice(this.origLength);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
protected getLLMContextOrigLength(): number {
|
|
123
|
-
return this.origLength;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
protected lastMessage(): MessageParam | undefined {
|
|
127
|
-
if (this.messages.length > 1) {
|
|
128
|
-
return this.messages[this.messages.length - 1];
|
|
129
|
-
}
|
|
130
|
-
return undefined;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
popMessage(): MessageParam | undefined {
|
|
134
|
-
if (this.messages.length > this.origLength) {
|
|
135
|
-
return this.messages.pop();
|
|
136
|
-
}
|
|
137
|
-
return undefined;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Trivial implementation of IContextManage which just manages the context as
|
|
143
|
-
* an array of `ChatCompletionMessageParam[]`
|
|
144
|
-
*/
|
|
145
|
-
export class ContextManager implements IContextManager {
|
|
146
|
-
private messages: MessageParam[];
|
|
147
|
-
private systemPromptProvider: SystemPromptProvider;
|
|
148
|
-
|
|
149
|
-
constructor(systemPrompt: string, messages: MessageParam[]) {
|
|
150
|
-
assert(messages.length === 0 || messages[0].role !== "system");
|
|
151
|
-
|
|
152
|
-
// Insert system message at the beginning if not present
|
|
153
|
-
if (messages.length === 0 || messages[0].role !== "system") {
|
|
154
|
-
this.messages = [
|
|
155
|
-
{
|
|
156
|
-
role: "system",
|
|
157
|
-
content: "",
|
|
158
|
-
} as MessageParam,
|
|
159
|
-
...messages,
|
|
160
|
-
];
|
|
161
|
-
} else {
|
|
162
|
-
assert(false);
|
|
163
|
-
// this.messages = [...conversationMessages];
|
|
164
|
-
// this.messages[0] = {systemPrompt;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
this.systemPromptProvider = new SystemPromptProvider(systemPrompt);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// IContextManager.getLLMContext
|
|
171
|
-
getLLMContext(): MessageParam[] {
|
|
172
|
-
return this.getLLMContextRaw().slice();
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// IContextManager.getAgentPrompt
|
|
176
|
-
getAgentPrompt(): string {
|
|
177
|
-
return this.systemPromptProvider.getAgentPrompt();
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// IContextManager.setAgentPrompt
|
|
181
|
-
setAgentPrompt(prompt: string): void {
|
|
182
|
-
this.systemPromptProvider.setAgentPrompt(prompt);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// IContextManager.setPromptFragment
|
|
186
|
-
setPromptFragment(fragmentID: string, prompt: string) {
|
|
187
|
-
this.systemPromptProvider.setFragment(fragmentID, prompt);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// IContextManager.removePromptFragment
|
|
191
|
-
removePromptFragment(fragmentID: string) {
|
|
192
|
-
this.systemPromptProvider.removeFragment(fragmentID);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// IContextManager.startTx
|
|
196
|
-
startTx(userMessages: UserMessageParam[]): Promise<ContextTransaction> {
|
|
197
|
-
return Promise.resolve(
|
|
198
|
-
new ContextTransaction(this.getLLMContext(), userMessages)
|
|
199
|
-
);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// IContextManager.commit
|
|
203
|
-
commit(writer: IContextTransaction): Promise<void> {
|
|
204
|
-
assert(writer instanceof ContextTransaction);
|
|
205
|
-
const newMessages = writer.newMessages();
|
|
206
|
-
this.messages.push(...newMessages);
|
|
207
|
-
return Promise.resolve();
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
clear(): void {
|
|
211
|
-
this.messages = [
|
|
212
|
-
{
|
|
213
|
-
role: "system",
|
|
214
|
-
content: "",
|
|
215
|
-
},
|
|
216
|
-
];
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
protected lastMessage(): MessageParam | undefined {
|
|
220
|
-
if (this.messages.length > 1) {
|
|
221
|
-
return this.messages[this.messages.length - 1];
|
|
222
|
-
}
|
|
223
|
-
return undefined;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
protected numMessages(): number {
|
|
227
|
-
return this.messages.length - 1;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
protected leadingMessages(numMessages: number): MessageParam[] {
|
|
231
|
-
return this.messages.slice(1, numMessages + 1);
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
protected trailingMessagesFrom(idx: number): MessageParam[] {
|
|
235
|
-
return this.messages.slice(1 + idx);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
protected replaceLeadingMessages(
|
|
239
|
-
numMessagesToReplace: number,
|
|
240
|
-
replacement: MessageParam
|
|
241
|
-
): void {
|
|
242
|
-
assert(this.messages.length >= 1 + numMessagesToReplace);
|
|
243
|
-
const remainingMsgs = this.messages.slice(1 + numMessagesToReplace);
|
|
244
|
-
this.messages = [this.messages[0], replacement, ...remainingMsgs];
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
protected popMessage(): MessageParam | undefined {
|
|
248
|
-
if (this.messages.length > 1) {
|
|
249
|
-
return this.messages.pop();
|
|
250
|
-
}
|
|
251
|
-
return undefined;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
protected pushMessage(...msgs: MessageParam[]) {
|
|
255
|
-
this.messages.push(...msgs);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/// Returns the actual array (so that child classes can avoid an unnecessary
|
|
259
|
-
/// copy)
|
|
260
|
-
protected getLLMContextRaw(): MessageParam[] {
|
|
261
|
-
assert(this.messages[0].role === "system");
|
|
262
|
-
this.messages[0].content = this.systemPromptProvider.getSystemPrompt();
|
|
263
|
-
return this.messages;
|
|
264
|
-
}
|
|
265
|
-
}
|