@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.
Files changed (161) hide show
  1. package/package.json +5 -2
  2. package/.env.development +0 -6
  3. package/.env.test +0 -7
  4. package/.prettierrc.json +0 -11
  5. package/context_system.md +0 -498
  6. package/eslint.config.mjs +0 -38
  7. package/scripts/chat_server +0 -8
  8. package/scripts/git_message +0 -31
  9. package/scripts/git_wip +0 -21
  10. package/scripts/pr_message +0 -18
  11. package/scripts/pr_review +0 -16
  12. package/scripts/setup_chat +0 -90
  13. package/scripts/shutdown_chat_server +0 -42
  14. package/scripts/start_chat_server +0 -24
  15. package/scripts/sudomcp_import +0 -23
  16. package/scripts/test_chat +0 -327
  17. package/src/agent/agent.ts +0 -699
  18. package/src/agent/agentUtils.ts +0 -286
  19. package/src/agent/compressingContextManager.ts +0 -129
  20. package/src/agent/context.ts +0 -265
  21. package/src/agent/contextWithWorkspace.ts +0 -162
  22. package/src/agent/documentSummarizer.ts +0 -157
  23. package/src/agent/dummyLLM.ts +0 -130
  24. package/src/agent/iAgentEventHandler.ts +0 -64
  25. package/src/agent/imageGenLLM.ts +0 -101
  26. package/src/agent/imageGenerator.ts +0 -45
  27. package/src/agent/iplatform.ts +0 -18
  28. package/src/agent/llm.ts +0 -74
  29. package/src/agent/mcpServerManager.ts +0 -541
  30. package/src/agent/nullAgentEventHandler.ts +0 -26
  31. package/src/agent/nullPlatform.ts +0 -13
  32. package/src/agent/openAI.ts +0 -123
  33. package/src/agent/openAILLM.ts +0 -99
  34. package/src/agent/openAILLMStreaming.ts +0 -648
  35. package/src/agent/promptProvider.ts +0 -87
  36. package/src/agent/repeatLLM.ts +0 -62
  37. package/src/agent/sudoMcpServerManager.ts +0 -361
  38. package/src/agent/test_data/harrypotter.txt +0 -6065
  39. package/src/agent/tokenAuth.ts +0 -50
  40. package/src/agent/tokenCounter.test.ts +0 -243
  41. package/src/agent/tokenCounter.ts +0 -483
  42. package/src/agent/toolSettings.ts +0 -24
  43. package/src/agent/tools/calculatorTool.ts +0 -50
  44. package/src/agent/tools/contentExtractors/htmlToText.ts +0 -61
  45. package/src/agent/tools/contentExtractors/pdfToText.ts +0 -60
  46. package/src/agent/tools/datetimeTool.ts +0 -41
  47. package/src/agent/tools/fileManager/fileManagerTool.ts +0 -199
  48. package/src/agent/tools/fileManager/index.ts +0 -50
  49. package/src/agent/tools/fileManager/memoryFileManager.ts +0 -120
  50. package/src/agent/tools/fileManager/mimeTypes.ts +0 -60
  51. package/src/agent/tools/fileManager/prompt.ts +0 -38
  52. package/src/agent/tools/fileManager/types.ts +0 -189
  53. package/src/agent/tools/index.ts +0 -49
  54. package/src/agent/tools/openUrlTool.ts +0 -62
  55. package/src/agent/tools/renderTool.ts +0 -92
  56. package/src/agent/tools/utils.ts +0 -74
  57. package/src/agent/tools/webSearch.ts +0 -138
  58. package/src/agent/tools/webSearchTool.ts +0 -44
  59. package/src/chat/client/chatClient.ts +0 -967
  60. package/src/chat/client/connection.test.ts +0 -241
  61. package/src/chat/client/connection.ts +0 -286
  62. package/src/chat/client/constants.ts +0 -1
  63. package/src/chat/client/index.ts +0 -21
  64. package/src/chat/client/interfaces.ts +0 -34
  65. package/src/chat/client/sessionClient.ts +0 -574
  66. package/src/chat/client/sessionFiles.ts +0 -142
  67. package/src/chat/client/teamManager.ts +0 -29
  68. package/src/chat/constants.ts +0 -6
  69. package/src/chat/data/apiKeyManager.ts +0 -76
  70. package/src/chat/data/dataModels.ts +0 -107
  71. package/src/chat/data/database.ts +0 -997
  72. package/src/chat/data/dbMcpServerConfigs.ts +0 -59
  73. package/src/chat/data/dbSessionFiles.ts +0 -107
  74. package/src/chat/data/dbSessionMessages.ts +0 -102
  75. package/src/chat/protocol/connectionMessages.ts +0 -49
  76. package/src/chat/protocol/constants.ts +0 -55
  77. package/src/chat/protocol/errors.ts +0 -16
  78. package/src/chat/protocol/messages.ts +0 -899
  79. package/src/chat/server/README.md +0 -127
  80. package/src/chat/server/chatContextManager.ts +0 -660
  81. package/src/chat/server/connectionManager.test.ts +0 -246
  82. package/src/chat/server/connectionManager.ts +0 -506
  83. package/src/chat/server/conversation.ts +0 -319
  84. package/src/chat/server/errorUtils.ts +0 -28
  85. package/src/chat/server/imageGeneratorTools.ts +0 -179
  86. package/src/chat/server/openAIRouterLLM.ts +0 -168
  87. package/src/chat/server/openSession.ts +0 -1945
  88. package/src/chat/server/openSessionMessageSender.ts +0 -4
  89. package/src/chat/server/promptRefiner.ts +0 -106
  90. package/src/chat/server/server.ts +0 -178
  91. package/src/chat/server/sessionFileManager.ts +0 -151
  92. package/src/chat/server/sessionRegistry.test.ts +0 -137
  93. package/src/chat/server/sessionRegistry.ts +0 -1553
  94. package/src/chat/server/test-utils/mockFactories.ts +0 -422
  95. package/src/chat/server/titleGenerator.test.ts +0 -103
  96. package/src/chat/server/titleGenerator.ts +0 -143
  97. package/src/chat/server/tools.ts +0 -170
  98. package/src/chat/utils/agentSessionMap.ts +0 -76
  99. package/src/chat/utils/approvalManager.ts +0 -189
  100. package/src/chat/utils/asyncLock.ts +0 -43
  101. package/src/chat/utils/asyncQueue.ts +0 -62
  102. package/src/chat/utils/multiAsyncQueue.ts +0 -66
  103. package/src/chat/utils/responseAwaiter.ts +0 -181
  104. package/src/chat/utils/userResolver.ts +0 -48
  105. package/src/chat/utils/websocket.ts +0 -16
  106. package/src/index.ts +0 -0
  107. package/src/test/agent.test.ts +0 -584
  108. package/src/test/approvalManager.test.ts +0 -141
  109. package/src/test/chatContextManager.test.ts +0 -552
  110. package/src/test/clientServerConnection.test.ts +0 -205
  111. package/src/test/compressingContextManager.test.ts +0 -77
  112. package/src/test/context.test.ts +0 -150
  113. package/src/test/contextTestTools.ts +0 -95
  114. package/src/test/conversation.test.ts +0 -109
  115. package/src/test/db.test.ts +0 -363
  116. package/src/test/dbMcpServerConfigs.test.ts +0 -112
  117. package/src/test/dbSessionFiles.test.ts +0 -258
  118. package/src/test/dbSessionMessages.test.ts +0 -85
  119. package/src/test/dbTestTools.ts +0 -157
  120. package/src/test/imageLoad.test.ts +0 -15
  121. package/src/test/mcpServerManager.test.ts +0 -114
  122. package/src/test/multiAsyncQueue.test.ts +0 -183
  123. package/src/test/openaiStreaming.test.ts +0 -177
  124. package/src/test/prompt.test.ts +0 -27
  125. package/src/test/promptProvider.test.ts +0 -33
  126. package/src/test/responseAwaiter.test.ts +0 -103
  127. package/src/test/sudoMcpServerManager.test.ts +0 -63
  128. package/src/test/testTools.ts +0 -176
  129. package/src/test/tools.test.ts +0 -64
  130. package/src/tool/agentChat.ts +0 -203
  131. package/src/tool/agentMain.ts +0 -180
  132. package/src/tool/chatMain.ts +0 -621
  133. package/src/tool/commandPrompt.ts +0 -264
  134. package/src/tool/files.ts +0 -82
  135. package/src/tool/main.ts +0 -25
  136. package/src/tool/nodePlatform.ts +0 -73
  137. package/src/tool/options.ts +0 -144
  138. package/src/tool/prompt.ts +0 -101
  139. package/test_data/background_test_profile.json +0 -6
  140. package/test_data/background_test_script.json +0 -11
  141. package/test_data/dummyllm_script_crash.json +0 -32
  142. package/test_data/dummyllm_script_image_gen.json +0 -19
  143. package/test_data/dummyllm_script_image_gen_fe.json +0 -29
  144. package/test_data/dummyllm_script_invoke_image_gen_tool.json +0 -37
  145. package/test_data/dummyllm_script_render_tool.json +0 -29
  146. package/test_data/dummyllm_script_simplecalc.json +0 -28
  147. package/test_data/dummyllm_script_test_auto_approve.json +0 -81
  148. package/test_data/dummyllm_script_test_simplecalc_addition.json +0 -29
  149. package/test_data/frog.png +0 -0
  150. package/test_data/frog.png.b64 +0 -1
  151. package/test_data/git_message_profile.json +0 -4
  152. package/test_data/git_wip_system.txt +0 -5
  153. package/test_data/image_gen_test_profile.json +0 -5
  154. package/test_data/pr_message_profile.json +0 -4
  155. package/test_data/pr_review_profile.json +0 -4
  156. package/test_data/prompt_simplecalc.txt +0 -1
  157. package/test_data/simplecalc_profile.json +0 -4
  158. package/test_data/sudomcp_import_profile.json +0 -4
  159. package/test_data/test_script_profile.json +0 -8
  160. package/tsconfig.json +0 -13
  161. package/vitest.config.ts +0 -39
@@ -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
- }
@@ -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
- }