@xalia/agent 0.5.8 → 0.6.0

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 (185) hide show
  1. package/README.md +23 -8
  2. package/dist/agent/src/agent/agent.js +173 -96
  3. package/dist/agent/src/agent/agentUtils.js +82 -53
  4. package/dist/agent/src/agent/compressingContextManager.js +102 -0
  5. package/dist/agent/src/agent/context.js +189 -0
  6. package/dist/agent/src/agent/dummyLLM.js +46 -5
  7. package/dist/agent/src/agent/iAgentEventHandler.js +2 -0
  8. package/dist/agent/src/agent/mcpServerManager.js +22 -23
  9. package/dist/agent/src/agent/nullAgentEventHandler.js +21 -0
  10. package/dist/agent/src/agent/nullPlatform.js +14 -0
  11. package/dist/agent/src/agent/openAILLMStreaming.js +12 -7
  12. package/dist/agent/src/agent/promptProvider.js +63 -0
  13. package/dist/agent/src/agent/repeatLLM.js +5 -5
  14. package/dist/agent/src/agent/sudoMcpServerManager.js +11 -9
  15. package/dist/agent/src/agent/tokenAuth.js +7 -7
  16. package/dist/agent/src/agent/tools.js +1 -1
  17. package/dist/agent/src/chat/client/chatClient.js +733 -0
  18. package/dist/agent/src/chat/client/connection.js +209 -0
  19. package/dist/agent/src/chat/client/connection.test.js +188 -0
  20. package/dist/agent/src/chat/client/constants.js +5 -0
  21. package/dist/agent/src/chat/client/index.js +15 -0
  22. package/dist/agent/src/chat/client/interfaces.js +2 -0
  23. package/dist/agent/src/chat/client/responseHandler.js +105 -0
  24. package/dist/agent/src/chat/client/sessionClient.js +331 -0
  25. package/dist/agent/src/chat/client/teamManager.js +2 -0
  26. package/dist/agent/src/chat/{apiKeyManager.js → data/apiKeyManager.js} +4 -0
  27. package/dist/agent/src/chat/data/dataModels.js +2 -0
  28. package/dist/agent/src/chat/data/database.js +749 -0
  29. package/dist/agent/src/chat/data/dbMcpServerConfigs.js +47 -0
  30. package/dist/agent/src/chat/protocol/connectionMessages.js +5 -0
  31. package/dist/agent/src/chat/protocol/constants.js +50 -0
  32. package/dist/agent/src/chat/protocol/errors.js +22 -0
  33. package/dist/agent/src/chat/protocol/messages.js +110 -0
  34. package/dist/agent/src/chat/server/chatContextManager.js +405 -0
  35. package/dist/agent/src/chat/server/connectionManager.js +352 -0
  36. package/dist/agent/src/chat/server/connectionManager.test.js +159 -0
  37. package/dist/agent/src/chat/server/conversation.js +198 -0
  38. package/dist/agent/src/chat/server/errorUtils.js +23 -0
  39. package/dist/agent/src/chat/server/openSession.js +869 -0
  40. package/dist/agent/src/chat/server/server.js +177 -0
  41. package/dist/agent/src/chat/server/sessionFileManager.js +161 -0
  42. package/dist/agent/src/chat/server/sessionRegistry.js +700 -0
  43. package/dist/agent/src/chat/server/sessionRegistry.test.js +97 -0
  44. package/dist/agent/src/chat/server/test-utils/mockFactories.js +307 -0
  45. package/dist/agent/src/chat/server/tools.js +243 -0
  46. package/dist/agent/src/chat/utils/agentSessionMap.js +66 -0
  47. package/dist/agent/src/chat/utils/approvalManager.js +85 -0
  48. package/dist/agent/src/{utils → chat/utils}/asyncLock.js +3 -3
  49. package/dist/agent/src/chat/{asyncQueue.js → utils/asyncQueue.js} +12 -2
  50. package/dist/agent/src/chat/utils/htmlToText.js +84 -0
  51. package/dist/agent/src/chat/utils/multiAsyncQueue.js +42 -0
  52. package/dist/agent/src/chat/utils/search.js +145 -0
  53. package/dist/agent/src/chat/utils/userResolver.js +46 -0
  54. package/dist/agent/src/chat/{websocket.js → utils/websocket.js} +2 -0
  55. package/dist/agent/src/test/agent.test.js +332 -0
  56. package/dist/agent/src/test/approvalManager.test.js +58 -0
  57. package/dist/agent/src/test/chatContextManager.test.js +392 -0
  58. package/dist/agent/src/test/clientServerConnection.test.js +158 -0
  59. package/dist/agent/src/test/compressingContextManager.test.js +65 -0
  60. package/dist/agent/src/test/context.test.js +83 -0
  61. package/dist/agent/src/test/conversation.test.js +89 -0
  62. package/dist/agent/src/test/db.test.js +262 -90
  63. package/dist/agent/src/test/dbMcpServerConfigs.test.js +72 -0
  64. package/dist/agent/src/test/dbTestTools.js +99 -0
  65. package/dist/agent/src/test/imageLoad.test.js +8 -7
  66. package/dist/agent/src/test/mcpServerManager.test.js +21 -18
  67. package/dist/agent/src/test/multiAsyncQueue.test.js +101 -0
  68. package/dist/agent/src/test/openaiStreaming.test.js +12 -11
  69. package/dist/agent/src/test/prompt.test.js +5 -4
  70. package/dist/agent/src/test/promptProvider.test.js +28 -0
  71. package/dist/agent/src/test/responseHandler.test.js +61 -0
  72. package/dist/agent/src/test/sudoMcpServerManager.test.js +14 -12
  73. package/dist/agent/src/test/testTools.js +109 -0
  74. package/dist/agent/src/test/tools.test.js +31 -0
  75. package/dist/agent/src/tool/agentChat.js +21 -10
  76. package/dist/agent/src/tool/agentMain.js +1 -1
  77. package/dist/agent/src/tool/chatMain.js +235 -58
  78. package/dist/agent/src/tool/commandPrompt.js +15 -9
  79. package/dist/agent/src/tool/files.js +20 -16
  80. package/dist/agent/src/tool/nodePlatform.js +47 -3
  81. package/dist/agent/src/tool/options.js +4 -4
  82. package/dist/agent/src/tool/prompt.js +19 -13
  83. package/eslint.config.mjs +14 -1
  84. package/package.json +14 -6
  85. package/scripts/chat_server +8 -0
  86. package/scripts/setup_chat +7 -2
  87. package/scripts/shutdown_chat_server +3 -0
  88. package/scripts/test_chat +135 -17
  89. package/src/agent/agent.ts +270 -135
  90. package/src/agent/agentUtils.ts +136 -95
  91. package/src/agent/compressingContextManager.ts +164 -0
  92. package/src/agent/context.ts +268 -0
  93. package/src/agent/dummyLLM.ts +76 -8
  94. package/src/agent/iAgentEventHandler.ts +54 -0
  95. package/src/agent/iplatform.ts +1 -0
  96. package/src/agent/mcpServerManager.ts +32 -30
  97. package/src/agent/nullAgentEventHandler.ts +20 -0
  98. package/src/agent/nullPlatform.ts +13 -0
  99. package/src/agent/openAILLMStreaming.ts +12 -6
  100. package/src/agent/promptProvider.ts +87 -0
  101. package/src/agent/repeatLLM.ts +5 -5
  102. package/src/agent/sudoMcpServerManager.ts +13 -11
  103. package/src/agent/tokenAuth.ts +7 -7
  104. package/src/agent/tools.ts +3 -1
  105. package/src/chat/client/chatClient.ts +900 -0
  106. package/src/chat/client/connection.test.ts +241 -0
  107. package/src/chat/client/connection.ts +276 -0
  108. package/src/chat/client/constants.ts +3 -0
  109. package/src/chat/client/index.ts +18 -0
  110. package/src/chat/client/interfaces.ts +34 -0
  111. package/src/chat/client/responseHandler.ts +131 -0
  112. package/src/chat/client/sessionClient.ts +443 -0
  113. package/src/chat/client/teamManager.ts +29 -0
  114. package/src/chat/{apiKeyManager.ts → data/apiKeyManager.ts} +6 -2
  115. package/src/chat/data/dataModels.ts +85 -0
  116. package/src/chat/data/database.ts +982 -0
  117. package/src/chat/data/dbMcpServerConfigs.ts +59 -0
  118. package/src/chat/protocol/connectionMessages.ts +49 -0
  119. package/src/chat/protocol/constants.ts +55 -0
  120. package/src/chat/protocol/errors.ts +16 -0
  121. package/src/chat/protocol/messages.ts +682 -0
  122. package/src/chat/server/README.md +127 -0
  123. package/src/chat/server/chatContextManager.ts +612 -0
  124. package/src/chat/server/connectionManager.test.ts +266 -0
  125. package/src/chat/server/connectionManager.ts +541 -0
  126. package/src/chat/server/conversation.ts +269 -0
  127. package/src/chat/server/errorUtils.ts +28 -0
  128. package/src/chat/server/openSession.ts +1332 -0
  129. package/src/chat/server/server.ts +177 -0
  130. package/src/chat/server/sessionFileManager.ts +239 -0
  131. package/src/chat/server/sessionRegistry.test.ts +138 -0
  132. package/src/chat/server/sessionRegistry.ts +1064 -0
  133. package/src/chat/server/test-utils/mockFactories.ts +422 -0
  134. package/src/chat/server/tools.ts +265 -0
  135. package/src/chat/utils/agentSessionMap.ts +76 -0
  136. package/src/chat/utils/approvalManager.ts +111 -0
  137. package/src/{utils → chat/utils}/asyncLock.ts +3 -3
  138. package/src/chat/{asyncQueue.ts → utils/asyncQueue.ts} +14 -3
  139. package/src/chat/utils/htmlToText.ts +61 -0
  140. package/src/chat/utils/multiAsyncQueue.ts +52 -0
  141. package/src/chat/utils/search.ts +139 -0
  142. package/src/chat/utils/userResolver.ts +48 -0
  143. package/src/chat/{websocket.ts → utils/websocket.ts} +2 -0
  144. package/src/test/agent.test.ts +487 -0
  145. package/src/test/approvalManager.test.ts +73 -0
  146. package/src/test/chatContextManager.test.ts +521 -0
  147. package/src/test/clientServerConnection.test.ts +207 -0
  148. package/src/test/compressingContextManager.test.ts +82 -0
  149. package/src/test/context.test.ts +105 -0
  150. package/src/test/conversation.test.ts +109 -0
  151. package/src/test/db.test.ts +351 -103
  152. package/src/test/dbMcpServerConfigs.test.ts +112 -0
  153. package/src/test/dbTestTools.ts +153 -0
  154. package/src/test/imageLoad.test.ts +7 -6
  155. package/src/test/mcpServerManager.test.ts +19 -14
  156. package/src/test/multiAsyncQueue.test.ts +125 -0
  157. package/src/test/openaiStreaming.test.ts +11 -10
  158. package/src/test/prompt.test.ts +4 -3
  159. package/src/test/promptProvider.test.ts +33 -0
  160. package/src/test/responseHandler.test.ts +78 -0
  161. package/src/test/sudoMcpServerManager.test.ts +22 -15
  162. package/src/test/testTools.ts +146 -0
  163. package/src/test/tools.test.ts +39 -0
  164. package/src/tool/agentChat.ts +26 -12
  165. package/src/tool/agentMain.ts +1 -1
  166. package/src/tool/chatMain.ts +283 -100
  167. package/src/tool/commandPrompt.ts +25 -9
  168. package/src/tool/files.ts +25 -19
  169. package/src/tool/nodePlatform.ts +52 -3
  170. package/src/tool/options.ts +4 -2
  171. package/src/tool/prompt.ts +22 -15
  172. package/test_data/dummyllm_script_crash.json +32 -0
  173. package/test_data/frog.png.b64 +1 -0
  174. package/vitest.config.ts +39 -0
  175. package/dist/agent/src/chat/client.js +0 -310
  176. package/dist/agent/src/chat/conversationManager.js +0 -502
  177. package/dist/agent/src/chat/db.js +0 -218
  178. package/dist/agent/src/chat/messages.js +0 -29
  179. package/dist/agent/src/chat/server.js +0 -158
  180. package/src/chat/client.ts +0 -445
  181. package/src/chat/conversationManager.ts +0 -730
  182. package/src/chat/db.ts +0 -304
  183. package/src/chat/messages.ts +0 -266
  184. package/src/chat/server.ts +0 -177
  185. /package/{frog.png → test_data/frog.png} +0 -0
@@ -0,0 +1,269 @@
1
+ /// Abstraction of LLM messages (suitable for passing conversations to the
2
+ /// LLM) and SessionMessage (saved in the DB)
3
+
4
+ import { strict as assert } from "assert";
5
+
6
+ import {
7
+ ChatCompletionMessageParam,
8
+ ChatCompletionUserMessageParam,
9
+ createUserMessage,
10
+ } from "../../agent/agent";
11
+ import { SessionMessage, UserMessageData } from "../data/dataModels";
12
+ import {
13
+ ServerAgentMessage,
14
+ ServerToolCallResult,
15
+ ServerUserMessage,
16
+ } from "../protocol/messages";
17
+ import { ChatErrorMessage } from "../protocol/errors";
18
+
19
+ export const MESSAGE_INDEX_START_VALUE = 0;
20
+ export const MESSAGE_INDEX_FULL_INCREMENT = 100;
21
+ export const MESSAGE_INDEX_SUB_INCREMENT = 1;
22
+
23
+ // MESSAGE_INDEX_START_VALUE = N * MESSAGE_INDEX_FULL_INCREMENT
24
+ // <=> MESSAGE_INDEX_START_VALUE =
25
+ // floor(MESSAGE_INDEX_START_VALUE/MESSAGE_INDEX_FULL_INCREMENT)
26
+ // * MESSAGE_INDEX_FULL_INCREMENT
27
+ assert(
28
+ MESSAGE_INDEX_START_VALUE ===
29
+ ((MESSAGE_INDEX_START_VALUE / MESSAGE_INDEX_FULL_INCREMENT) | 0) *
30
+ MESSAGE_INDEX_FULL_INCREMENT
31
+ );
32
+
33
+ export type ConversationMessage =
34
+ | ServerUserMessage
35
+ | ServerAgentMessage
36
+ | ServerToolCallResult;
37
+
38
+ /**
39
+ * Compute the next message index to assign. Note, this is non-trivial since
40
+ * we use a 'BIGINT with gaps' strategy to ensure that multi-part agent
41
+ * messages can be inserted into the conversation.
42
+ */
43
+ export function sessionMessagesToNextIndex(
44
+ sessionMessages: SessionMessage[]
45
+ ): number {
46
+ const numMessages = sessionMessages.length;
47
+ if (numMessages === 0) {
48
+ return MESSAGE_INDEX_START_VALUE;
49
+ }
50
+
51
+ const lastIdx = sessionMessages[numMessages - 1].message_idx;
52
+
53
+ // We must compute lastIdx + 1 rounded up to the nearest
54
+ // MESSAGE_INDEX_FULL_INCREMENT
55
+ const numFullIncrements =
56
+ (lastIdx + MESSAGE_INDEX_FULL_INCREMENT) / MESSAGE_INDEX_FULL_INCREMENT;
57
+ const floorNumFullIncrements = numFullIncrements | 0;
58
+ return floorNumFullIncrements * MESSAGE_INDEX_FULL_INCREMENT;
59
+ }
60
+
61
+ /**
62
+ * The conversation history may be truncated. In this case, discard any
63
+ * messages which do not make sense (e.g. leading Agent messages). Inform the
64
+ * caller of the first messages to be included in the conversation, so it can
65
+ * request messages further back in history if required.
66
+ */
67
+ export function sessionMessagesToLLMConversation(
68
+ sessionMessages: SessionMessage[]
69
+ ): { firstIndex: number; conversation: ChatCompletionMessageParam[] } {
70
+ const conversation = [];
71
+ let started = false;
72
+ let firstIndex: number = -1;
73
+
74
+ for (const msg of sessionMessages) {
75
+ if (!msg.is_for_llm) {
76
+ continue;
77
+ }
78
+
79
+ const llmMsg = msg.content;
80
+
81
+ // Skip leading messages which are not the users. Record the index of the
82
+ // first message we actually use.
83
+
84
+ if (!started) {
85
+ if (llmMsg.role !== "user") {
86
+ continue;
87
+ }
88
+
89
+ started = true;
90
+ firstIndex = msg.message_idx;
91
+ }
92
+
93
+ conversation.push(llmMsg);
94
+ }
95
+
96
+ return { firstIndex, conversation };
97
+ }
98
+
99
+ export function sessionMessagesToChatMessages(
100
+ sessionMessages: SessionMessage[],
101
+ defaultUserUuid: string,
102
+ session_id: string
103
+ ): (ServerUserMessage | ServerAgentMessage)[] {
104
+ const msgs: (ServerUserMessage | ServerAgentMessage)[] = [];
105
+ for (const sm of sessionMessages) {
106
+ const ccmp = sm.content;
107
+ const message_idx = sm.message_idx;
108
+ switch (ccmp.role) {
109
+ case "developer":
110
+ throw new Error("developer messages not handled yet");
111
+ case "assistant":
112
+ assert(!ccmp.audio);
113
+ if (ccmp.content) {
114
+ msgs.push({
115
+ type: "agent_msg",
116
+ message: ccmp,
117
+ message_idx,
118
+ session_id,
119
+ });
120
+ }
121
+ // TODO: do we want to convert tool calls etc?
122
+ break;
123
+ case "user":
124
+ {
125
+ const msg = userMessageToChatMessage(
126
+ ccmp,
127
+ message_idx,
128
+ defaultUserUuid,
129
+ session_id
130
+ );
131
+ if (msg) {
132
+ msgs.push(msg);
133
+ }
134
+ }
135
+ break;
136
+ default:
137
+ break;
138
+ }
139
+ }
140
+
141
+ return msgs;
142
+ }
143
+
144
+ export function llmUserMessageToUserMessageData(
145
+ userMessage: ChatCompletionUserMessageParam
146
+ ): UserMessageData | undefined {
147
+ if (typeof userMessage.content === "string") {
148
+ return {
149
+ message: userMessage.content,
150
+ };
151
+ }
152
+
153
+ let message = "";
154
+ let image: string | undefined = undefined;
155
+ for (const content of userMessage.content) {
156
+ switch (content.type) {
157
+ case "text":
158
+ message += content.text;
159
+ break;
160
+ case "image_url":
161
+ assert(!image, "only one image per message supported");
162
+ image = content.image_url.url;
163
+ break;
164
+ case "input_audio":
165
+ throw new ChatErrorMessage(
166
+ "userMessageToChatMessage: audio content not supported"
167
+ );
168
+ case "file":
169
+ throw new ChatErrorMessage(
170
+ "userMessageToChatMessage: file content not supported"
171
+ );
172
+ default:
173
+ throw new ChatErrorMessage(
174
+ "userMessageToChatMessage: unexpected content.type"
175
+ );
176
+ }
177
+ }
178
+
179
+ const finalMsg: UserMessageData = {
180
+ message,
181
+ };
182
+ if (image) {
183
+ finalMsg.imageB64 = image;
184
+ }
185
+ return finalMsg;
186
+ }
187
+
188
+ export function userMessageToChatMessage(
189
+ userMessage: ChatCompletionUserMessageParam,
190
+ message_idx: number,
191
+ defaultUserUuid: string,
192
+ session_id: string
193
+ ): ServerUserMessage | undefined {
194
+ // The name on the message should be the uuid
195
+
196
+ const userMsgData = llmUserMessageToUserMessageData(userMessage);
197
+ if (!userMsgData) {
198
+ return undefined;
199
+ }
200
+
201
+ const user_uuid = userMessage.name || defaultUserUuid;
202
+ const msg: ServerUserMessage = {
203
+ type: "user_msg",
204
+ message: userMsgData.message,
205
+ message_idx,
206
+ user_uuid,
207
+ session_id,
208
+ };
209
+ if (userMsgData.imageB64) {
210
+ msg.imageB64 = userMsgData.imageB64;
211
+ }
212
+ return msg;
213
+ }
214
+
215
+ export function chatToolResultMessageToSessionMessage(
216
+ chatMessage: ServerToolCallResult
217
+ ): SessionMessage {
218
+ return {
219
+ message_idx: chatMessage.message_idx,
220
+ is_for_llm: true,
221
+ content: chatMessage.result,
222
+ };
223
+ }
224
+
225
+ export function chatUserMessageToSessionMessage(
226
+ chatMessage: ServerUserMessage
227
+ ): SessionMessage {
228
+ const userMsg = createUserMessage(
229
+ chatMessage.message,
230
+ chatMessage.imageB64,
231
+ chatMessage.user_uuid
232
+ );
233
+ assert(userMsg);
234
+ return {
235
+ message_idx: chatMessage.message_idx,
236
+ is_for_llm: true,
237
+ sender_uuid: chatMessage.user_uuid,
238
+ content: userMsg,
239
+ };
240
+ }
241
+
242
+ export function chatAgentMessageToSessionMessage(
243
+ chatMessage: ServerAgentMessage
244
+ ): SessionMessage {
245
+ return {
246
+ message_idx: chatMessage.message_idx,
247
+ is_for_llm: true,
248
+ content: chatMessage.message,
249
+ };
250
+ }
251
+
252
+ export function chatMessagesToSessionMessages(
253
+ chatMessages: ConversationMessage[]
254
+ ): SessionMessage[] {
255
+ return chatMessages.map((c) => {
256
+ switch (c.type) {
257
+ case "user_msg":
258
+ return chatUserMessageToSessionMessage(c);
259
+ case "agent_msg":
260
+ return chatAgentMessageToSessionMessage(c);
261
+ case "tool_call_result":
262
+ return chatToolResultMessageToSessionMessage(c);
263
+ default: {
264
+ const exhaustive: never = c;
265
+ return exhaustive;
266
+ }
267
+ }
268
+ });
269
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Extract error string from an unknown error. Handles raw strings, `Error`
3
+ * objects, DB errors and falls back to outputting as String and JSON.
4
+ */
5
+ export function getErrorString(err: unknown): string {
6
+ if (typeof err === "string") {
7
+ return err;
8
+ }
9
+
10
+ if (err instanceof Error) {
11
+ // Generic Error. For now just send messages, don't close.
12
+ return "internal server error: " + err.message;
13
+ }
14
+
15
+ const dbErr = err as {
16
+ code: string | undefined;
17
+ details: string | undefined;
18
+ };
19
+ if (dbErr.code && dbErr.details) {
20
+ return "db error: " + dbErr.details;
21
+ }
22
+
23
+ return (
24
+ `unknown err (${typeof err}, ${String(err?.constructor?.name)}) ` +
25
+ JSON.stringify(err) +
26
+ "String(err)"
27
+ );
28
+ }