@xalia/agent 0.6.9 → 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 (199) hide show
  1. package/README.md +11 -0
  2. package/dist/agent/src/agent/agent.js +77 -18
  3. package/dist/agent/src/agent/agentUtils.js +3 -2
  4. package/dist/agent/src/agent/documentSummarizer.js +126 -0
  5. package/dist/agent/src/agent/dummyLLM.js +25 -22
  6. package/dist/agent/src/agent/imageGenLLM.js +22 -19
  7. package/dist/agent/src/agent/llm.js +1 -1
  8. package/dist/agent/src/agent/openAILLM.js +15 -12
  9. package/dist/agent/src/agent/openAILLMStreaming.js +68 -37
  10. package/dist/agent/src/agent/repeatLLM.js +16 -7
  11. package/dist/agent/src/agent/tokenCounter.js +390 -0
  12. package/dist/agent/src/agent/tokenCounter.test.js +206 -0
  13. package/dist/agent/src/agent/toolSettings.js +17 -0
  14. package/dist/agent/src/agent/tools/calculatorTool.js +45 -0
  15. package/dist/agent/src/agent/tools/contentExtractors/pdfToText.js +55 -0
  16. package/dist/agent/src/agent/tools/datetimeTool.js +38 -0
  17. package/dist/agent/src/agent/tools/fileManager/fileManagerTool.js +156 -0
  18. package/dist/agent/src/agent/tools/fileManager/index.js +31 -0
  19. package/dist/agent/src/agent/tools/fileManager/memoryFileManager.js +102 -0
  20. package/dist/agent/src/{chat/data → agent/tools/fileManager}/mimeTypes.js +3 -1
  21. package/dist/agent/src/agent/tools/fileManager/prompt.js +33 -0
  22. package/dist/agent/src/{chat/data/dbSessionFileModels.js → agent/tools/fileManager/types.js} +7 -0
  23. package/dist/agent/src/agent/tools/index.js +64 -0
  24. package/dist/agent/src/agent/tools/openUrlTool.js +57 -0
  25. package/dist/agent/src/agent/tools/renderTool.js +89 -0
  26. package/dist/agent/src/agent/tools/utils.js +61 -0
  27. package/dist/agent/src/{chat/utils/search.js → agent/tools/webSearch.js} +1 -2
  28. package/dist/agent/src/agent/tools/webSearchTool.js +40 -0
  29. package/dist/agent/src/chat/client/chatClient.js +28 -0
  30. package/dist/agent/src/chat/client/index.js +4 -1
  31. package/dist/agent/src/chat/client/sessionClient.js +28 -2
  32. package/dist/agent/src/chat/constants.js +8 -0
  33. package/dist/agent/src/chat/data/dbSessionFiles.js +11 -6
  34. package/dist/agent/src/chat/protocol/messages.js +5 -0
  35. package/dist/agent/src/chat/server/chatContextManager.js +45 -25
  36. package/dist/agent/src/chat/server/conversation.js +3 -0
  37. package/dist/agent/src/chat/server/imageGeneratorTools.js +20 -8
  38. package/dist/agent/src/chat/server/openAIRouterLLM.js +0 -3
  39. package/dist/agent/src/chat/server/openSession.js +218 -55
  40. package/dist/agent/src/chat/server/promptRefiner.js +86 -0
  41. package/dist/agent/src/chat/server/server.js +5 -1
  42. package/dist/agent/src/chat/server/sessionFileManager.js +22 -221
  43. package/dist/agent/src/chat/server/sessionRegistry.js +87 -0
  44. package/dist/agent/src/chat/server/titleGenerator.js +112 -0
  45. package/dist/agent/src/chat/server/titleGenerator.test.js +113 -0
  46. package/dist/agent/src/chat/server/tools.js +63 -287
  47. package/dist/agent/src/chat/utils/approvalManager.js +6 -3
  48. package/dist/agent/src/chat/utils/multiAsyncQueue.js +3 -0
  49. package/dist/agent/src/test/agent.test.js +16 -17
  50. package/dist/agent/src/test/chatContextManager.test.js +15 -3
  51. package/dist/agent/src/test/dbMcpServerConfigs.test.js +4 -4
  52. package/dist/agent/src/test/dbSessionFiles.test.js +17 -17
  53. package/dist/agent/src/test/testTools.js +6 -1
  54. package/dist/agent/src/test/tools.test.js +27 -9
  55. package/dist/agent/src/tool/agentChat.js +5 -2
  56. package/dist/agent/src/tool/chatMain.js +34 -7
  57. package/dist/agent/src/tool/commandPrompt.js +2 -2
  58. package/dist/agent/src/tool/files.js +7 -8
  59. package/package.json +8 -2
  60. package/.env.development +0 -1
  61. package/.prettierrc.json +0 -11
  62. package/dist/agent/src/agent/tools.js +0 -44
  63. package/eslint.config.mjs +0 -38
  64. package/scripts/chat_server +0 -8
  65. package/scripts/git_message +0 -31
  66. package/scripts/git_wip +0 -21
  67. package/scripts/pr_message +0 -18
  68. package/scripts/pr_review +0 -16
  69. package/scripts/setup_chat +0 -90
  70. package/scripts/shutdown_chat_server +0 -42
  71. package/scripts/start_chat_server +0 -24
  72. package/scripts/sudomcp_import +0 -23
  73. package/scripts/test_chat +0 -308
  74. package/src/agent/agent.ts +0 -624
  75. package/src/agent/agentUtils.ts +0 -285
  76. package/src/agent/compressingContextManager.ts +0 -129
  77. package/src/agent/context.ts +0 -265
  78. package/src/agent/contextWithWorkspace.ts +0 -162
  79. package/src/agent/dummyLLM.ts +0 -126
  80. package/src/agent/iAgentEventHandler.ts +0 -64
  81. package/src/agent/imageGenLLM.ts +0 -97
  82. package/src/agent/imageGenerator.ts +0 -45
  83. package/src/agent/iplatform.ts +0 -18
  84. package/src/agent/llm.ts +0 -74
  85. package/src/agent/mcpServerManager.ts +0 -541
  86. package/src/agent/nullAgentEventHandler.ts +0 -26
  87. package/src/agent/nullPlatform.ts +0 -13
  88. package/src/agent/openAI.ts +0 -123
  89. package/src/agent/openAILLM.ts +0 -95
  90. package/src/agent/openAILLMStreaming.ts +0 -609
  91. package/src/agent/promptProvider.ts +0 -87
  92. package/src/agent/repeatLLM.ts +0 -50
  93. package/src/agent/sudoMcpServerManager.ts +0 -361
  94. package/src/agent/tokenAuth.ts +0 -50
  95. package/src/agent/tools.ts +0 -57
  96. package/src/chat/client/chatClient.ts +0 -922
  97. package/src/chat/client/connection.test.ts +0 -241
  98. package/src/chat/client/connection.ts +0 -286
  99. package/src/chat/client/constants.ts +0 -1
  100. package/src/chat/client/index.ts +0 -18
  101. package/src/chat/client/interfaces.ts +0 -34
  102. package/src/chat/client/sessionClient.ts +0 -537
  103. package/src/chat/client/sessionFiles.ts +0 -142
  104. package/src/chat/client/teamManager.ts +0 -29
  105. package/src/chat/data/apiKeyManager.ts +0 -76
  106. package/src/chat/data/dataModels.ts +0 -101
  107. package/src/chat/data/database.ts +0 -997
  108. package/src/chat/data/dbMcpServerConfigs.ts +0 -59
  109. package/src/chat/data/dbSessionFileModels.ts +0 -113
  110. package/src/chat/data/dbSessionFiles.ts +0 -99
  111. package/src/chat/data/dbSessionMessages.ts +0 -102
  112. package/src/chat/data/mimeTypes.ts +0 -58
  113. package/src/chat/protocol/connectionMessages.ts +0 -49
  114. package/src/chat/protocol/constants.ts +0 -55
  115. package/src/chat/protocol/errors.ts +0 -16
  116. package/src/chat/protocol/messages.ts +0 -846
  117. package/src/chat/server/README.md +0 -127
  118. package/src/chat/server/chatContextManager.ts +0 -639
  119. package/src/chat/server/connectionManager.test.ts +0 -246
  120. package/src/chat/server/connectionManager.ts +0 -506
  121. package/src/chat/server/conversation.ts +0 -316
  122. package/src/chat/server/errorUtils.ts +0 -28
  123. package/src/chat/server/imageGeneratorTools.ts +0 -160
  124. package/src/chat/server/openAIRouterLLM.ts +0 -171
  125. package/src/chat/server/openSession.ts +0 -1689
  126. package/src/chat/server/openSessionMessageSender.ts +0 -4
  127. package/src/chat/server/server.ts +0 -175
  128. package/src/chat/server/sessionFileManager.ts +0 -422
  129. package/src/chat/server/sessionRegistry.test.ts +0 -137
  130. package/src/chat/server/sessionRegistry.ts +0 -1425
  131. package/src/chat/server/test-utils/mockFactories.ts +0 -422
  132. package/src/chat/server/tools.ts +0 -397
  133. package/src/chat/utils/agentSessionMap.ts +0 -76
  134. package/src/chat/utils/approvalManager.ts +0 -183
  135. package/src/chat/utils/asyncLock.ts +0 -43
  136. package/src/chat/utils/asyncQueue.ts +0 -62
  137. package/src/chat/utils/htmlToText.ts +0 -61
  138. package/src/chat/utils/multiAsyncQueue.ts +0 -62
  139. package/src/chat/utils/responseAwaiter.ts +0 -181
  140. package/src/chat/utils/search.ts +0 -139
  141. package/src/chat/utils/userResolver.ts +0 -48
  142. package/src/chat/utils/websocket.ts +0 -16
  143. package/src/index.ts +0 -0
  144. package/src/test/agent.test.ts +0 -590
  145. package/src/test/approvalManager.test.ts +0 -141
  146. package/src/test/chatContextManager.test.ts +0 -527
  147. package/src/test/clientServerConnection.test.ts +0 -205
  148. package/src/test/compressingContextManager.test.ts +0 -77
  149. package/src/test/context.test.ts +0 -150
  150. package/src/test/contextTestTools.ts +0 -95
  151. package/src/test/conversation.test.ts +0 -109
  152. package/src/test/db.test.ts +0 -363
  153. package/src/test/dbMcpServerConfigs.test.ts +0 -112
  154. package/src/test/dbSessionFiles.test.ts +0 -258
  155. package/src/test/dbSessionMessages.test.ts +0 -85
  156. package/src/test/dbTestTools.ts +0 -157
  157. package/src/test/imageLoad.test.ts +0 -15
  158. package/src/test/mcpServerManager.test.ts +0 -114
  159. package/src/test/multiAsyncQueue.test.ts +0 -183
  160. package/src/test/openaiStreaming.test.ts +0 -177
  161. package/src/test/prompt.test.ts +0 -27
  162. package/src/test/promptProvider.test.ts +0 -33
  163. package/src/test/responseAwaiter.test.ts +0 -103
  164. package/src/test/sudoMcpServerManager.test.ts +0 -63
  165. package/src/test/testTools.ts +0 -171
  166. package/src/test/tools.test.ts +0 -39
  167. package/src/tool/agentChat.ts +0 -194
  168. package/src/tool/agentMain.ts +0 -180
  169. package/src/tool/chatMain.ts +0 -594
  170. package/src/tool/commandPrompt.ts +0 -264
  171. package/src/tool/files.ts +0 -84
  172. package/src/tool/main.ts +0 -25
  173. package/src/tool/nodePlatform.ts +0 -73
  174. package/src/tool/options.ts +0 -144
  175. package/src/tool/prompt.ts +0 -101
  176. package/test_data/background_test_profile.json +0 -6
  177. package/test_data/background_test_script.json +0 -11
  178. package/test_data/dummyllm_script_crash.json +0 -32
  179. package/test_data/dummyllm_script_image_gen.json +0 -19
  180. package/test_data/dummyllm_script_image_gen_fe.json +0 -29
  181. package/test_data/dummyllm_script_invoke_image_gen_tool.json +0 -37
  182. package/test_data/dummyllm_script_render_tool.json +0 -29
  183. package/test_data/dummyllm_script_simplecalc.json +0 -28
  184. package/test_data/dummyllm_script_test_auto_approve.json +0 -81
  185. package/test_data/dummyllm_script_test_simplecalc_addition.json +0 -29
  186. package/test_data/frog.png +0 -0
  187. package/test_data/frog.png.b64 +0 -1
  188. package/test_data/git_message_profile.json +0 -4
  189. package/test_data/git_wip_system.txt +0 -5
  190. package/test_data/image_gen_test_profile.json +0 -5
  191. package/test_data/pr_message_profile.json +0 -4
  192. package/test_data/pr_review_profile.json +0 -4
  193. package/test_data/prompt_simplecalc.txt +0 -1
  194. package/test_data/simplecalc_profile.json +0 -4
  195. package/test_data/sudomcp_import_profile.json +0 -4
  196. package/test_data/test_script_profile.json +0 -8
  197. package/tsconfig.json +0 -13
  198. package/vitest.config.ts +0 -39
  199. /package/dist/agent/src/{chat/utils → agent/tools/contentExtractors}/htmlToText.js +0 -0
@@ -1,594 +0,0 @@
1
- /* eslint-disable @typescript-eslint/only-throw-error */
2
-
3
- import chalk from "chalk";
4
- import { command, optional, option, string, number, subcommands } from "cmd-ts";
5
- import { stdout } from "process";
6
- import * as fs from "fs";
7
- import { strict as assert } from "assert";
8
-
9
- import { configuration } from "@xalia/xmcp/tool";
10
- import { getLogger } from "@xalia/xmcp/sdk";
11
-
12
- import {
13
- ChatClient,
14
- SessionClient,
15
- IChatClientEventHandler,
16
- } from "../chat/client";
17
- import {
18
- runServer,
19
- resolveSessionIdFromIdentifier,
20
- } from "../chat/server/server";
21
- import {
22
- ServerToClient,
23
- decodeAssistantMessageParam,
24
- } from "../chat/protocol/messages";
25
- import { Database, createSessionParticipantMap } from "../chat/data/database";
26
-
27
- import { IPrompt, Prompt, ScriptPrompt } from "./prompt";
28
- import * as options from "./options";
29
- import { CommandPrompt } from "./commandPrompt";
30
- import { NODE_PLATFORM } from "./nodePlatform";
31
- import { loadImageAsDataUrl, loadSessionFileAsDataUrl } from "./files";
32
- import { isFileMetaData } from "../chat/data/dbSessionFileModels";
33
-
34
- const logger = getLogger();
35
-
36
- const listSessions = command({
37
- name: "delete-session",
38
- args: {
39
- supabaseUrl: options.supabaseUrl,
40
- supabaseKey: options.supabaseKey,
41
- },
42
- handler: async ({ supabaseUrl, supabaseKey }): Promise<void> => {
43
- const db = new Database(supabaseUrl, supabaseKey);
44
- console.log(JSON.stringify(await db.sessionsGet()));
45
- },
46
- });
47
-
48
- const clearSessions = command({
49
- name: "clear-sessions",
50
- args: {
51
- supabaseUrl: options.supabaseUrl,
52
- supabaseKey: options.supabaseKey,
53
- },
54
- handler: async ({ supabaseUrl, supabaseKey }): Promise<void> => {
55
- const db = new Database(supabaseUrl, supabaseKey);
56
- await db.clearSessions();
57
- },
58
- });
59
-
60
- const deleteSession = command({
61
- name: "delete-session",
62
- args: {
63
- supabaseUrl: options.supabaseUrl,
64
- supabaseKey: options.supabaseKey,
65
- session: option({
66
- type: string,
67
- long: "session",
68
- description:
69
- "Session identifier (id, name, user/name or name of new session)",
70
- env: "SESSION",
71
- }),
72
- },
73
- handler: async ({ supabaseUrl, supabaseKey, session }): Promise<void> => {
74
- const db = new Database(supabaseUrl, supabaseKey);
75
- const sessionId = await resolveSessionIdFromIdentifier(db, session);
76
- if (sessionId) {
77
- await db.sessionDeleteById(sessionId);
78
- } else {
79
- throw `No such session ${session}`;
80
- }
81
- },
82
- });
83
-
84
- const listParticipants = command({
85
- name: "list-participants",
86
- args: {
87
- supabaseUrl: options.supabaseUrl,
88
- supabaseKey: options.supabaseKey,
89
- session: option({
90
- type: string,
91
- long: "session",
92
- description:
93
- "Session identifier (id, name, user/name or name of new session)",
94
- env: "SESSION",
95
- }),
96
- },
97
- handler: async ({ supabaseUrl, supabaseKey, session }): Promise<void> => {
98
- const db = new Database(supabaseUrl, supabaseKey);
99
- const sessionId = await resolveSessionIdFromIdentifier(db, session);
100
- if (sessionId) {
101
- const participants = await db.sessionGetParticipants(sessionId);
102
-
103
- console.log(`participants: ${JSON.stringify(participants)}`);
104
- const users = createSessionParticipantMap(participants);
105
- console.log(JSON.stringify(users));
106
- } else {
107
- throw `No such session ${session}`;
108
- }
109
- },
110
- });
111
-
112
- const server = command({
113
- name: "server",
114
- args: {
115
- port: option({
116
- type: number,
117
- long: "port",
118
- short: "p",
119
- env: "CHAT_SERVER_PORT",
120
- defaultValue: () => 5003,
121
- }),
122
- supabaseUrl: options.supabaseUrl,
123
- supabaseKey: options.supabaseKey,
124
- xmcpUrl: options.xmcpUrl,
125
- pidFile: options.pidFile,
126
- },
127
- // eslint-disable-next-line @typescript-eslint/require-await
128
- handler: async ({
129
- port,
130
- supabaseUrl,
131
- supabaseKey,
132
- xmcpUrl,
133
- pidFile,
134
- }): Promise<void> => {
135
- if (pidFile) {
136
- fs.writeFileSync(pidFile, process.pid.toString());
137
- }
138
-
139
- void runServer(port, supabaseUrl, supabaseKey, xmcpUrl);
140
- },
141
- });
142
-
143
- const client = command({
144
- name: "client",
145
- args: {
146
- url: option({
147
- type: string,
148
- long: "url",
149
- short: "h",
150
- env: "CHAT_URL",
151
- description: "Chat server url",
152
- defaultValue: () => "ws://localhost:5003",
153
- }),
154
- apiKey: options.apiKey,
155
- sessionId: option({
156
- type: optional(string),
157
- long: "session-id",
158
- description: "Join existing session with the given UUID",
159
- env: "SESSION_UUID",
160
- }),
161
- teamId: option({
162
- type: optional(string),
163
- long: "team-id",
164
- description:
165
- "Team uuid, if not provided, a user session will be created.",
166
- env: "TEAM_ID",
167
- }),
168
- agentProfileId: option({
169
- type: optional(string),
170
- long: "agent-profile-id",
171
- description: "Create new session with agent profile (uuid)",
172
- env: "AGENT_PROFILE_ID",
173
- }),
174
- sessionTitle: option({
175
- type: optional(string),
176
- long: "session-title",
177
- description: "Title for new session",
178
- env: "SESSION_TITLE",
179
- }),
180
- script: option({
181
- type: optional(string),
182
- long: "script",
183
- description: "Script (file) to execute and then exit.",
184
- }),
185
- },
186
- handler: async ({
187
- url,
188
- apiKey,
189
- sessionId,
190
- agentProfileId,
191
- sessionTitle,
192
- teamId,
193
- script,
194
- }): Promise<void> => {
195
- if (!apiKey) {
196
- // TODO: configFIle param list in ../main.ts
197
- const sudomcpConfig = configuration.loadEnsureConfig();
198
- apiKey = sudomcpConfig.api_key;
199
- }
200
-
201
- const repl: IPrompt = (() => {
202
- if (script) {
203
- const scriptLines = fs.readFileSync(script, "utf8").split("\n");
204
- return new ScriptPrompt(scriptLines);
205
- }
206
- return new Prompt();
207
- })();
208
-
209
- const helpText = `
210
- ${chalk.yellow("/aa <server> <tool> [1]")} Auto approve
211
- ${chalk.yellow("/error <msg>")} Force server error
212
- ${chalk.yellow("/ap <team> <user>")} Add-Participant
213
- ${chalk.yellow("/rp <team> <user>")} Remove-Participant
214
- ${chalk.yellow("/lp")} List-Participants
215
- ${chalk.yellow("/si [<file>]")} Write Session id to file
216
- ${chalk.yellow("/ct <name>")} Create Team
217
- ${chalk.yellow("/ci [<file>]")} Write team id to file
218
- ${chalk.yellow("/sw [file:a.png|data:....]")} Set workspace (no args = clear)
219
- ${chalk.yellow("/list-files")} List file-manager files
220
- ${chalk.yellow("/put-file <name> <file:...|data:...>")} Add file
221
- ${chalk.yellow("/delete-file <name>")} Delete file
222
- ${chalk.yellow("/get-file <name>")} Get file contents
223
- ${chalk.yellow("/share-session <file>")} Share and write access token
224
- ${chalk.yellow("/pause-agent <0|1>")} Pause (or unpause) the agent
225
- ${chalk.yellow("/add-custom-mcp-server <server-name> <url>")} Add MCP server
226
- ${chalk.yellow("/remove-custom-mcp-server <server-name>")} Remove MCP server
227
- ${chalk.yellow("/list-custom-mcp-servers")} list custom mcp servers
228
- ${chalk.yellow("/get-resource <server-name> <uri>")} get MCP server resource
229
- `;
230
-
231
- const cmdPrompt = new CommandPrompt(repl, helpText);
232
- const eventHandler = getCLIEventHandler(cmdPrompt);
233
-
234
- const [client, sessionClient] = await (async () => {
235
- const newClient = await ChatClient.init(url, apiKey, eventHandler);
236
- if (sessionId) {
237
- if (agentProfileId || sessionTitle) {
238
- throw "t agent-profile-id/session-title set joining existing session";
239
- }
240
-
241
- console.log(`joining existing session: ${sessionId} ...`);
242
- const newSessionClient = await newClient.connectToSession(sessionId);
243
- return [newClient, newSessionClient];
244
- }
245
-
246
- const newSessionClient = await newClient.createNewSession(
247
- sessionTitle || "New Chat",
248
- agentProfileId,
249
- teamId
250
- );
251
- return [newClient, newSessionClient];
252
- })();
253
- logger.debug("client created");
254
-
255
- const onUnknownCommand = async (cmds: string[]): Promise<void> => {
256
- switch (cmds[0]) {
257
- case "aa":
258
- sessionClient.setAutoApproval(cmds[1], cmds[2], !!cmds[3]);
259
- break;
260
- case "error":
261
- sessionClient.sendMessage({ type: "fatal_error", message: cmds[1] });
262
- break;
263
- case "ap": // Add Participant
264
- case "au":
265
- client.addTeamMember(cmds[1], cmds[2]);
266
- break;
267
- case "rp": // Remove Participant
268
- case "ru":
269
- client.removeTeamMember(cmds[1], cmds[2]);
270
- break;
271
- case "lp": // List Participants
272
- case "lu":
273
- console.log(JSON.stringify(sessionClient.getParticipants()));
274
- break;
275
- case "si": // Write Session id to file
276
- fs.writeFileSync(cmds[1], sessionClient.getSessionUUID());
277
- break;
278
- case "ct": // Create Team
279
- client.createNewTeam(cmds[1], []);
280
- break;
281
- case "ci": // Write team id to file
282
- fs.writeFileSync(cmds[1], client.getCurrentTeamId() ?? "");
283
- break;
284
- case "sw": // Set workspace
285
- setWorkspaceFromPrompt(sessionClient, cmds);
286
- break;
287
- case "list-files": // List files
288
- listFiles(sessionClient, cmds[1]);
289
- break;
290
- case "put-file": // Add file
291
- putFile(sessionClient, cmds.slice(1));
292
- break;
293
- case "delete-file": // Delete file
294
- deleteFile(sessionClient, cmds[1]);
295
- break;
296
- case "get-file": // Get file contents
297
- await getFileContents(sessionClient, cmds[1]);
298
- break;
299
- case "share-session":
300
- await shareSession(sessionClient, cmds[1]);
301
- break;
302
- case "pause-agent":
303
- pauseAgent(sessionClient, cmds[1]);
304
- break;
305
- case "add-custom-mcp-server":
306
- addCustomMcpServer(client, cmds[1], cmds[2]);
307
- break;
308
- case "remove-custom-mcp-server":
309
- removeCustomMcpServer(client, cmds[1]);
310
- break;
311
- case "list-custom-mcp-servers":
312
- listCustomMcpServers(client);
313
- break;
314
- case "get-resource":
315
- await getResource(sessionClient, cmds[1], cmds[2]);
316
- break;
317
- default:
318
- console.log(`error: Unknown command ${cmds[0]}`);
319
- }
320
- };
321
-
322
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
323
- while (true) {
324
- const [msgText, imageFile] = await cmdPrompt.getNextPrompt(
325
- sessionClient,
326
- sessionClient.getSudoMcpServerManager(),
327
- onUnknownCommand
328
- );
329
- assert(imageFile === undefined);
330
-
331
- if (msgText === undefined) {
332
- logger.debug("exiting...");
333
- logger.info("exiting...");
334
- client.shutdown();
335
- return;
336
- }
337
-
338
- // TODO: other prompts
339
-
340
- if (msgText.length > 0) {
341
- logger.debug(`sending message: ${msgText}`);
342
- sessionClient.userMessage(msgText);
343
- } else {
344
- logger.debug("(ignoring empty message)");
345
- }
346
- }
347
- },
348
- });
349
-
350
- function listFiles(
351
- sessionClient: SessionClient,
352
- filename: string | undefined
353
- ): void {
354
- const sessionFiles = sessionClient.getSessionFiles();
355
- const fileList = sessionFiles.listFiles();
356
- const fileListStr = JSON.stringify(fileList, undefined, 2);
357
- console.log(`Session files:\n${fileListStr}`);
358
- if (filename) {
359
- fs.writeFileSync(filename, fileListStr);
360
- }
361
- }
362
-
363
- function putFile(sessionClient: SessionClient, tail: string[]): void {
364
- if (tail.length < 2) {
365
- throw new Error(`usage: put-file <name> <content ....>`);
366
- }
367
- const name = tail[0];
368
- let content = tail.slice(1).join(" ");
369
- if (content.startsWith("file:")) {
370
- content = loadSessionFileAsDataUrl(content.slice(5));
371
- }
372
-
373
- const sessionFiles = sessionClient.getSessionFiles();
374
- sessionFiles.putFileContent(name, undefined, content);
375
- }
376
-
377
- function deleteFile(sessionClient: SessionClient, name: string) {
378
- const sessionFiles = sessionClient.getSessionFiles();
379
- sessionFiles.deleteFile(name);
380
- }
381
-
382
- async function getFileContents(sessionClient: SessionClient, name: string) {
383
- const sessionFiles = sessionClient.getSessionFiles();
384
- const dataUrl = await sessionFiles.getFileContent(name);
385
- try {
386
- void NODE_PLATFORM.renderHTML(`<img src="${dataUrl}" />`);
387
- } catch {
388
- console.log(`(render failed) file ${name}: ${dataUrl}`);
389
- }
390
- }
391
-
392
- async function shareSession(sessionClient: SessionClient, filename: string) {
393
- const accessToken = await sessionClient.shareSession();
394
- fs.writeFileSync(filename, accessToken);
395
- }
396
-
397
- function pauseAgent(sessionClient: SessionClient, pause: string) {
398
- sessionClient.setAgentPaused(!!parseInt(pause));
399
- }
400
-
401
- function addCustomMcpServer(chatClient: ChatClient, name: string, url: string) {
402
- chatClient.addCustomMcpServer(name, "Temporary description", url);
403
- }
404
-
405
- function removeCustomMcpServer(chatClient: ChatClient, name: string) {
406
- chatClient.removeCustomMcpServer(name);
407
- }
408
-
409
- function listCustomMcpServers(chatClient: ChatClient) {
410
- const customMcpServers: Record<string, string> =
411
- chatClient.getCustomMcpServers();
412
- console.log(
413
- `Custom mcp serevrs:\n${JSON.stringify(customMcpServers, undefined, 2)}`
414
- );
415
- }
416
-
417
- async function getResource(
418
- sessionClient: SessionClient,
419
- serverName: string,
420
- resourceUrl: string
421
- ) {
422
- const contents = await sessionClient.getMcpResource(serverName, resourceUrl);
423
- console.log(
424
- `resource: (${serverName}) ${resourceUrl}: ${JSON.stringify(contents)}`
425
- );
426
- }
427
-
428
- function setWorkspaceFromPrompt(
429
- sessionClient: SessionClient,
430
- cmds: string[]
431
- ): void {
432
- let msg = "";
433
- let image = undefined;
434
- if (!cmds[1]) {
435
- sessionClient.setWorkspace(undefined, undefined);
436
- return;
437
- }
438
- if (cmds[1].startsWith("file:")) {
439
- image = loadImageAsDataUrl(cmds[1].slice(5));
440
- msg = cmds.slice(2).join(" ");
441
- console.log(`setting workspace: ${msg} (image: ${image})`);
442
- } else {
443
- msg = cmds.slice(1).join(" ");
444
- console.log(`setting workspace: ${msg}`);
445
- }
446
-
447
- sessionClient.setWorkspace(msg, image);
448
- }
449
-
450
- function getCLIEventHandler(
451
- cmdPrompt?: CommandPrompt
452
- ): IChatClientEventHandler {
453
- let numErrors = 0;
454
-
455
- const onClosed = async () => {
456
- logger.debug("[onClosed]");
457
- if (cmdPrompt) {
458
- // TODO: check if this fully shuts down
459
- await cmdPrompt.shutdown();
460
- }
461
-
462
- // If there have been errors, exit with an error code.
463
- process.exit(numErrors);
464
- };
465
-
466
- const onError = (message: string) => {
467
- numErrors++;
468
- logger.debug("[onError]");
469
- console.error(message);
470
- };
471
-
472
- let startMsg = true;
473
- let startReasoning = true;
474
- const onMessage = async (msg: ServerToClient, client: ChatClient) => {
475
- let sessionClient: SessionClient | undefined = undefined;
476
- try {
477
- sessionClient = client.getCurrentSession("[chatMain.onMessage]");
478
- } catch (error) {
479
- logger.error(String(error));
480
- return;
481
- }
482
-
483
- switch (msg.type) {
484
- case "user_msg":
485
- stdout.write(`[${msg.user_nickname}]: ${msg.message || ""}\n`);
486
- if (msg.imageB64) {
487
- stdout.write(`[${msg.user_nickname}]: IMAGE: ${msg.imageB64}\n`);
488
- }
489
- break;
490
- case "agent_msg":
491
- {
492
- const text = decodeAssistantMessageParam(msg.message);
493
- if (text) {
494
- stdout.write(`[AGENT]: ${text}\n`);
495
- }
496
- }
497
- break;
498
- case "agent_msg_chunk":
499
- if (startMsg) {
500
- if (!startReasoning) {
501
- stdout.write(chalk.grey("]\n"));
502
- }
503
- stdout.write("[AGENT]: ");
504
- startMsg = false;
505
- }
506
- stdout.write(msg.message);
507
- if (msg.end) {
508
- stdout.write("\n");
509
- startMsg = true;
510
- startReasoning = true;
511
- }
512
- break;
513
- case "agent_reasoning_chunk":
514
- if (startMsg) {
515
- stdout.write(chalk.grey(`[${msg.reasoning}`));
516
- startReasoning = false;
517
- } else {
518
- stdout.write(chalk.grey(msg.reasoning));
519
- }
520
- break;
521
- case "approve_tool_call":
522
- {
523
- const result = cmdPrompt
524
- ? await cmdPrompt.promptToolCall(msg.tool_call)
525
- : true;
526
- logger.debug(`cmdPrompt.promptToolCall returned: ${String(result)}`);
527
- sessionClient.toolCallApprovalResult(
528
- msg.id,
529
- result,
530
- false /* auto-approve */
531
- );
532
- }
533
- break;
534
- case "tool_call_result":
535
- {
536
- console.log(`tool call result: ${JSON.stringify(msg.result)}`);
537
-
538
- const metadata = msg.result._meta;
539
- if (isFileMetaData(metadata)) {
540
- console.log(`filemanager file: ${JSON.stringify(metadata)}`);
541
-
542
- // SessionFiles should already hold the file information.
543
-
544
- const sessionFiles = sessionClient.getSessionFiles();
545
- const { name } = sessionFiles.decodeSessionFileUrl(
546
- msg.result.content as string
547
- );
548
- if (!sessionFiles.descriptors.has(name)) {
549
- throw new Error(`no ${name} in SessionFiles`);
550
- }
551
- }
552
- }
553
- break;
554
- case "render_html":
555
- await NODE_PLATFORM.renderHTML(msg.html);
556
- break;
557
- case "authenticate":
558
- NODE_PLATFORM.openUrl(
559
- msg.url,
560
- new Promise<boolean>((r) => {
561
- r(true);
562
- }),
563
- msg.display_name
564
- );
565
- break;
566
- case "session_error":
567
- stdout.write(
568
- chalk.red(`session_error(${msg.session_id}): ${msg.message}`)
569
- );
570
- break;
571
- default:
572
- stdout.write(`(unrecognised) ${JSON.stringify(msg.type)}\n`);
573
- break;
574
- }
575
- };
576
-
577
- return {
578
- onMessage,
579
- onError,
580
- onClosed: onClosed,
581
- };
582
- }
583
-
584
- export const chatMain = subcommands({
585
- name: "chat",
586
- cmds: {
587
- server,
588
- client,
589
- "clear-sessions": clearSessions,
590
- "delete-session": deleteSession,
591
- "list-sessions": listSessions,
592
- "list-participants": listParticipants,
593
- },
594
- });