@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,316 +0,0 @@
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 { createUserMessage } from "../../agent/agent";
7
- import {
8
- AssistantMessageParam,
9
- MessageParam,
10
- ToolMessageParam,
11
- UserMessageParam,
12
- } from "../../agent/llm";
13
- import { SessionMessage, UserMessageData } from "../data/dataModels";
14
- import {
15
- ServerAgentMessage,
16
- ServerToolCallResult,
17
- ServerUserMessage,
18
- } from "../protocol/messages";
19
- import { ChatErrorMessage } from "../protocol/errors";
20
-
21
- export const MESSAGE_INDEX_START_VALUE = 0;
22
- export const MESSAGE_INDEX_FULL_INCREMENT = 100;
23
- export const MESSAGE_INDEX_SUB_INCREMENT = 1;
24
-
25
- // MESSAGE_INDEX_START_VALUE = N * MESSAGE_INDEX_FULL_INCREMENT
26
- // <=> MESSAGE_INDEX_START_VALUE =
27
- // floor(MESSAGE_INDEX_START_VALUE/MESSAGE_INDEX_FULL_INCREMENT)
28
- // * MESSAGE_INDEX_FULL_INCREMENT
29
- assert(
30
- MESSAGE_INDEX_START_VALUE ===
31
- ((MESSAGE_INDEX_START_VALUE / MESSAGE_INDEX_FULL_INCREMENT) | 0) *
32
- MESSAGE_INDEX_FULL_INCREMENT
33
- );
34
-
35
- export type ConversationMessage =
36
- | ServerUserMessage
37
- | ServerAgentMessage
38
- | ServerToolCallResult;
39
-
40
- /**
41
- * Compute the next message index to assign. Note, this is non-trivial since
42
- * we use a 'BIGINT with gaps' strategy to ensure that multi-part agent
43
- * messages can be inserted into the conversation.
44
- */
45
- export function sessionMessagesToNextIndex(
46
- sessionMessages: SessionMessage[]
47
- ): number {
48
- const numMessages = sessionMessages.length;
49
- if (numMessages === 0) {
50
- return MESSAGE_INDEX_START_VALUE;
51
- }
52
-
53
- const lastIdx = sessionMessages[numMessages - 1].message_idx;
54
-
55
- // We must compute lastIdx + 1 rounded up to the nearest
56
- // MESSAGE_INDEX_FULL_INCREMENT
57
- const numFullIncrements =
58
- (lastIdx + MESSAGE_INDEX_FULL_INCREMENT) / MESSAGE_INDEX_FULL_INCREMENT;
59
- const floorNumFullIncrements = numFullIncrements | 0;
60
- return floorNumFullIncrements * MESSAGE_INDEX_FULL_INCREMENT;
61
- }
62
-
63
- /**
64
- * The conversation history may be truncated. In this case, discard any
65
- * messages which do not make sense (e.g. leading Agent messages). Inform the
66
- * caller of the first messages to be included in the conversation, so it can
67
- * request messages further back in history if required.
68
- */
69
- export function sessionMessagesToLLMConversation(
70
- sessionMessages: SessionMessage[]
71
- ): { firstIndex: number; conversation: MessageParam[] } {
72
- const conversation = [];
73
- let started = false;
74
- let firstIndex: number = -1;
75
-
76
- for (const msg of sessionMessages) {
77
- if (!msg.is_for_llm) {
78
- continue;
79
- }
80
-
81
- const llmMsg = msg.content;
82
-
83
- // Skip leading messages which are not the users. Record the index of the
84
- // first message we actually use.
85
-
86
- if (!started) {
87
- if (llmMsg.role !== "user") {
88
- continue;
89
- }
90
-
91
- started = true;
92
- firstIndex = msg.message_idx;
93
- }
94
-
95
- conversation.push(llmMsg);
96
- }
97
-
98
- return { firstIndex, conversation };
99
- }
100
-
101
- /**
102
- * Convert the DB data (SessionMessage) for a ChatCompletionUserMessageParam
103
- * into a ServerUserMessage message.
104
- */
105
- export function userMessageToConversationMessage(
106
- userMessage: UserMessageParam,
107
- user_uuid: string,
108
- message_idx: number,
109
- session_id: string
110
- ): ServerUserMessage {
111
- // The name on the message should be the uuid
112
-
113
- const userMsgData = llmUserMessageToUserMessageData(userMessage);
114
- const user_nickname = userMessage.name;
115
- assert(
116
- user_nickname,
117
- `ChatCompletionUserMessageParam without user ${JSON.stringify(userMessage)}`
118
- );
119
- const msg: ServerUserMessage = {
120
- type: "user_msg",
121
- message: userMsgData.message,
122
- message_idx,
123
- user_uuid,
124
- user_nickname,
125
- session_id,
126
- };
127
- if (userMsgData.imageB64) {
128
- msg.imageB64 = userMsgData.imageB64;
129
- }
130
- return msg;
131
- }
132
-
133
- /**
134
- * Convert the DB data (SessionMessage) for a
135
- * ChatCompletionAssistantMessageParam into a ServerAgentMessage message.
136
- */
137
- export function assistantMessageToConversationMessage(
138
- msg: AssistantMessageParam,
139
- message_idx: number,
140
- session_id: string
141
- ): ServerAgentMessage {
142
- assert(!msg.audio);
143
- return {
144
- type: "agent_msg",
145
- message: msg,
146
- message_idx,
147
- session_id,
148
- };
149
- }
150
-
151
- /**
152
- * Convert the DB data (SessionMessage) for a ChatCompletionToolMessageParam
153
- * into a ServerToolCallResult message.
154
- */
155
- export function toolResultToConversationMessage(
156
- toolCall: ToolMessageParam,
157
- message_idx: number,
158
- session_id: string
159
- ): ServerToolCallResult {
160
- return {
161
- type: "tool_call_result",
162
- result: toolCall,
163
- message_idx,
164
- session_id,
165
- };
166
- }
167
-
168
- /**
169
- * Convert a set of SessionMessages (stored in the DB) into Conversation
170
- * messages (protocol which can be sent over the wire).
171
- */
172
- export function sessionMessagesToConversationMessages(
173
- sessionMessages: SessionMessage[],
174
- defaultUserUuid: string,
175
- session_id: string
176
- ): ConversationMessage[] {
177
- const msgs: ConversationMessage[] = [];
178
- for (const sm of sessionMessages) {
179
- const ccmp = sm.content;
180
- const message_idx = sm.message_idx;
181
- const msgRole = ccmp.role;
182
- switch (msgRole) {
183
- case "system":
184
- throw new Error("cannot convert system to ConversationMessage");
185
- case "assistant":
186
- msgs.push(
187
- assistantMessageToConversationMessage(ccmp, message_idx, session_id)
188
- );
189
- break;
190
- case "user":
191
- {
192
- const user_uuid = sm.sender_uuid || defaultUserUuid;
193
- msgs.push(
194
- userMessageToConversationMessage(
195
- ccmp,
196
- user_uuid,
197
- message_idx,
198
- session_id
199
- )
200
- );
201
- }
202
- break;
203
- case "tool":
204
- msgs.push(
205
- toolResultToConversationMessage(ccmp, message_idx, session_id)
206
- );
207
- break;
208
- default: {
209
- const _: never = ccmp;
210
- throw new Error(`unexpected message role: ${msgRole as string}`);
211
- }
212
- }
213
- }
214
-
215
- return msgs;
216
- }
217
-
218
- export function llmUserMessageToUserMessageData(
219
- userMessage: UserMessageParam
220
- ): UserMessageData {
221
- if (typeof userMessage.content === "string") {
222
- return {
223
- message: userMessage.content,
224
- };
225
- }
226
-
227
- let message = "";
228
- let image: string | undefined = undefined;
229
- for (const content of userMessage.content) {
230
- switch (content.type) {
231
- case "text":
232
- message += content.text;
233
- break;
234
- case "image_url":
235
- assert(!image, "only one image per message supported");
236
- image = content.image_url.url;
237
- break;
238
- case "input_audio":
239
- throw new ChatErrorMessage(
240
- "llmUserMessageToUserMessageData: audio content not supported"
241
- );
242
- case "file":
243
- throw new ChatErrorMessage(
244
- "llmUserMessageToUserMessageData: file content not supported"
245
- );
246
- default:
247
- throw new ChatErrorMessage(
248
- "llmUserMessageToUserMessageData: unexpected content.type"
249
- );
250
- }
251
- }
252
-
253
- const finalMsg: UserMessageData = {
254
- message,
255
- };
256
- if (image) {
257
- finalMsg.imageB64 = image;
258
- }
259
- return finalMsg;
260
- }
261
-
262
- export function chatToolResultMessageToSessionMessage(
263
- chatMessage: ServerToolCallResult
264
- ): SessionMessage {
265
- return {
266
- message_idx: chatMessage.message_idx,
267
- is_for_llm: true,
268
- content: chatMessage.result,
269
- };
270
- }
271
-
272
- export function chatUserMessageToSessionMessage(
273
- chatMessage: ServerUserMessage
274
- ): SessionMessage {
275
- const userMsg = createUserMessage(
276
- chatMessage.message,
277
- chatMessage.imageB64,
278
- chatMessage.user_uuid
279
- );
280
- assert(userMsg);
281
- return {
282
- message_idx: chatMessage.message_idx,
283
- is_for_llm: true,
284
- sender_uuid: chatMessage.user_uuid,
285
- content: userMsg,
286
- };
287
- }
288
-
289
- export function chatAgentMessageToSessionMessage(
290
- chatMessage: ServerAgentMessage
291
- ): SessionMessage {
292
- return {
293
- message_idx: chatMessage.message_idx,
294
- is_for_llm: true,
295
- content: chatMessage.message,
296
- };
297
- }
298
-
299
- export function chatMessagesToSessionMessages(
300
- chatMessages: ConversationMessage[]
301
- ): SessionMessage[] {
302
- return chatMessages.map((c) => {
303
- switch (c.type) {
304
- case "user_msg":
305
- return chatUserMessageToSessionMessage(c);
306
- case "agent_msg":
307
- return chatAgentMessageToSessionMessage(c);
308
- case "tool_call_result":
309
- return chatToolResultMessageToSessionMessage(c);
310
- default: {
311
- const exhaustive: never = c;
312
- return exhaustive;
313
- }
314
- }
315
- });
316
- }
@@ -1,28 +0,0 @@
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
- }
@@ -1,160 +0,0 @@
1
- import { getLogger } from "@xalia/xmcp/sdk";
2
-
3
- import { AgentEx, IAgentToolProvider, ToolCallResult } from "../../agent/agent";
4
- import { ToolDescriptor } from "../../agent/llm";
5
- import { ImageGenerator } from "../../agent/imageGenerator";
6
- import {
7
- ChatSessionFileManager,
8
- ToolCallResultWithFileRef,
9
- } from "./sessionFileManager";
10
- import { makeParseArgsFn } from "./tools";
11
- import { getSessionFileMimeTypeFromDataUrl } from "../data/dbSessionFileModels";
12
- import { getOpenAIClientParams } from "./openAIRouterLLM";
13
- import { DEFAULT_IMAGE_GEN_MODEL, ImageGenLLM } from "../../agent/imageGenLLM";
14
- import { createSpecializedLLM } from "../../agent/agentUtils";
15
- import { IPlatform } from "../../agent/iplatform";
16
-
17
- const logger = getLogger();
18
-
19
- async function createImageGenerator(
20
- platform: IPlatform
21
- ): Promise<ImageGenerator> {
22
- const imageGenModel =
23
- process.env["GEN_IMAGE_MODEL"] || DEFAULT_IMAGE_GEN_MODEL;
24
-
25
- // Allow the image generator to use a "specialized" or "debug" LLM if
26
- // requested. Otherwise query the router maps for the url and api key and
27
- // instantiate an ImageGenLLM.
28
-
29
- let llm = await createSpecializedLLM(imageGenModel, platform);
30
- if (!llm) {
31
- const { apiKey, baseURL } = getOpenAIClientParams(imageGenModel);
32
- logger.debug(
33
- `[genImageFileTool] model: ${imageGenModel}, url: ${baseURL}"}`
34
- );
35
- llm = new ImageGenLLM(apiKey, baseURL, imageGenModel);
36
- }
37
- return ImageGenerator.init(llm);
38
- }
39
-
40
- // gen_image
41
- //
42
- // Simple tool to generate image output as tool output. The user can then
43
- // decide how/whether to use the image.
44
-
45
- export async function genImageTool(
46
- platform: IPlatform
47
- ): Promise<IAgentToolProvider> {
48
- const GEN_IMAGE_DESC: ToolDescriptor = {
49
- type: "function",
50
- function: {
51
- name: "gen_image",
52
- description: "Generate image",
53
- parameters: {
54
- type: "object",
55
- properties: {
56
- prompt: {
57
- type: "string",
58
- description: "Prompt/instructions for image generator",
59
- },
60
- input_img: {
61
- type: "string",
62
- description: "(Optional) input image data",
63
- },
64
- },
65
- required: ["prompt"],
66
- },
67
- },
68
- } as const;
69
- const imageGenerator = await createImageGenerator(platform);
70
- const getPromptInputImg = makeParseArgsFn(
71
- ["prompt"] as const,
72
- ["input_img"] as const
73
- );
74
- const toolFn = async (_: AgentEx, args: unknown): Promise<ToolCallResult> => {
75
- const { prompt, input_img } = getPromptInputImg(args);
76
- const image = await imageGenerator.generate(prompt, input_img);
77
- return {
78
- response: image,
79
- overwriteArgs: JSON.stringify({ prompt }),
80
- // overwriteResponse: "Image generated",
81
- // // For now, let the UI see the image.
82
- // passOriginalResponseToEventHandler: true,
83
- };
84
- };
85
-
86
- return {
87
- // eslint-disable-next-line @typescript-eslint/require-await
88
- setup: async (agent: AgentEx) => {
89
- agent.addAgentTool(GEN_IMAGE_DESC, toolFn);
90
- },
91
- };
92
- }
93
-
94
- // gen_image_file
95
-
96
- export async function genImageFileTool(
97
- platform: IPlatform,
98
- fileManager: ChatSessionFileManager
99
- ): Promise<IAgentToolProvider> {
100
- const GEN_IMAGE_FILE_DESC: ToolDescriptor = {
101
- type: "function",
102
- function: {
103
- name: "gen_image_file",
104
- description: "Generate image (into session file manager)",
105
- parameters: {
106
- type: "object",
107
- properties: {
108
- prompt: {
109
- type: "string",
110
- description: "Prompt/instructions for image generator",
111
- },
112
- name: {
113
- type: "string",
114
- description: "Name of file to (over)write",
115
- },
116
- summary: {
117
- type: "string",
118
- description: "Summary (for file manager)",
119
- },
120
- input_name: {
121
- type: "string",
122
- description: "(Optional) input image filename",
123
- },
124
- },
125
- required: ["prompt", "name", "summary"],
126
- },
127
- },
128
- } as const;
129
-
130
- const imageGenerator = await createImageGenerator(platform);
131
- const getPromptNameSummary = makeParseArgsFn(
132
- ["prompt", "name", "summary"] as const,
133
- ["input_name"] as const
134
- );
135
- const toolFn = async (
136
- _: AgentEx,
137
- args: unknown
138
- ): Promise<ToolCallResultWithFileRef> => {
139
- const { prompt, name, summary, input_name } = getPromptNameSummary(args);
140
- const input_image = input_name
141
- ? await fileManager.getFileContent(input_name)
142
- : undefined;
143
-
144
- const image = await imageGenerator.generate(prompt, input_image);
145
- const mimeType = getSessionFileMimeTypeFromDataUrl(image);
146
- await fileManager.putFileContent(name, summary, image);
147
- const uri = fileManager.getSessionFileRelativeUrl(name);
148
- return {
149
- response: uri,
150
- _meta: { "xalia/fileUri": uri, "xalia/fileMimeType": mimeType },
151
- };
152
- };
153
-
154
- return {
155
- // eslint-disable-next-line @typescript-eslint/require-await
156
- setup: async (agent: AgentEx) => {
157
- agent.addAgentTool(GEN_IMAGE_FILE_DESC, toolFn);
158
- },
159
- };
160
- }
@@ -1,171 +0,0 @@
1
- import { OpenAI } from "openai";
2
-
3
- import { getLogger } from "@xalia/xmcp/sdk";
4
- import { utils } from "@xalia/xmcp/tool";
5
-
6
- import { OpenAILLMStreaming } from "../../agent/openAILLMStreaming";
7
- import {
8
- ILLM,
9
- MessageParam,
10
- ToolDescriptor,
11
- Completion,
12
- XALIA_APP_HEADER,
13
- } from "../../agent/llm";
14
-
15
- const logger = getLogger();
16
-
17
- // TODO: May be better to allow the calling code to determine this.
18
-
19
- const DEFAULT_PROVIDER_URLS: Record<string, string | undefined> = {
20
- openrouter: "https://openrouter.ai/api/v1",
21
- openai: "https://api.openai.com/v1",
22
- anthropic: "https://api.anthropic.com/v1",
23
- together: "https://api.together.xyz/v1",
24
- };
25
-
26
- const DEFAULT_MODEL_MAP: Record<string, string | undefined> = {
27
- "gpt-4o-mini": "openai",
28
- "gpt-4o": "openai",
29
- "openai/gpt-4o-mini": "openrouter",
30
- "openai/gpt-4o": "openrouter",
31
- "google/gemini-2.5-flash": "openrouter",
32
- "google/gemini-2.5-pro": "openrouter",
33
- "google/gemini-2.5-flash-image-preview": "openrouter",
34
- "anthropic/claude-3.7-sonnet": "openrouter",
35
- "anthropic/claude-sonnet-4": "openrouter",
36
- "anthropic/claude-sonnet-4.5": "openrouter",
37
- "claude-3-7-sonnet-20250219": "anthropic",
38
- "arcee-ai/AFM-4.5B-Preview": "together",
39
- "meta-llama/Llama-3.3-70B-Instruct-Turbo-Free": "together",
40
- };
41
-
42
- type CachedMaps = {
43
- modelToProvider: Record<string, string | undefined>;
44
- providerUrls: Record<string, string | undefined>;
45
- providerApiKeys: Record<string, string | undefined>;
46
- };
47
-
48
- let cached_maps: CachedMaps | undefined = undefined;
49
-
50
- // TODO: Move this to the CLI command args?
51
-
52
- function decodeOrUseDefault(
53
- stringOrFile: string | undefined,
54
- defaultValue: Record<string, string | undefined>
55
- ): Record<string, string | undefined> {
56
- const value =
57
- utils.loadContentOrFileOrUndefined<Record<string, string | undefined>>(
58
- stringOrFile
59
- );
60
- if (value) {
61
- return value;
62
- }
63
- return defaultValue;
64
- }
65
-
66
- function getMaps(): CachedMaps {
67
- // global cached_maps;
68
- if (!cached_maps) {
69
- const providerApiKeys = utils.loadContentOrFileOrUndefined<
70
- Record<string, string | undefined>
71
- >(process.env.LLM_API_KEY_MAP);
72
- if (!providerApiKeys) {
73
- throw new Error("LLM_API_KEY_MAP not not given");
74
- }
75
- const providerUrls = decodeOrUseDefault(
76
- process.env.LLM_PROVIDER_URLS,
77
- DEFAULT_PROVIDER_URLS
78
- );
79
- const modelToProvider = decodeOrUseDefault(
80
- process.env.LLM_MODEL_MAP,
81
- DEFAULT_MODEL_MAP
82
- );
83
- cached_maps = {
84
- modelToProvider,
85
- providerUrls,
86
- providerApiKeys,
87
- };
88
- }
89
-
90
- return cached_maps;
91
- }
92
-
93
- export function getOpenAIClientParams(model: string): {
94
- apiKey: string | undefined;
95
- baseURL: string;
96
- } {
97
- const maps = getMaps();
98
- const provider = maps.modelToProvider[model];
99
- if (!provider) {
100
- throw new Error(`no provider registered for model ${model}`);
101
- }
102
- const baseURL = maps.providerUrls[provider];
103
- if (!baseURL) {
104
- throw new Error(`no provider url for provider ${provider}`);
105
- }
106
- const apiKey = maps.providerApiKeys[provider];
107
- if (!apiKey) {
108
- logger.warn(`No apiKey registered for provider ${provider}`);
109
- }
110
-
111
- return { apiKey, baseURL };
112
- }
113
-
114
- export function getOpenAIClient(model: string): OpenAI {
115
- const { apiKey, baseURL } = getOpenAIClientParams(model);
116
- return new OpenAI({
117
- apiKey,
118
- baseURL,
119
- dangerouslyAllowBrowser: true,
120
- defaultHeaders: XALIA_APP_HEADER,
121
- });
122
- }
123
-
124
- /**
125
- * An ILLM implementation that accepts maps:
126
- *
127
- * model-name => prover-name
128
- * provider-name => url
129
- * provider-name => api-key
130
- *
131
- * Requests are dynamically routed to the appropriate provider based on the
132
- * currently active model.
133
- */
134
- export class OpenAIRouterLLM implements ILLM {
135
- private model: string;
136
- private openai: OpenAI;
137
-
138
- constructor(model: string) {
139
- this.model = model;
140
- this.openai = getOpenAIClient(model);
141
- }
142
-
143
- public setModel(model: string) {
144
- this.model = model;
145
- this.openai = getOpenAIClient(model);
146
- }
147
-
148
- public getModel(): string {
149
- return this.model;
150
- }
151
-
152
- public getUrl(): string {
153
- return this.openai.baseURL;
154
- }
155
-
156
- public async getConversationResponse(
157
- messages: MessageParam[],
158
- tools?: ToolDescriptor[],
159
- onMessage?: (msg: string, end: boolean) => Promise<void>,
160
- onReasoning?: (reasoning: string) => Promise<void>
161
- ): Promise<Completion> {
162
- return OpenAILLMStreaming.makeRequest(
163
- this.openai,
164
- this.model,
165
- messages,
166
- tools,
167
- onMessage,
168
- onReasoning
169
- );
170
- }
171
- }