@mcp-use/agent 0.0.0-bootstrap.0 → 2.0.0-beta.1

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 (131) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/adapters/base.d.ts +112 -0
  3. package/dist/adapters/base.d.ts.map +1 -0
  4. package/dist/adapters/index.d.ts +3 -0
  5. package/dist/adapters/index.d.ts.map +1 -0
  6. package/dist/adapters/langchain_adapter.d.ts +26 -0
  7. package/dist/adapters/langchain_adapter.d.ts.map +1 -0
  8. package/dist/adapters/native_adapter.d.ts +27 -0
  9. package/dist/adapters/native_adapter.d.ts.map +1 -0
  10. package/dist/agents/agent_options.d.ts +38 -0
  11. package/dist/agents/agent_options.d.ts.map +1 -0
  12. package/dist/agents/base.d.ts +27 -0
  13. package/dist/agents/base.d.ts.map +1 -0
  14. package/dist/agents/display.d.ts +6 -0
  15. package/dist/agents/display.d.ts.map +1 -0
  16. package/dist/agents/index.d.ts +9 -0
  17. package/dist/agents/index.d.ts.map +1 -0
  18. package/dist/agents/mcp_agent.d.ts +90 -0
  19. package/dist/agents/mcp_agent.d.ts.map +1 -0
  20. package/dist/agents/mcp_agent_langchain.d.ts +283 -0
  21. package/dist/agents/mcp_agent_langchain.d.ts.map +1 -0
  22. package/dist/agents/normalize_run_options.d.ts +12 -0
  23. package/dist/agents/normalize_run_options.d.ts.map +1 -0
  24. package/dist/agents/prompts/index.d.ts +10 -0
  25. package/dist/agents/prompts/index.d.ts.map +1 -0
  26. package/dist/agents/prompts/system_prompt_builder.d.ts +4 -0
  27. package/dist/agents/prompts/system_prompt_builder.d.ts.map +1 -0
  28. package/dist/agents/prompts/templates.d.ts +3 -0
  29. package/dist/agents/prompts/templates.d.ts.map +1 -0
  30. package/dist/agents/remote.d.ts +48 -0
  31. package/dist/agents/remote.d.ts.map +1 -0
  32. package/dist/agents/run_options.d.ts +13 -0
  33. package/dist/agents/run_options.d.ts.map +1 -0
  34. package/dist/agents/types.d.ts +79 -0
  35. package/dist/agents/types.d.ts.map +1 -0
  36. package/dist/agents/utils/ai_sdk.d.ts +22 -0
  37. package/dist/agents/utils/ai_sdk.d.ts.map +1 -0
  38. package/dist/agents/utils/index.d.ts +3 -0
  39. package/dist/agents/utils/index.d.ts.map +1 -0
  40. package/dist/agents/utils/llm_provider.d.ts +53 -0
  41. package/dist/agents/utils/llm_provider.d.ts.map +1 -0
  42. package/dist/browser-agent.cjs +3272 -0
  43. package/dist/browser-agent.cjs.map +1 -0
  44. package/dist/browser-agent.d.ts +9 -0
  45. package/dist/browser-agent.d.ts.map +1 -0
  46. package/dist/browser-agent.js +3227 -0
  47. package/dist/browser-agent.js.map +1 -0
  48. package/dist/index.cjs +3299 -0
  49. package/dist/index.cjs.map +1 -0
  50. package/dist/index.d.ts +14 -0
  51. package/dist/index.d.ts.map +1 -0
  52. package/dist/index.js +3248 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/langchain.cjs +46340 -0
  55. package/dist/langchain.cjs.map +1 -0
  56. package/dist/langchain.d.ts +11 -0
  57. package/dist/langchain.d.ts.map +1 -0
  58. package/dist/langchain.js +46328 -0
  59. package/dist/langchain.js.map +1 -0
  60. package/dist/llm/chat.d.ts +8 -0
  61. package/dist/llm/chat.d.ts.map +1 -0
  62. package/dist/llm/driver.d.ts +40 -0
  63. package/dist/llm/driver.d.ts.map +1 -0
  64. package/dist/llm/messageFormat.d.ts +48 -0
  65. package/dist/llm/messageFormat.d.ts.map +1 -0
  66. package/dist/llm/native_runner.d.ts +23 -0
  67. package/dist/llm/native_runner.d.ts.map +1 -0
  68. package/dist/llm/ndjson.d.ts +5 -0
  69. package/dist/llm/ndjson.d.ts.map +1 -0
  70. package/dist/llm/provider_config.d.ts +13 -0
  71. package/dist/llm/provider_config.d.ts.map +1 -0
  72. package/dist/llm/providers/anthropic.d.ts +19 -0
  73. package/dist/llm/providers/anthropic.d.ts.map +1 -0
  74. package/dist/llm/providers/google.d.ts +19 -0
  75. package/dist/llm/providers/google.d.ts.map +1 -0
  76. package/dist/llm/providers/index.d.ts +19 -0
  77. package/dist/llm/providers/index.d.ts.map +1 -0
  78. package/dist/llm/providers/ollama/index.d.ts +18 -0
  79. package/dist/llm/providers/ollama/index.d.ts.map +1 -0
  80. package/dist/llm/providers/ollama/utils.d.ts +7 -0
  81. package/dist/llm/providers/ollama/utils.d.ts.map +1 -0
  82. package/dist/llm/providers/openai-chat-completions.d.ts +25 -0
  83. package/dist/llm/providers/openai-chat-completions.d.ts.map +1 -0
  84. package/dist/llm/providers/openai-responses-driver.d.ts +22 -0
  85. package/dist/llm/providers/openai-responses-driver.d.ts.map +1 -0
  86. package/dist/llm/providers/openai-responses.d.ts +37 -0
  87. package/dist/llm/providers/openai-responses.d.ts.map +1 -0
  88. package/dist/llm/providers/openai-shared.d.ts +6 -0
  89. package/dist/llm/providers/openai-shared.d.ts.map +1 -0
  90. package/dist/llm/schemaUtils.d.ts +2 -0
  91. package/dist/llm/schemaUtils.d.ts.map +1 -0
  92. package/dist/llm/sse.d.ts +15 -0
  93. package/dist/llm/sse.d.ts.map +1 -0
  94. package/dist/llm/toolLoop.d.ts +41 -0
  95. package/dist/llm/toolLoop.d.ts.map +1 -0
  96. package/dist/llm/toolResultParts.d.ts +28 -0
  97. package/dist/llm/toolResultParts.d.ts.map +1 -0
  98. package/dist/llm/types.d.ts +116 -0
  99. package/dist/llm/types.d.ts.map +1 -0
  100. package/dist/llm/usage.d.ts +4 -0
  101. package/dist/llm/usage.d.ts.map +1 -0
  102. package/dist/managers/server_manager.d.ts +19 -0
  103. package/dist/managers/server_manager.d.ts.map +1 -0
  104. package/dist/managers/tools/acquire_active_mcp_server.d.ts +13 -0
  105. package/dist/managers/tools/acquire_active_mcp_server.d.ts.map +1 -0
  106. package/dist/managers/tools/add_server_from_config.d.ts +15 -0
  107. package/dist/managers/tools/add_server_from_config.d.ts.map +1 -0
  108. package/dist/managers/tools/base.d.ts +19 -0
  109. package/dist/managers/tools/base.d.ts.map +1 -0
  110. package/dist/managers/tools/connect_mcp_server.d.ts +18 -0
  111. package/dist/managers/tools/connect_mcp_server.d.ts.map +1 -0
  112. package/dist/managers/tools/index.d.ts +6 -0
  113. package/dist/managers/tools/index.d.ts.map +1 -0
  114. package/dist/managers/tools/list_mcp_servers.d.ts +13 -0
  115. package/dist/managers/tools/list_mcp_servers.d.ts.map +1 -0
  116. package/dist/managers/tools/release_mcp_server_connection.d.ts +13 -0
  117. package/dist/managers/tools/release_mcp_server_connection.d.ts.map +1 -0
  118. package/dist/managers/types.d.ts +14 -0
  119. package/dist/managers/types.d.ts.map +1 -0
  120. package/dist/observability/index.d.ts +9 -0
  121. package/dist/observability/index.d.ts.map +1 -0
  122. package/dist/observability/langfuse.d.ts +26 -0
  123. package/dist/observability/langfuse.d.ts.map +1 -0
  124. package/dist/observability/manager.d.ts +89 -0
  125. package/dist/observability/manager.d.ts.map +1 -0
  126. package/dist/telemetry/utils.d.ts +4 -0
  127. package/dist/telemetry/utils.d.ts.map +1 -0
  128. package/dist/version.d.ts +3 -0
  129. package/dist/version.d.ts.map +1 -0
  130. package/package.json +109 -8
  131. package/README.md +0 -5
package/dist/index.js ADDED
@@ -0,0 +1,3248 @@
1
+ // src/agents/mcp_agent.ts
2
+ import { logger as logger5 } from "@mcp-use/client";
3
+
4
+ // src/adapters/native_adapter.ts
5
+ import { logger as logger2 } from "@mcp-use/client";
6
+
7
+ // src/adapters/base.ts
8
+ import { logger } from "@mcp-use/client";
9
+ var BaseAdapter = class {
10
+ /**
11
+ * List of tool names that should not be available.
12
+ */
13
+ disallowedTools;
14
+ /**
15
+ * Internal cache that maps a connector instance to the list of tools
16
+ * generated for it.
17
+ */
18
+ connectorToolMap = /* @__PURE__ */ new Map();
19
+ constructor(disallowedTools) {
20
+ this.disallowedTools = disallowedTools ?? [];
21
+ }
22
+ /**
23
+ * Create tools from an MCPClient instance.
24
+ *
25
+ * This is the recommended way to create tools from an MCPClient, as it handles
26
+ * session creation and connector extraction automatically.
27
+ *
28
+ * @param client The MCPClient to extract tools from.
29
+ * @param disallowedTools Optional list of tool names to exclude.
30
+ * @returns A promise that resolves with a list of converted tools.
31
+ */
32
+ static async createTools(client, disallowedTools) {
33
+ const adapter = new this(disallowedTools);
34
+ if (!client.activeSessions || Object.keys(client.activeSessions).length === 0) {
35
+ logger.debug("No active sessions found, creating new ones...");
36
+ await client.createAllSessions();
37
+ }
38
+ const sessions = client.getAllActiveSessions();
39
+ const connectors = Object.values(sessions).map(
40
+ (session) => session.connector
41
+ );
42
+ return adapter.createToolsFromConnectors(connectors);
43
+ }
44
+ /**
45
+ * Dynamically load tools for a specific connector.
46
+ *
47
+ * @param connector The connector to load tools for.
48
+ * @returns The list of tools that were loaded in the target framework's format.
49
+ */
50
+ async loadToolsForConnector(connector) {
51
+ if (this.connectorToolMap.has(connector)) {
52
+ const cached = this.connectorToolMap.get(connector);
53
+ logger.debug(`Returning ${cached.length} existing tools for connector`);
54
+ return cached;
55
+ }
56
+ const connectorTools = [];
57
+ const success = await this.ensureConnectorInitialized(connector);
58
+ if (!success) {
59
+ return [];
60
+ }
61
+ for (const tool of connector.tools) {
62
+ const converted = this.convertTool(tool, connector);
63
+ if (converted) {
64
+ connectorTools.push(converted);
65
+ }
66
+ }
67
+ this.connectorToolMap.set(connector, connectorTools);
68
+ logger.debug(
69
+ `Loaded ${connectorTools.length} new tools for connector: ${connectorTools.map((t) => t?.name ?? String(t)).join(", ")}`
70
+ );
71
+ return connectorTools;
72
+ }
73
+ /**
74
+ * Create tools from MCP tools in all provided connectors.
75
+ *
76
+ * @param connectors List of MCP connectors to create tools from.
77
+ * @returns A promise that resolves with all converted tools.
78
+ */
79
+ async createToolsFromConnectors(connectors) {
80
+ const tools = [];
81
+ for (const connector of connectors) {
82
+ const connectorTools = await this.loadToolsForConnector(connector);
83
+ tools.push(...connectorTools);
84
+ }
85
+ logger.debug(`Available tools: ${tools.length}`);
86
+ return tools;
87
+ }
88
+ /**
89
+ * Dynamically load resources for a specific connector.
90
+ *
91
+ * @param connector The connector to load resources for.
92
+ * @returns The list of resources that were loaded in the target framework's format.
93
+ */
94
+ async loadResourcesForConnector(connector) {
95
+ const connectorResources = [];
96
+ const success = await this.ensureConnectorInitialized(connector);
97
+ if (!success) {
98
+ return [];
99
+ }
100
+ try {
101
+ const resourcesResult = await connector.listAllResources();
102
+ const resources = resourcesResult?.resources || [];
103
+ if (this.convertResource) {
104
+ for (const resource of resources) {
105
+ const converted = this.convertResource(resource, connector);
106
+ if (converted) {
107
+ connectorResources.push(converted);
108
+ }
109
+ }
110
+ }
111
+ logger.debug(
112
+ `Loaded ${connectorResources.length} new resources for connector: ${connectorResources.map((r) => r?.name ?? String(r)).join(", ")}`
113
+ );
114
+ } catch (err) {
115
+ logger.warn(`Error loading resources for connector: ${err}`);
116
+ }
117
+ return connectorResources;
118
+ }
119
+ /**
120
+ * Dynamically load prompts for a specific connector.
121
+ *
122
+ * @param connector The connector to load prompts for.
123
+ * @returns The list of prompts that were loaded in the target framework's format.
124
+ */
125
+ async loadPromptsForConnector(connector) {
126
+ const connectorPrompts = [];
127
+ const success = await this.ensureConnectorInitialized(connector);
128
+ if (!success) {
129
+ return [];
130
+ }
131
+ try {
132
+ const promptsResult = await connector.listPrompts();
133
+ const prompts = promptsResult?.prompts || [];
134
+ if (this.convertPrompt) {
135
+ for (const prompt of prompts) {
136
+ const converted = this.convertPrompt(prompt, connector);
137
+ if (converted) {
138
+ connectorPrompts.push(converted);
139
+ }
140
+ }
141
+ }
142
+ logger.debug(
143
+ `Loaded ${connectorPrompts.length} new prompts for connector: ${connectorPrompts.map((p) => p?.name ?? String(p)).join(", ")}`
144
+ );
145
+ } catch (err) {
146
+ logger.warn(`Error loading prompts for connector: ${err}`);
147
+ }
148
+ return connectorPrompts;
149
+ }
150
+ /**
151
+ * Create resources from MCP resources in all provided connectors.
152
+ *
153
+ * @param connectors List of MCP connectors to create resources from.
154
+ * @returns A promise that resolves with all converted resources.
155
+ */
156
+ async createResourcesFromConnectors(connectors) {
157
+ const resources = [];
158
+ for (const connector of connectors) {
159
+ const connectorResources = await this.loadResourcesForConnector(connector);
160
+ resources.push(...connectorResources);
161
+ }
162
+ logger.debug(`Available resources: ${resources.length}`);
163
+ return resources;
164
+ }
165
+ /**
166
+ * Create prompts from MCP prompts in all provided connectors.
167
+ *
168
+ * @param connectors List of MCP connectors to create prompts from.
169
+ * @returns A promise that resolves with all converted prompts.
170
+ */
171
+ async createPromptsFromConnectors(connectors) {
172
+ const prompts = [];
173
+ for (const connector of connectors) {
174
+ const connectorPrompts = await this.loadPromptsForConnector(connector);
175
+ prompts.push(...connectorPrompts);
176
+ }
177
+ logger.debug(`Available prompts: ${prompts.length}`);
178
+ return prompts;
179
+ }
180
+ /**
181
+ * Check if a connector is initialized and has tools.
182
+ *
183
+ * @param connector The connector to check.
184
+ * @returns True if the connector is initialized and has tools, false otherwise.
185
+ */
186
+ checkConnectorInitialized(connector) {
187
+ return Boolean(connector.tools && connector.tools.length);
188
+ }
189
+ /**
190
+ * Ensure a connector is initialized.
191
+ *
192
+ * @param connector The connector to initialize.
193
+ * @returns True if initialization succeeded, false otherwise.
194
+ */
195
+ async ensureConnectorInitialized(connector) {
196
+ if (!this.checkConnectorInitialized(connector)) {
197
+ logger.debug("Connector doesn't have tools, initializing it");
198
+ try {
199
+ await connector.initialize();
200
+ return true;
201
+ } catch (err) {
202
+ logger.error(`Error initializing connector: ${err}`);
203
+ return false;
204
+ }
205
+ }
206
+ return true;
207
+ }
208
+ };
209
+
210
+ // src/adapters/native_adapter.ts
211
+ function sanitizeToolName(name) {
212
+ return name.replace(/[^A-Za-z0-9_]+/g, "_").toLowerCase().replace(/^_+|_+$/g, "");
213
+ }
214
+ var NativeAdapter = class extends BaseAdapter {
215
+ usedToolNames = /* @__PURE__ */ new Set();
216
+ handlers = /* @__PURE__ */ new Map();
217
+ constructor(disallowedTools = []) {
218
+ super(disallowedTools);
219
+ }
220
+ async createToolsFromConnectors(connectors) {
221
+ this.usedToolNames.clear();
222
+ this.handlers.clear();
223
+ return super.createToolsFromConnectors(connectors);
224
+ }
225
+ createCallTool() {
226
+ const handlers = this.handlers;
227
+ return async (name, args) => {
228
+ const handler = handlers.get(name);
229
+ if (!handler) {
230
+ throw new Error(`Unknown tool: ${name}`);
231
+ }
232
+ try {
233
+ if (handler.kind === "tool") {
234
+ return await handler.connector.callTool(handler.mcpName, args);
235
+ }
236
+ if (handler.kind === "resource") {
237
+ const uri = handler.resourceUri ?? handler.mcpName;
238
+ return await handler.connector.readResource(uri);
239
+ }
240
+ return await handler.connector.getPrompt(handler.mcpName, args);
241
+ } catch (err) {
242
+ logger2.error(`Error executing native MCP tool ${name}: ${err}`);
243
+ throw err;
244
+ }
245
+ };
246
+ }
247
+ toProviderTools(entries) {
248
+ return entries.map(({ name, description, inputSchema }) => ({
249
+ name,
250
+ description,
251
+ inputSchema
252
+ }));
253
+ }
254
+ reserveName(name, kind) {
255
+ if (!this.usedToolNames.has(name)) {
256
+ this.usedToolNames.add(name);
257
+ return name;
258
+ }
259
+ if (kind) {
260
+ const prefixed = `${kind}_${name}`;
261
+ if (!this.usedToolNames.has(prefixed)) {
262
+ this.usedToolNames.add(prefixed);
263
+ return prefixed;
264
+ }
265
+ let i2 = 2;
266
+ while (this.usedToolNames.has(`${prefixed}_${i2}`)) i2++;
267
+ const fallback2 = `${prefixed}_${i2}`;
268
+ this.usedToolNames.add(fallback2);
269
+ return fallback2;
270
+ }
271
+ let i = 2;
272
+ while (this.usedToolNames.has(`${name}_${i}`)) i++;
273
+ const fallback = `${name}_${i}`;
274
+ this.usedToolNames.add(fallback);
275
+ return fallback;
276
+ }
277
+ register(entry, handler) {
278
+ this.handlers.set(entry.name, handler);
279
+ return entry;
280
+ }
281
+ convertTool(mcpTool, connector) {
282
+ if (this.disallowedTools.includes(mcpTool.name)) return null;
283
+ const toolName = this.reserveName(mcpTool.name ?? "tool");
284
+ const entry = {
285
+ name: toolName,
286
+ dispatchKey: toolName,
287
+ description: mcpTool.description ?? "",
288
+ inputSchema: mcpTool.inputSchema ?? {
289
+ type: "object",
290
+ properties: {}
291
+ }
292
+ };
293
+ return this.register(entry, {
294
+ connector,
295
+ kind: "tool",
296
+ mcpName: mcpTool.name
297
+ });
298
+ }
299
+ convertResource(mcpResource, connector) {
300
+ const resourceBaseName = sanitizeToolName(mcpResource.name || mcpResource.uri) || "resource";
301
+ const resourceName = this.reserveName(resourceBaseName, "resource");
302
+ const entry = {
303
+ name: resourceName,
304
+ dispatchKey: resourceName,
305
+ description: mcpResource.description || `Return the content of the resource located at URI ${mcpResource.uri}.`,
306
+ inputSchema: { type: "object", properties: {} }
307
+ };
308
+ return this.register(entry, {
309
+ connector,
310
+ kind: "resource",
311
+ mcpName: mcpResource.uri,
312
+ resourceUri: mcpResource.uri
313
+ });
314
+ }
315
+ convertPrompt(mcpPrompt, connector) {
316
+ const properties = {};
317
+ const required = [];
318
+ if (mcpPrompt.arguments?.length) {
319
+ for (const arg of mcpPrompt.arguments) {
320
+ properties[arg.name] = { type: "string", description: arg.description };
321
+ if (arg.required !== false) required.push(arg.name);
322
+ }
323
+ }
324
+ const promptBaseName = sanitizeToolName(mcpPrompt.name || "prompt") || "prompt";
325
+ const promptName = this.reserveName(promptBaseName, "prompt");
326
+ const entry = {
327
+ name: promptName,
328
+ dispatchKey: promptName,
329
+ description: mcpPrompt.description || "",
330
+ inputSchema: {
331
+ type: "object",
332
+ properties,
333
+ ...required.length > 0 ? { required } : {}
334
+ }
335
+ };
336
+ return this.register(entry, {
337
+ connector,
338
+ kind: "prompt",
339
+ mcpName: mcpPrompt.name
340
+ });
341
+ }
342
+ };
343
+
344
+ // src/llm/toolResultParts.ts
345
+ function makeText(text) {
346
+ return { type: "text", text };
347
+ }
348
+ function makeImage(data, mimeType) {
349
+ return {
350
+ type: "image",
351
+ url: `data:${mimeType};base64,${data}`,
352
+ mimeType,
353
+ data
354
+ };
355
+ }
356
+ function isMcpResultShape(value) {
357
+ if (!value || typeof value !== "object") return false;
358
+ const v = value;
359
+ if (Array.isArray(v.content)) return true;
360
+ return "structuredContent" in v;
361
+ }
362
+ function isToolResultError(result) {
363
+ return typeof result === "object" && result !== null && result.isError === true;
364
+ }
365
+ function blockToPart(block) {
366
+ if (!block || typeof block !== "object") return null;
367
+ switch (block.type) {
368
+ case "text": {
369
+ const text = block.text;
370
+ return typeof text === "string" && text.length > 0 ? makeText(text) : null;
371
+ }
372
+ case "image": {
373
+ const b = block;
374
+ if (typeof b.data !== "string" || !b.data) return null;
375
+ const mime = typeof b.mimeType === "string" && b.mimeType ? b.mimeType : "image/png";
376
+ return makeImage(b.data, mime);
377
+ }
378
+ case "audio": {
379
+ const b = block;
380
+ const mime = typeof b.mimeType === "string" && b.mimeType ? b.mimeType : "audio/*";
381
+ const bytes = typeof b.data === "string" ? b.data.length : 0;
382
+ return makeText(`[audio: ${mime}, base64 omitted (${bytes} chars)]`);
383
+ }
384
+ case "resource": {
385
+ const r = block.resource ?? {};
386
+ if (typeof r.text === "string" && r.text.length > 0) {
387
+ return makeText(r.text);
388
+ }
389
+ if (typeof r.blob === "string" && typeof r.mimeType === "string" && r.mimeType.startsWith("image/")) {
390
+ return makeImage(r.blob, r.mimeType);
391
+ }
392
+ const uri = typeof r.uri === "string" ? r.uri : "<unknown>";
393
+ const mime = typeof r.mimeType === "string" ? r.mimeType : "unknown";
394
+ return makeText(`[resource: ${uri} (${mime})]`);
395
+ }
396
+ case "resource_link": {
397
+ const b = block;
398
+ const uri = typeof b.uri === "string" ? b.uri : "<unknown>";
399
+ const name = typeof b.name === "string" ? ` "${b.name}"` : "";
400
+ return makeText(`[resource_link${name}: ${uri}]`);
401
+ }
402
+ default: {
403
+ return makeText(
404
+ `[unsupported tool content block: ${String(block.type)}]`
405
+ );
406
+ }
407
+ }
408
+ }
409
+ function stripMeta(value) {
410
+ if (value && typeof value === "object" && !Array.isArray(value)) {
411
+ const { _meta: _ignored, ...rest } = value;
412
+ return rest;
413
+ }
414
+ return value;
415
+ }
416
+ function extractToolResultParts(result) {
417
+ const stripped = stripMeta(result);
418
+ if (typeof stripped === "string") {
419
+ return stripped.length > 0 ? [makeText(stripped)] : [];
420
+ }
421
+ if (isMcpResultShape(stripped)) {
422
+ const r = stripped;
423
+ const parts = [];
424
+ if (Array.isArray(r.content)) {
425
+ for (const block of r.content) {
426
+ const p = blockToPart(block);
427
+ if (p) parts.push(p);
428
+ }
429
+ }
430
+ if (r.structuredContent !== void 0) {
431
+ try {
432
+ parts.push(
433
+ makeText(`structuredContent: ${JSON.stringify(r.structuredContent)}`)
434
+ );
435
+ } catch {
436
+ }
437
+ }
438
+ if (r.isError) {
439
+ parts.unshift(makeText("[tool reported isError=true]"));
440
+ }
441
+ return parts;
442
+ }
443
+ try {
444
+ return [makeText(JSON.stringify(stripped))];
445
+ } catch {
446
+ return [makeText(String(stripped))];
447
+ }
448
+ }
449
+ function collapseToString(parts) {
450
+ if (parts.length === 0) return "";
451
+ if (parts.every((p) => p.type === "text")) {
452
+ return parts.map((p) => p.text).join("\n");
453
+ }
454
+ return null;
455
+ }
456
+ function toolResultToContent(result) {
457
+ const parts = extractToolResultParts(result);
458
+ const collapsed = collapseToString(parts);
459
+ return collapsed !== null ? collapsed : parts;
460
+ }
461
+ function partitionToolContent(content) {
462
+ if (typeof content === "string") {
463
+ return { text: content, imageParts: [], isString: true };
464
+ }
465
+ const texts = [];
466
+ const imageParts = [];
467
+ for (const p of content) {
468
+ if (p.type === "text") {
469
+ if (p.text) texts.push(p.text);
470
+ } else if (p.type === "image") {
471
+ imageParts.push(p);
472
+ }
473
+ }
474
+ return { text: texts.join("\n"), imageParts, isString: false };
475
+ }
476
+ function toolImageFollowupHeader(toolName, count) {
477
+ return `(Tool "${toolName ?? "<tool>"}" returned the following image${count === 1 ? "" : "s"}:)`;
478
+ }
479
+
480
+ // src/llm/messageFormat.ts
481
+ function extractText(m) {
482
+ const raw = typeof m.content === "string" ? m.content : Array.isArray(m.content) ? m.content.map((x) => x?.text ?? "").join("\n") : JSON.stringify(m.content ?? "");
483
+ if (raw.trim()) return raw.trim();
484
+ if (m.parts?.length) {
485
+ return m.parts.filter((p) => p.type === "text" && p.text).map((p) => p.text).join("").trim();
486
+ }
487
+ return "";
488
+ }
489
+ function convertMessagesToProvider(messages) {
490
+ const out = [];
491
+ messages.forEach((m, mi) => {
492
+ if (m.role === "user") {
493
+ const text2 = extractText(m) || "[no content]";
494
+ if (m.attachments?.length) {
495
+ const parts = [{ type: "text", text: text2 }];
496
+ for (const a of m.attachments) {
497
+ if (a.type === "image") {
498
+ parts.push({
499
+ type: "image",
500
+ url: `data:${a.mimeType};base64,${a.data}`,
501
+ mimeType: a.mimeType,
502
+ data: a.data
503
+ });
504
+ }
505
+ }
506
+ out.push({ role: "user", content: parts });
507
+ } else {
508
+ out.push({ role: "user", content: text2 });
509
+ }
510
+ return;
511
+ }
512
+ const toolParts = (m.parts ?? []).filter(
513
+ (p) => p.type === "tool-invocation" && p.toolInvocation && p.toolInvocation.result !== void 0
514
+ );
515
+ if (toolParts.length === 0) {
516
+ const text2 = extractText(m) || "[no content]";
517
+ out.push({ role: "assistant", content: text2 });
518
+ return;
519
+ }
520
+ const text = extractText(m);
521
+ const toolCalls = toolParts.map((p, i) => ({
522
+ id: `call_${mi}_${i}_${p.toolInvocation.toolName}`,
523
+ name: p.toolInvocation.toolName,
524
+ args: p.toolInvocation.args
525
+ }));
526
+ out.push({
527
+ role: "assistant",
528
+ content: text,
529
+ toolCalls
530
+ });
531
+ toolParts.forEach((p, i) => {
532
+ const result = p.toolInvocation.result;
533
+ out.push({
534
+ role: "tool",
535
+ content: toolResultToContent(result),
536
+ toolCallId: `call_${mi}_${i}_${p.toolInvocation.toolName}`,
537
+ toolName: p.toolInvocation.toolName,
538
+ toolResult: result,
539
+ toolIsError: isToolResultError(result)
540
+ });
541
+ });
542
+ });
543
+ return out;
544
+ }
545
+ function extractSystem(messages) {
546
+ const sys = [];
547
+ const rest = [];
548
+ for (const m of messages) {
549
+ if (m.role === "system") {
550
+ if (typeof m.content === "string") sys.push(m.content);
551
+ else if (Array.isArray(m.content)) {
552
+ for (const p of m.content) if (p.type === "text") sys.push(p.text);
553
+ }
554
+ } else {
555
+ rest.push(m);
556
+ }
557
+ }
558
+ return {
559
+ system: sys.length > 0 ? sys.join("\n\n") : void 0,
560
+ rest
561
+ };
562
+ }
563
+ function parseDataUrl(url) {
564
+ const m = url.match(/^data:([^;,]+);base64,(.+)$/);
565
+ if (!m) return null;
566
+ return { mimeType: m[1], data: m[2] };
567
+ }
568
+
569
+ // src/llm/sse.ts
570
+ async function* parseSSE(body, signal) {
571
+ const reader = body.getReader();
572
+ const decoder = new TextDecoder("utf-8");
573
+ let buffer = "";
574
+ try {
575
+ while (true) {
576
+ if (signal?.aborted) return;
577
+ const { value, done } = await reader.read();
578
+ if (done) break;
579
+ buffer += decoder.decode(value, { stream: true });
580
+ let sep;
581
+ while ((sep = indexOfEventSeparator(buffer)) !== -1) {
582
+ const raw = buffer.slice(0, sep);
583
+ buffer = buffer.slice(sep).replace(/^(\r\n\r\n|\n\n|\r\r)/, "");
584
+ const parsed = parseSseBlock(raw);
585
+ if (parsed) yield parsed;
586
+ }
587
+ }
588
+ if (buffer.trim()) {
589
+ const parsed = parseSseBlock(buffer);
590
+ if (parsed) yield parsed;
591
+ }
592
+ } finally {
593
+ try {
594
+ reader.releaseLock();
595
+ } catch {
596
+ }
597
+ }
598
+ }
599
+ function indexOfEventSeparator(s) {
600
+ const a = s.indexOf("\n\n");
601
+ const b = s.indexOf("\r\n\r\n");
602
+ if (a === -1) return b;
603
+ if (b === -1) return a;
604
+ return Math.min(a, b);
605
+ }
606
+ function parseSseBlock(raw) {
607
+ let event;
608
+ const dataLines = [];
609
+ for (const line of raw.split(/\r?\n/)) {
610
+ if (!line || line.startsWith(":")) continue;
611
+ const idx = line.indexOf(":");
612
+ const field = idx === -1 ? line : line.slice(0, idx);
613
+ let value = idx === -1 ? "" : line.slice(idx + 1);
614
+ if (value.startsWith(" ")) value = value.slice(1);
615
+ if (field === "event") event = value;
616
+ else if (field === "data") dataLines.push(value);
617
+ }
618
+ if (dataLines.length === 0) return null;
619
+ return { event, data: dataLines.join("\n") };
620
+ }
621
+
622
+ // src/llm/usage.ts
623
+ function numberAt(value, ...keys) {
624
+ for (const key of keys) {
625
+ const candidate = value[key];
626
+ if (typeof candidate === "number" && Number.isFinite(candidate)) {
627
+ return candidate;
628
+ }
629
+ }
630
+ return void 0;
631
+ }
632
+ function tokenUsageFromRecord(raw) {
633
+ if (!raw || typeof raw !== "object") return void 0;
634
+ const usage = raw;
635
+ const inputTokens = numberAt(
636
+ usage,
637
+ "inputTokens",
638
+ "input_tokens",
639
+ "prompt_tokens",
640
+ "promptTokenCount",
641
+ "prompt_eval_count"
642
+ );
643
+ const outputTokens = numberAt(
644
+ usage,
645
+ "outputTokens",
646
+ "output_tokens",
647
+ "completion_tokens",
648
+ "candidatesTokenCount",
649
+ "eval_count"
650
+ );
651
+ const totalTokens = numberAt(usage, "totalTokens", "total_tokens", "totalTokenCount") ?? (inputTokens !== void 0 && outputTokens !== void 0 ? inputTokens + outputTokens : void 0);
652
+ const inputDetails = usage.input_tokens_details && typeof usage.input_tokens_details === "object" ? usage.input_tokens_details : void 0;
653
+ const outputDetails = usage.output_tokens_details && typeof usage.output_tokens_details === "object" ? usage.output_tokens_details : void 0;
654
+ const cachedInputTokens = numberAt(usage, "cachedInputTokens", "cache_read_input_tokens") ?? (inputDetails ? numberAt(inputDetails, "cached_tokens") : void 0);
655
+ const reasoningTokens = numberAt(usage, "reasoningTokens", "thoughtsTokenCount") ?? (outputDetails ? numberAt(outputDetails, "reasoning_tokens") : void 0);
656
+ if (inputTokens === void 0 && outputTokens === void 0 && totalTokens === void 0 && cachedInputTokens === void 0 && reasoningTokens === void 0) {
657
+ return void 0;
658
+ }
659
+ return {
660
+ inputTokens,
661
+ outputTokens,
662
+ totalTokens,
663
+ cachedInputTokens,
664
+ reasoningTokens
665
+ };
666
+ }
667
+
668
+ // src/llm/providers/anthropic.ts
669
+ var DEFAULT_ENDPOINT = "https://api.anthropic.com/v1/messages";
670
+ var ANTHROPIC_VERSION = "2023-06-01";
671
+ var DEFAULT_MAX_TOKENS = 4096;
672
+ function buildImageBlock(p) {
673
+ if (p.type !== "image") return null;
674
+ if (p.data && p.mimeType) {
675
+ return {
676
+ type: "image",
677
+ source: { type: "base64", media_type: p.mimeType, data: p.data }
678
+ };
679
+ }
680
+ const parsed = parseDataUrl(p.url);
681
+ if (parsed) {
682
+ return {
683
+ type: "image",
684
+ source: {
685
+ type: "base64",
686
+ media_type: parsed.mimeType,
687
+ data: parsed.data
688
+ }
689
+ };
690
+ }
691
+ return { type: "image", source: { type: "url", url: p.url } };
692
+ }
693
+ function toAnthropicContent(content) {
694
+ if (typeof content === "string") {
695
+ return [{ type: "text", text: content || "[no content]" }];
696
+ }
697
+ const blocks = [];
698
+ for (const p of content) {
699
+ if (p.type === "text") {
700
+ if (p.text) blocks.push({ type: "text", text: p.text });
701
+ } else {
702
+ const img = buildImageBlock(p);
703
+ if (img) blocks.push(img);
704
+ }
705
+ }
706
+ if (blocks.length === 0) blocks.push({ type: "text", text: "[no content]" });
707
+ return blocks;
708
+ }
709
+ function toAnthropicToolResultContent(content) {
710
+ if (typeof content === "string") {
711
+ return content;
712
+ }
713
+ const blocks = [];
714
+ for (const p of content) {
715
+ if (p.type === "text") {
716
+ if (p.text) blocks.push({ type: "text", text: p.text });
717
+ } else if (p.type === "image") {
718
+ const img = buildImageBlock(p);
719
+ if (img) blocks.push(img);
720
+ }
721
+ }
722
+ if (blocks.length === 0) {
723
+ return "[no content]";
724
+ }
725
+ return blocks;
726
+ }
727
+ function toAnthropicMessages(messages) {
728
+ const out = [];
729
+ for (const m of messages) {
730
+ if (m.role === "tool") {
731
+ const last = out[out.length - 1];
732
+ const block = {
733
+ type: "tool_result",
734
+ tool_use_id: m.toolCallId,
735
+ content: toAnthropicToolResultContent(m.content),
736
+ ...m.toolIsError ? { is_error: true } : {}
737
+ };
738
+ if (last && last.role === "user" && Array.isArray(last.content)) {
739
+ last.content.push(block);
740
+ } else {
741
+ out.push({ role: "user", content: [block] });
742
+ }
743
+ continue;
744
+ }
745
+ if (m.role === "assistant") {
746
+ const blocks = [];
747
+ const textContent = typeof m.content === "string" ? m.content : Array.isArray(m.content) ? m.content.map((p) => p.type === "text" ? p.text : "").join("") : "";
748
+ if (textContent) blocks.push({ type: "text", text: textContent });
749
+ if (m.toolCalls?.length) {
750
+ for (const tc of m.toolCalls) {
751
+ blocks.push({
752
+ type: "tool_use",
753
+ id: tc.id,
754
+ name: tc.name,
755
+ input: tc.args ?? {}
756
+ });
757
+ }
758
+ }
759
+ if (blocks.length === 0) {
760
+ blocks.push({ type: "text", text: "[no content]" });
761
+ }
762
+ out.push({ role: "assistant", content: blocks });
763
+ continue;
764
+ }
765
+ out.push({ role: "user", content: toAnthropicContent(m.content) });
766
+ }
767
+ return out;
768
+ }
769
+ function buildBody(params, stream) {
770
+ const { config, messages, tools } = params;
771
+ const { system, rest } = extractSystem(messages);
772
+ const body = {
773
+ model: config.model,
774
+ max_tokens: config.maxTokens ?? DEFAULT_MAX_TOKENS,
775
+ messages: toAnthropicMessages(rest),
776
+ ...stream ? { stream: true } : {}
777
+ };
778
+ if (config.temperature !== void 0) body.temperature = config.temperature;
779
+ if (system) body.system = system;
780
+ if (tools && tools.length > 0) {
781
+ body.tools = tools.map((t) => ({
782
+ name: t.name,
783
+ description: t.description,
784
+ input_schema: t.inputSchema
785
+ }));
786
+ }
787
+ return body;
788
+ }
789
+ async function* streamChat(params) {
790
+ const { config, signal } = params;
791
+ const res = await fetch(DEFAULT_ENDPOINT, {
792
+ method: "POST",
793
+ headers: {
794
+ "Content-Type": "application/json",
795
+ "x-api-key": config.apiKey,
796
+ "anthropic-version": ANTHROPIC_VERSION,
797
+ "anthropic-dangerous-direct-browser-access": "true"
798
+ },
799
+ body: JSON.stringify(buildBody(params, true)),
800
+ signal
801
+ });
802
+ if (!res.ok || !res.body) {
803
+ const text = await res.text().catch(() => "");
804
+ throw new Error(
805
+ `Anthropic request failed (${res.status} ${res.statusText}): ${text}`
806
+ );
807
+ }
808
+ const blocks = /* @__PURE__ */ new Map();
809
+ let usage;
810
+ for await (const ev of parseSSE(res.body, signal)) {
811
+ let parsed;
812
+ try {
813
+ parsed = JSON.parse(ev.data);
814
+ } catch {
815
+ continue;
816
+ }
817
+ const t = parsed?.type;
818
+ if (t === "message_start") {
819
+ usage = tokenUsageFromRecord(parsed?.message?.usage);
820
+ } else if (t === "message_delta") {
821
+ const deltaUsage = tokenUsageFromRecord(parsed?.usage);
822
+ if (deltaUsage) usage = { ...usage, ...deltaUsage };
823
+ } else if (t === "content_block_start") {
824
+ const idx = parsed.index;
825
+ const cb = parsed.content_block ?? {};
826
+ if (cb.type === "tool_use") {
827
+ blocks.set(idx, {
828
+ kind: "tool_use",
829
+ id: cb.id,
830
+ name: cb.name,
831
+ argsJson: "",
832
+ emittedStart: false
833
+ });
834
+ yield {
835
+ type: "tool-call-start",
836
+ index: idx,
837
+ toolCallId: cb.id,
838
+ toolName: cb.name
839
+ };
840
+ const entry = blocks.get(idx);
841
+ if (entry) entry.emittedStart = true;
842
+ } else {
843
+ blocks.set(idx, {
844
+ kind: "text",
845
+ argsJson: "",
846
+ emittedStart: false
847
+ });
848
+ }
849
+ } else if (t === "content_block_delta") {
850
+ const idx = parsed.index;
851
+ const d = parsed.delta ?? {};
852
+ const entry = blocks.get(idx);
853
+ if (!entry) continue;
854
+ if (d.type === "text_delta" && typeof d.text === "string") {
855
+ yield { type: "text-delta", delta: d.text };
856
+ } else if (d.type === "input_json_delta" && typeof d.partial_json === "string" && entry.kind === "tool_use") {
857
+ entry.argsJson += d.partial_json;
858
+ yield {
859
+ type: "tool-call-args-delta",
860
+ index: idx,
861
+ toolCallId: entry.id,
862
+ toolName: entry.name,
863
+ argsDelta: d.partial_json
864
+ };
865
+ }
866
+ } else if (t === "content_block_stop") {
867
+ const idx = parsed.index;
868
+ const entry = blocks.get(idx);
869
+ if (entry && entry.kind === "tool_use" && entry.id && entry.name) {
870
+ let args = {};
871
+ if (entry.argsJson) {
872
+ try {
873
+ args = JSON.parse(entry.argsJson);
874
+ } catch {
875
+ args = {};
876
+ }
877
+ }
878
+ yield {
879
+ type: "tool-call-ready",
880
+ index: idx,
881
+ toolCallId: entry.id,
882
+ toolName: entry.name,
883
+ args
884
+ };
885
+ }
886
+ } else if (t === "message_stop") {
887
+ if (usage) {
888
+ const totalTokens = usage.totalTokens ?? (usage.inputTokens !== void 0 && usage.outputTokens !== void 0 ? usage.inputTokens + usage.outputTokens : void 0);
889
+ yield { type: "usage", usage: { ...usage, totalTokens } };
890
+ }
891
+ } else if (t === "error") {
892
+ yield {
893
+ type: "error",
894
+ message: parsed?.error?.message ?? "Anthropic stream error"
895
+ };
896
+ }
897
+ }
898
+ yield { type: "done" };
899
+ }
900
+ async function chat(params) {
901
+ const { config, signal } = params;
902
+ const res = await fetch(DEFAULT_ENDPOINT, {
903
+ method: "POST",
904
+ headers: {
905
+ "Content-Type": "application/json",
906
+ "x-api-key": config.apiKey,
907
+ "anthropic-version": ANTHROPIC_VERSION,
908
+ "anthropic-dangerous-direct-browser-access": "true"
909
+ },
910
+ body: JSON.stringify(buildBody(params, false)),
911
+ signal
912
+ });
913
+ if (!res.ok) {
914
+ const text2 = await res.text().catch(() => "");
915
+ throw new Error(
916
+ `Anthropic request failed (${res.status} ${res.statusText}): ${text2}`
917
+ );
918
+ }
919
+ const json = await res.json();
920
+ let text = "";
921
+ const toolCalls = [];
922
+ for (const block of json?.content ?? []) {
923
+ if (block.type === "text" && typeof block.text === "string") {
924
+ text += block.text;
925
+ } else if (block.type === "tool_use") {
926
+ toolCalls.push({
927
+ id: block.id,
928
+ name: block.name,
929
+ args: block.input && typeof block.input === "object" ? block.input : {}
930
+ });
931
+ }
932
+ }
933
+ return { text, toolCalls };
934
+ }
935
+
936
+ // src/llm/schemaUtils.ts
937
+ var ALLOWED_KEYS = /* @__PURE__ */ new Set([
938
+ "type",
939
+ "description",
940
+ "enum",
941
+ "properties",
942
+ "required",
943
+ "items",
944
+ "format",
945
+ "nullable",
946
+ "minimum",
947
+ "maximum",
948
+ "minItems",
949
+ "maxItems",
950
+ "minLength",
951
+ "maxLength",
952
+ "pattern"
953
+ ]);
954
+ function sanitizeSchemaForGemini(schema) {
955
+ if (!schema || typeof schema !== "object") {
956
+ return { type: "object" };
957
+ }
958
+ const cleaned = clean(schema);
959
+ if (typeof cleaned !== "object" || cleaned === null) {
960
+ return { type: "object" };
961
+ }
962
+ const out = cleaned;
963
+ if (!out.type) out.type = "object";
964
+ return out;
965
+ }
966
+ function clean(value) {
967
+ if (Array.isArray(value)) return value.map(clean);
968
+ if (!value || typeof value !== "object") return value;
969
+ const input = value;
970
+ for (const key of ["oneOf", "anyOf", "allOf"]) {
971
+ const arr = input[key];
972
+ if (Array.isArray(arr) && arr.length === 1) {
973
+ return clean(arr[0]);
974
+ }
975
+ }
976
+ const out = {};
977
+ for (const [k, v] of Object.entries(input)) {
978
+ if (!ALLOWED_KEYS.has(k)) continue;
979
+ if (k === "properties" && v && typeof v === "object") {
980
+ const props = {};
981
+ for (const [pk, pv] of Object.entries(v)) {
982
+ props[pk] = clean(pv);
983
+ }
984
+ out[k] = props;
985
+ } else if (k === "items") {
986
+ out[k] = clean(v);
987
+ } else {
988
+ out[k] = v;
989
+ }
990
+ }
991
+ return out;
992
+ }
993
+
994
+ // src/llm/providers/google.ts
995
+ function normalizeModelId(model) {
996
+ const trimmed = model.trim();
997
+ return trimmed.startsWith("models/") ? trimmed.slice("models/".length) : trimmed;
998
+ }
999
+ function endpointFor(model, mode) {
1000
+ const action = mode === "stream" ? "streamGenerateContent?alt=sse" : "generateContent";
1001
+ return `https://generativelanguage.googleapis.com/v1beta/models/${encodeURIComponent(
1002
+ normalizeModelId(model)
1003
+ )}:${action}`;
1004
+ }
1005
+ function buildInlineData(p) {
1006
+ if (p.type !== "image") return null;
1007
+ if (p.data && p.mimeType) {
1008
+ return { inlineData: { mimeType: p.mimeType, data: p.data } };
1009
+ }
1010
+ const parsed = parseDataUrl(p.url);
1011
+ if (parsed) {
1012
+ return {
1013
+ inlineData: { mimeType: parsed.mimeType, data: parsed.data }
1014
+ };
1015
+ }
1016
+ return null;
1017
+ }
1018
+ function toGeminiParts(content) {
1019
+ if (typeof content === "string") {
1020
+ return [{ text: content || "[no content]" }];
1021
+ }
1022
+ const parts = [];
1023
+ for (const p of content) {
1024
+ if (p.type === "text") {
1025
+ if (p.text) parts.push({ text: p.text });
1026
+ } else {
1027
+ const block = buildInlineData(p);
1028
+ if (block) parts.push(block);
1029
+ }
1030
+ }
1031
+ if (parts.length === 0) parts.push({ text: "[no content]" });
1032
+ return parts;
1033
+ }
1034
+ function buildGeminiToolResponse(content) {
1035
+ if (typeof content === "string") {
1036
+ let parsed;
1037
+ try {
1038
+ parsed = JSON.parse(content);
1039
+ } catch {
1040
+ parsed = { result: content };
1041
+ }
1042
+ if (!parsed || typeof parsed !== "object") {
1043
+ parsed = { result: parsed };
1044
+ }
1045
+ return { response: parsed, imageParts: [] };
1046
+ }
1047
+ const { text, imageParts } = partitionToolContent(content);
1048
+ const response = {};
1049
+ if (text) response.text = text;
1050
+ if (imageParts.length > 0) {
1051
+ response.images = imageParts.map((p) => ({
1052
+ mimeType: p.mimeType ?? "image/*",
1053
+ omitted: true
1054
+ }));
1055
+ response.note = "Image bytes were sent in the next user turn as inlineData.";
1056
+ }
1057
+ if (Object.keys(response).length === 0) {
1058
+ response.result = null;
1059
+ }
1060
+ return { response, imageParts };
1061
+ }
1062
+ function toGeminiContents(messages) {
1063
+ const out = [];
1064
+ for (const m of messages) {
1065
+ if (m.role === "tool") {
1066
+ const { response, imageParts } = buildGeminiToolResponse(m.content);
1067
+ const last = out[out.length - 1];
1068
+ const part = {
1069
+ functionResponse: {
1070
+ name: m.toolName,
1071
+ response
1072
+ }
1073
+ };
1074
+ if (last && last.role === "function") {
1075
+ last.parts.push(part);
1076
+ } else {
1077
+ out.push({ role: "function", parts: [part] });
1078
+ }
1079
+ if (imageParts.length > 0) {
1080
+ const userParts = [
1081
+ { text: toolImageFollowupHeader(m.toolName, imageParts.length) }
1082
+ ];
1083
+ for (const p of imageParts) {
1084
+ const block = buildInlineData(p);
1085
+ if (block) userParts.push(block);
1086
+ }
1087
+ out.push({ role: "user", parts: userParts });
1088
+ }
1089
+ continue;
1090
+ }
1091
+ if (m.role === "assistant") {
1092
+ const parts = [];
1093
+ const textContent = typeof m.content === "string" ? m.content : Array.isArray(m.content) ? m.content.map((p) => p.type === "text" ? p.text : "").join("") : "";
1094
+ if (textContent) parts.push({ text: textContent });
1095
+ if (m.toolCalls?.length) {
1096
+ for (const tc of m.toolCalls) {
1097
+ parts.push({
1098
+ functionCall: { name: tc.name, args: tc.args ?? {} }
1099
+ });
1100
+ }
1101
+ }
1102
+ if (parts.length === 0) parts.push({ text: "[no content]" });
1103
+ out.push({ role: "model", parts });
1104
+ continue;
1105
+ }
1106
+ out.push({ role: "user", parts: toGeminiParts(m.content) });
1107
+ }
1108
+ return out;
1109
+ }
1110
+ function buildBody2(params) {
1111
+ const { config, messages, tools } = params;
1112
+ const { system, rest } = extractSystem(messages);
1113
+ const body = {
1114
+ contents: toGeminiContents(rest)
1115
+ };
1116
+ if (system) {
1117
+ body.systemInstruction = { parts: [{ text: system }] };
1118
+ }
1119
+ const genConfig = {};
1120
+ if (config.temperature !== void 0)
1121
+ genConfig.temperature = config.temperature;
1122
+ if (config.maxTokens !== void 0)
1123
+ genConfig.maxOutputTokens = config.maxTokens;
1124
+ if (Object.keys(genConfig).length > 0) body.generationConfig = genConfig;
1125
+ if (tools && tools.length > 0) {
1126
+ body.tools = [
1127
+ {
1128
+ functionDeclarations: tools.map((t) => ({
1129
+ name: t.name,
1130
+ description: t.description,
1131
+ parameters: sanitizeSchemaForGemini(t.inputSchema)
1132
+ }))
1133
+ }
1134
+ ];
1135
+ }
1136
+ return body;
1137
+ }
1138
+ async function* streamChat2(params) {
1139
+ const { config, signal } = params;
1140
+ const url = `${endpointFor(config.model, "stream")}&key=${encodeURIComponent(
1141
+ config.apiKey
1142
+ )}`;
1143
+ const res = await fetch(url, {
1144
+ method: "POST",
1145
+ headers: { "Content-Type": "application/json" },
1146
+ body: JSON.stringify(buildBody2(params)),
1147
+ signal
1148
+ });
1149
+ if (!res.ok || !res.body) {
1150
+ const text = await res.text().catch(() => "");
1151
+ throw new Error(
1152
+ `Google request failed (${res.status} ${res.statusText}): ${text}`
1153
+ );
1154
+ }
1155
+ let toolCallCounter = 0;
1156
+ let usage;
1157
+ for await (const ev of parseSSE(res.body, signal)) {
1158
+ let parsed;
1159
+ try {
1160
+ parsed = JSON.parse(ev.data);
1161
+ } catch {
1162
+ continue;
1163
+ }
1164
+ usage = tokenUsageFromRecord(parsed?.usageMetadata) ?? usage;
1165
+ const parts = parsed?.candidates?.[0]?.content?.parts ?? [];
1166
+ for (const p of parts) {
1167
+ if (typeof p.text === "string" && p.text.length > 0) {
1168
+ yield { type: "text-delta", delta: p.text };
1169
+ } else if (p.functionCall && typeof p.functionCall === "object") {
1170
+ const idx = toolCallCounter++;
1171
+ const id = `call_${idx}_${p.functionCall.name ?? "tool"}`;
1172
+ const name = p.functionCall.name ?? "";
1173
+ const args = p.functionCall.args && typeof p.functionCall.args === "object" ? p.functionCall.args : {};
1174
+ yield {
1175
+ type: "tool-call-start",
1176
+ index: idx,
1177
+ toolCallId: id,
1178
+ toolName: name
1179
+ };
1180
+ const argsJson = JSON.stringify(args);
1181
+ if (argsJson && argsJson !== "{}") {
1182
+ yield {
1183
+ type: "tool-call-args-delta",
1184
+ index: idx,
1185
+ toolCallId: id,
1186
+ toolName: name,
1187
+ argsDelta: argsJson
1188
+ };
1189
+ }
1190
+ yield {
1191
+ type: "tool-call-ready",
1192
+ index: idx,
1193
+ toolCallId: id,
1194
+ toolName: name,
1195
+ args
1196
+ };
1197
+ }
1198
+ }
1199
+ }
1200
+ if (usage) yield { type: "usage", usage };
1201
+ yield { type: "done" };
1202
+ }
1203
+ async function chat2(params) {
1204
+ const { config, signal } = params;
1205
+ const url = `${endpointFor(config.model, "single")}?key=${encodeURIComponent(
1206
+ config.apiKey
1207
+ )}`;
1208
+ const res = await fetch(url, {
1209
+ method: "POST",
1210
+ headers: { "Content-Type": "application/json" },
1211
+ body: JSON.stringify(buildBody2(params)),
1212
+ signal
1213
+ });
1214
+ if (!res.ok) {
1215
+ const text2 = await res.text().catch(() => "");
1216
+ throw new Error(
1217
+ `Google request failed (${res.status} ${res.statusText}): ${text2}`
1218
+ );
1219
+ }
1220
+ const json = await res.json();
1221
+ let text = "";
1222
+ const toolCalls = [];
1223
+ const parts = json?.candidates?.[0]?.content?.parts ?? [];
1224
+ for (const p of parts) {
1225
+ if (typeof p.text === "string") text += p.text;
1226
+ else if (p.functionCall) {
1227
+ toolCalls.push({
1228
+ id: `call_${toolCalls.length}_${p.functionCall.name ?? "tool"}`,
1229
+ name: p.functionCall.name ?? "",
1230
+ args: p.functionCall.args && typeof p.functionCall.args === "object" ? p.functionCall.args : {}
1231
+ });
1232
+ }
1233
+ }
1234
+ return { text, toolCalls };
1235
+ }
1236
+
1237
+ // src/llm/ndjson.ts
1238
+ async function* parseNDJSON(body, signal) {
1239
+ const reader = body.getReader();
1240
+ const decoder = new TextDecoder();
1241
+ let buffer = "";
1242
+ try {
1243
+ while (true) {
1244
+ if (signal?.aborted) return;
1245
+ const { done, value } = await reader.read();
1246
+ if (done) break;
1247
+ buffer += decoder.decode(value, { stream: true });
1248
+ const lines = buffer.split("\n");
1249
+ buffer = lines.pop() ?? "";
1250
+ for (const line of lines) {
1251
+ const trimmed = line.trim();
1252
+ if (!trimmed) continue;
1253
+ try {
1254
+ yield JSON.parse(trimmed);
1255
+ } catch {
1256
+ }
1257
+ }
1258
+ }
1259
+ const trailing = buffer.trim();
1260
+ if (trailing) {
1261
+ try {
1262
+ yield JSON.parse(trailing);
1263
+ } catch {
1264
+ }
1265
+ }
1266
+ } finally {
1267
+ reader.releaseLock();
1268
+ }
1269
+ }
1270
+
1271
+ // src/llm/providers/ollama/utils.ts
1272
+ var DEFAULT_OLLAMA_BASE_URL = "http://localhost:11434";
1273
+ function normalizeOllamaBaseUrl(baseUrl) {
1274
+ const raw = (baseUrl || DEFAULT_OLLAMA_BASE_URL).trim();
1275
+ let end = raw.length;
1276
+ while (end > 0 && raw.charCodeAt(end - 1) === 47) {
1277
+ end--;
1278
+ }
1279
+ const trimmed = raw.slice(0, end);
1280
+ return trimmed.endsWith("/api") ? trimmed.slice(0, -4) : trimmed;
1281
+ }
1282
+ function buildOllamaApiUrl(baseUrl, path) {
1283
+ return `${normalizeOllamaBaseUrl(baseUrl)}${path}`;
1284
+ }
1285
+ var OllamaCorsError = class extends Error {
1286
+ constructor(cause) {
1287
+ super(
1288
+ "Could not reach Ollama. If it's running, allow this origin by starting Ollama with `OLLAMA_ORIGINS=*` (or your inspector origin) and try again."
1289
+ );
1290
+ this.name = "OllamaCorsError";
1291
+ this.cause = cause;
1292
+ }
1293
+ };
1294
+
1295
+ // src/llm/providers/ollama/index.ts
1296
+ function toOllamaImages(content) {
1297
+ const images = [];
1298
+ for (const part of content) {
1299
+ if (part.type !== "image") continue;
1300
+ if (part.data) {
1301
+ images.push(part.data);
1302
+ continue;
1303
+ }
1304
+ const parsed = parseDataUrl(part.url);
1305
+ if (parsed?.data) {
1306
+ images.push(parsed.data);
1307
+ }
1308
+ }
1309
+ return images;
1310
+ }
1311
+ function toOllamaContent(content) {
1312
+ if (typeof content === "string") {
1313
+ return { content };
1314
+ }
1315
+ const text = content.filter(
1316
+ (part) => part.type === "text"
1317
+ ).map((part) => part.text).join("");
1318
+ const images = toOllamaImages(content);
1319
+ return {
1320
+ content: text,
1321
+ ...images.length > 0 ? { images } : {}
1322
+ };
1323
+ }
1324
+ function toOllamaMessages(messages) {
1325
+ return messages.map((message) => {
1326
+ if (message.role === "tool") {
1327
+ return {
1328
+ role: "tool",
1329
+ tool_name: message.toolName,
1330
+ content: typeof message.content === "string" ? message.content : JSON.stringify(message.toolResult ?? message.content)
1331
+ };
1332
+ }
1333
+ if (message.role === "assistant") {
1334
+ const content = typeof message.content === "string" ? { content: message.content } : toOllamaContent(message.content);
1335
+ return {
1336
+ role: "assistant",
1337
+ ...content,
1338
+ ...message.toolCalls?.length ? {
1339
+ tool_calls: message.toolCalls.map((toolCall, index) => ({
1340
+ type: "function",
1341
+ function: {
1342
+ index,
1343
+ name: toolCall.name,
1344
+ arguments: toolCall.args
1345
+ }
1346
+ }))
1347
+ } : {}
1348
+ };
1349
+ }
1350
+ return {
1351
+ role: message.role,
1352
+ ...toOllamaContent(message.content)
1353
+ };
1354
+ });
1355
+ }
1356
+ function buildBody3(params, stream) {
1357
+ const { config, messages, tools } = params;
1358
+ const body = {
1359
+ model: config.model,
1360
+ messages: toOllamaMessages(messages),
1361
+ stream
1362
+ };
1363
+ const options = {};
1364
+ if (config.temperature !== void 0)
1365
+ options.temperature = config.temperature;
1366
+ if (config.maxTokens !== void 0) options.num_predict = config.maxTokens;
1367
+ if (Object.keys(options).length > 0) body.options = options;
1368
+ if (tools && tools.length > 0) {
1369
+ body.tools = tools.map((tool) => ({
1370
+ type: "function",
1371
+ function: {
1372
+ name: tool.name,
1373
+ description: tool.description,
1374
+ parameters: tool.inputSchema
1375
+ }
1376
+ }));
1377
+ }
1378
+ return body;
1379
+ }
1380
+ function buildHeaders(config) {
1381
+ return {
1382
+ "Content-Type": "application/json",
1383
+ ...config.apiKey.trim() ? { Authorization: `Bearer ${config.apiKey.trim()}` } : {}
1384
+ };
1385
+ }
1386
+ function normalizeToolCalls(toolCalls) {
1387
+ if (!Array.isArray(toolCalls)) return [];
1388
+ return toolCalls.map((toolCall) => {
1389
+ const functionCall = toolCall && typeof toolCall === "object" ? toolCall.function : void 0;
1390
+ const name = typeof functionCall?.name === "string" ? functionCall.name : "";
1391
+ const rawArgs = functionCall?.arguments;
1392
+ const args = rawArgs && typeof rawArgs === "object" ? rawArgs : {};
1393
+ return {
1394
+ name,
1395
+ args
1396
+ };
1397
+ }).filter((toolCall) => toolCall.name);
1398
+ }
1399
+ async function* streamChat3(params) {
1400
+ const { config, signal } = params;
1401
+ const res = await fetch(buildOllamaApiUrl(config.baseUrl, "/api/chat"), {
1402
+ method: "POST",
1403
+ headers: buildHeaders(config),
1404
+ body: JSON.stringify(buildBody3(params, true)),
1405
+ signal
1406
+ });
1407
+ if (!res.ok || !res.body) {
1408
+ const text = await res.text().catch(() => "");
1409
+ throw new Error(
1410
+ `Ollama request failed (${res.status} ${res.statusText}): ${text}`
1411
+ );
1412
+ }
1413
+ let toolCallsEmitted = false;
1414
+ let usage;
1415
+ for await (const chunk of parseNDJSON(res.body, signal)) {
1416
+ const message = chunk && typeof chunk === "object" ? chunk.message : void 0;
1417
+ if (typeof message?.content === "string" && message.content.length > 0) {
1418
+ yield { type: "text-delta", delta: message.content };
1419
+ }
1420
+ if (!toolCallsEmitted) {
1421
+ const toolCalls = normalizeToolCalls(message?.tool_calls);
1422
+ if (toolCalls.length > 0) {
1423
+ for (const [index, toolCall] of toolCalls.entries()) {
1424
+ const toolCallId = `call_${index}_${toolCall.name || "tool"}`;
1425
+ yield {
1426
+ type: "tool-call-start",
1427
+ index,
1428
+ toolCallId,
1429
+ toolName: toolCall.name
1430
+ };
1431
+ const argsJson = JSON.stringify(toolCall.args);
1432
+ if (argsJson && argsJson !== "{}") {
1433
+ yield {
1434
+ type: "tool-call-args-delta",
1435
+ index,
1436
+ toolCallId,
1437
+ toolName: toolCall.name,
1438
+ argsDelta: argsJson
1439
+ };
1440
+ }
1441
+ yield {
1442
+ type: "tool-call-ready",
1443
+ index,
1444
+ toolCallId,
1445
+ toolName: toolCall.name,
1446
+ args: toolCall.args
1447
+ };
1448
+ }
1449
+ toolCallsEmitted = true;
1450
+ }
1451
+ }
1452
+ if (chunk && typeof chunk === "object" && chunk.error) {
1453
+ yield {
1454
+ type: "error",
1455
+ message: String(chunk.error)
1456
+ };
1457
+ }
1458
+ usage = tokenUsageFromRecord(chunk) ?? usage;
1459
+ }
1460
+ if (usage) yield { type: "usage", usage };
1461
+ yield { type: "done" };
1462
+ }
1463
+ async function chat3(params) {
1464
+ const { config, signal } = params;
1465
+ const res = await fetch(buildOllamaApiUrl(config.baseUrl, "/api/chat"), {
1466
+ method: "POST",
1467
+ headers: buildHeaders(config),
1468
+ body: JSON.stringify(buildBody3(params, false)),
1469
+ signal
1470
+ });
1471
+ if (!res.ok) {
1472
+ const text = await res.text().catch(() => "");
1473
+ throw new Error(
1474
+ `Ollama request failed (${res.status} ${res.statusText}): ${text}`
1475
+ );
1476
+ }
1477
+ const json = await res.json();
1478
+ const message = json?.message ?? {};
1479
+ return {
1480
+ text: typeof message.content === "string" ? message.content : "",
1481
+ toolCalls: normalizeToolCalls(message.tool_calls).map((tc, index) => ({
1482
+ id: `call_${index}_${tc.name || "tool"}`,
1483
+ name: tc.name,
1484
+ args: tc.args
1485
+ }))
1486
+ };
1487
+ }
1488
+
1489
+ // src/llm/providers/openai-chat-completions.ts
1490
+ var LlmRequestError = class extends Error {
1491
+ status;
1492
+ body;
1493
+ constructor(status, message, body) {
1494
+ super(message);
1495
+ this.name = "LlmRequestError";
1496
+ this.status = status;
1497
+ this.body = body;
1498
+ }
1499
+ };
1500
+ async function throwLlmRequestError(res) {
1501
+ const text = await res.text().catch(() => "");
1502
+ let body = text;
1503
+ if (text) {
1504
+ try {
1505
+ body = JSON.parse(text);
1506
+ } catch {
1507
+ }
1508
+ }
1509
+ throw new LlmRequestError(
1510
+ res.status,
1511
+ `OpenAI request failed (${res.status} ${res.statusText}): ${text}`,
1512
+ body
1513
+ );
1514
+ }
1515
+ var OPENAI_BASE_URL = "https://api.openai.com/v1";
1516
+ function buildEndpoint(config, path) {
1517
+ return `${config.baseUrl ?? OPENAI_BASE_URL}${path}`;
1518
+ }
1519
+ function buildHeaders2(config) {
1520
+ const headers = {
1521
+ "Content-Type": "application/json",
1522
+ ...config.extraHeaders
1523
+ };
1524
+ if (config.apiKey) {
1525
+ headers.Authorization = `Bearer ${config.apiKey}`;
1526
+ }
1527
+ return headers;
1528
+ }
1529
+ function toOpenAIContent(content) {
1530
+ if (typeof content === "string") return content;
1531
+ return content.map((p) => {
1532
+ if (p.type === "text") return { type: "text", text: p.text };
1533
+ return { type: "image_url", image_url: { url: p.url } };
1534
+ });
1535
+ }
1536
+ function toOpenAIMessages(messages) {
1537
+ const out = [];
1538
+ for (const m of messages) {
1539
+ if (m.role === "tool") {
1540
+ const { text, imageParts } = partitionToolContent(m.content);
1541
+ const fallback = imageParts.length > 0 ? "[image content; see next message]" : "[no content]";
1542
+ out.push({
1543
+ role: "tool",
1544
+ tool_call_id: m.toolCallId,
1545
+ content: text || fallback
1546
+ });
1547
+ if (imageParts.length > 0) {
1548
+ const userParts = [
1549
+ {
1550
+ type: "text",
1551
+ text: toolImageFollowupHeader(m.toolName, imageParts.length)
1552
+ },
1553
+ ...imageParts.map((p) => ({
1554
+ type: "image_url",
1555
+ image_url: { url: p.url }
1556
+ }))
1557
+ ];
1558
+ out.push({ role: "user", content: userParts });
1559
+ }
1560
+ continue;
1561
+ }
1562
+ if (m.role === "assistant") {
1563
+ const entry = {
1564
+ role: "assistant",
1565
+ content: typeof m.content === "string" && m.content.length > 0 ? m.content : null
1566
+ };
1567
+ if (m.toolCalls?.length) {
1568
+ entry.tool_calls = m.toolCalls.map((tc) => ({
1569
+ id: tc.id,
1570
+ type: "function",
1571
+ function: { name: tc.name, arguments: JSON.stringify(tc.args) }
1572
+ }));
1573
+ }
1574
+ out.push(entry);
1575
+ continue;
1576
+ }
1577
+ out.push({ role: m.role, content: toOpenAIContent(m.content) });
1578
+ }
1579
+ return out;
1580
+ }
1581
+ async function* streamChat4(params) {
1582
+ const { config, messages, tools, signal } = params;
1583
+ const body = {
1584
+ model: config.model,
1585
+ messages: toOpenAIMessages(messages),
1586
+ stream: true
1587
+ };
1588
+ if (config.provider === "openrouter") {
1589
+ body.stream_options = { include_usage: true };
1590
+ }
1591
+ if (config.temperature !== void 0) body.temperature = config.temperature;
1592
+ if (config.maxTokens !== void 0) body.max_tokens = config.maxTokens;
1593
+ if (tools && tools.length > 0) {
1594
+ body.tools = tools.map((t) => ({
1595
+ type: "function",
1596
+ function: {
1597
+ name: t.name,
1598
+ description: t.description,
1599
+ parameters: t.inputSchema
1600
+ }
1601
+ }));
1602
+ }
1603
+ const endpoint = buildEndpoint(config, "/chat/completions");
1604
+ const res = await fetch(endpoint, {
1605
+ method: "POST",
1606
+ headers: buildHeaders2(config),
1607
+ body: JSON.stringify(body),
1608
+ signal,
1609
+ ...config.credentials ? { credentials: config.credentials } : {}
1610
+ });
1611
+ const responseBody = res.body;
1612
+ if (!res.ok) {
1613
+ await throwLlmRequestError(res);
1614
+ }
1615
+ if (!responseBody) {
1616
+ await throwLlmRequestError(res);
1617
+ }
1618
+ const stream = responseBody;
1619
+ const buffers = /* @__PURE__ */ new Map();
1620
+ for await (const ev of parseSSE(stream, signal)) {
1621
+ if (!ev.data || ev.data === "[DONE]") continue;
1622
+ let parsed;
1623
+ try {
1624
+ parsed = JSON.parse(ev.data);
1625
+ } catch {
1626
+ continue;
1627
+ }
1628
+ const usage = tokenUsageFromRecord(parsed?.usage);
1629
+ if (usage) {
1630
+ yield { type: "usage", usage };
1631
+ }
1632
+ const choice = parsed?.choices?.[0];
1633
+ if (!choice) continue;
1634
+ const delta = choice.delta ?? {};
1635
+ if (typeof delta.content === "string" && delta.content.length > 0) {
1636
+ yield { type: "text-delta", delta: delta.content };
1637
+ }
1638
+ if (Array.isArray(delta.tool_calls)) {
1639
+ for (const tc of delta.tool_calls) {
1640
+ const idx = typeof tc.index === "number" ? tc.index : 0;
1641
+ let buf = buffers.get(idx);
1642
+ if (!buf) {
1643
+ buf = {
1644
+ id: tc.id ?? `call_${idx}`,
1645
+ name: tc.function?.name ?? "",
1646
+ argsJson: "",
1647
+ started: false
1648
+ };
1649
+ buffers.set(idx, buf);
1650
+ }
1651
+ if (tc.id && !buf.id.startsWith("call_")) buf.id = tc.id;
1652
+ else if (tc.id) buf.id = tc.id;
1653
+ if (tc.function?.name) buf.name = tc.function.name;
1654
+ if (!buf.started && buf.name) {
1655
+ buf.started = true;
1656
+ yield {
1657
+ type: "tool-call-start",
1658
+ index: idx,
1659
+ toolCallId: buf.id,
1660
+ toolName: buf.name
1661
+ };
1662
+ }
1663
+ const argsChunk = tc.function?.arguments;
1664
+ if (typeof argsChunk === "string" && argsChunk.length > 0) {
1665
+ buf.argsJson += argsChunk;
1666
+ if (buf.started) {
1667
+ yield {
1668
+ type: "tool-call-args-delta",
1669
+ index: idx,
1670
+ toolCallId: buf.id,
1671
+ toolName: buf.name,
1672
+ argsDelta: argsChunk
1673
+ };
1674
+ }
1675
+ }
1676
+ }
1677
+ }
1678
+ if (choice.finish_reason) {
1679
+ for (const [idx, buf] of buffers) {
1680
+ let args = {};
1681
+ if (buf.argsJson) {
1682
+ try {
1683
+ args = JSON.parse(buf.argsJson);
1684
+ } catch {
1685
+ args = {};
1686
+ }
1687
+ }
1688
+ yield {
1689
+ type: "tool-call-ready",
1690
+ index: idx,
1691
+ toolCallId: buf.id,
1692
+ toolName: buf.name,
1693
+ args
1694
+ };
1695
+ }
1696
+ buffers.clear();
1697
+ }
1698
+ }
1699
+ yield { type: "done" };
1700
+ }
1701
+ async function chat4(params) {
1702
+ const { config, messages, tools, signal } = params;
1703
+ const body = {
1704
+ model: config.model,
1705
+ messages: toOpenAIMessages(messages)
1706
+ };
1707
+ if (config.temperature !== void 0) body.temperature = config.temperature;
1708
+ if (config.maxTokens !== void 0) body.max_tokens = config.maxTokens;
1709
+ if (tools && tools.length > 0) {
1710
+ body.tools = tools.map((t) => ({
1711
+ type: "function",
1712
+ function: {
1713
+ name: t.name,
1714
+ description: t.description,
1715
+ parameters: t.inputSchema
1716
+ }
1717
+ }));
1718
+ }
1719
+ const endpoint = buildEndpoint(config, "/chat/completions");
1720
+ const res = await fetch(endpoint, {
1721
+ method: "POST",
1722
+ headers: buildHeaders2(config),
1723
+ body: JSON.stringify(body),
1724
+ signal,
1725
+ ...config.credentials ? { credentials: config.credentials } : {}
1726
+ });
1727
+ if (!res.ok) {
1728
+ await throwLlmRequestError(res);
1729
+ }
1730
+ const json = await res.json();
1731
+ const choice = json?.choices?.[0]?.message;
1732
+ const text = typeof choice?.content === "string" ? choice.content : "";
1733
+ const toolCalls = Array.isArray(choice?.tool_calls) ? choice.tool_calls.map((tc) => {
1734
+ let args = {};
1735
+ try {
1736
+ args = JSON.parse(tc?.function?.arguments ?? "{}");
1737
+ } catch {
1738
+ args = {};
1739
+ }
1740
+ return {
1741
+ id: tc.id,
1742
+ name: tc.function?.name ?? "",
1743
+ args
1744
+ };
1745
+ }) : [];
1746
+ return { text, toolCalls };
1747
+ }
1748
+
1749
+ // src/llm/providers/index.ts
1750
+ function withOpenRouter(params) {
1751
+ return {
1752
+ ...params,
1753
+ config: {
1754
+ ...params.config,
1755
+ baseUrl: "https://openrouter.ai/api/v1",
1756
+ extraHeaders: {
1757
+ "HTTP-Referer": "https://inspector.mcp-use.com",
1758
+ "X-Title": "mcp-use Inspector"
1759
+ }
1760
+ }
1761
+ };
1762
+ }
1763
+ function streamChat5(params) {
1764
+ switch (params.config.provider) {
1765
+ case "openai":
1766
+ throw new Error(
1767
+ "provider 'openai' uses the Responses API via OpenAIResponsesDriver, not streamChat"
1768
+ );
1769
+ case "openai-compatible":
1770
+ return streamChat4(params);
1771
+ case "anthropic":
1772
+ return streamChat(params);
1773
+ case "google":
1774
+ return streamChat2(params);
1775
+ case "openrouter":
1776
+ return streamChat4(withOpenRouter(params));
1777
+ case "ollama":
1778
+ return streamChat3(params);
1779
+ default:
1780
+ throw new Error(`Unsupported LLM provider: ${params.config.provider}`);
1781
+ }
1782
+ }
1783
+ function chat5(params) {
1784
+ switch (params.config.provider) {
1785
+ case "openai":
1786
+ throw new Error(
1787
+ "provider 'openai' uses the Responses API via OpenAIResponsesDriver, not chat"
1788
+ );
1789
+ case "openai-compatible":
1790
+ return chat4(params);
1791
+ case "anthropic":
1792
+ return chat(params);
1793
+ case "google":
1794
+ return chat2(params);
1795
+ case "openrouter":
1796
+ return chat4(withOpenRouter(params));
1797
+ case "ollama":
1798
+ return chat3(params);
1799
+ default:
1800
+ throw new Error(`Unsupported LLM provider: ${params.config.provider}`);
1801
+ }
1802
+ }
1803
+
1804
+ // src/llm/providers/openai-shared.ts
1805
+ var OPENAI_BASE_URL2 = "https://api.openai.com/v1";
1806
+ function buildEndpoint2(config, path) {
1807
+ const base = config.baseUrl ?? OPENAI_BASE_URL2;
1808
+ return `${base.replace(/\/$/, "")}${path}`;
1809
+ }
1810
+ function buildHeaders3(config) {
1811
+ const headers = {
1812
+ "Content-Type": "application/json",
1813
+ ...config.extraHeaders
1814
+ };
1815
+ if (config.apiKey) {
1816
+ headers.Authorization = `Bearer ${config.apiKey}`;
1817
+ }
1818
+ return headers;
1819
+ }
1820
+ async function readOpenAIError(res) {
1821
+ const text = await res.text().catch(() => "");
1822
+ return `OpenAI request failed (${res.status} ${res.statusText}): ${text}`;
1823
+ }
1824
+
1825
+ // src/llm/providers/openai-responses.ts
1826
+ function toResponsesUserContent(content) {
1827
+ if (typeof content === "string") return content;
1828
+ return content.map((p) => {
1829
+ if (p.type === "text") return { type: "input_text", text: p.text };
1830
+ return { type: "input_image", image_url: p.url };
1831
+ });
1832
+ }
1833
+ function seedInputFromMessages(messages) {
1834
+ const systemParts = [];
1835
+ const input = [];
1836
+ for (const m of messages) {
1837
+ if (m.role === "system") {
1838
+ const text = typeof m.content === "string" ? m.content : m.content.filter((p) => p.type === "text").map((p) => p.text).join("\n");
1839
+ if (text) systemParts.push(text);
1840
+ continue;
1841
+ }
1842
+ if (m.role === "user") {
1843
+ input.push({
1844
+ role: "user",
1845
+ content: toResponsesUserContent(m.content)
1846
+ });
1847
+ continue;
1848
+ }
1849
+ if (m.role === "assistant") {
1850
+ if (typeof m.content === "string" && m.content.length > 0) {
1851
+ input.push({
1852
+ type: "message",
1853
+ role: "assistant",
1854
+ content: [{ type: "output_text", text: m.content }]
1855
+ });
1856
+ }
1857
+ for (const tc of m.toolCalls ?? []) {
1858
+ input.push({
1859
+ type: "function_call",
1860
+ call_id: tc.id,
1861
+ name: tc.name,
1862
+ arguments: JSON.stringify(tc.args)
1863
+ });
1864
+ }
1865
+ continue;
1866
+ }
1867
+ if (m.role === "tool") {
1868
+ const { text, imageParts } = partitionToolContent(m.content);
1869
+ const fallback = imageParts.length > 0 ? "[image content; see next message]" : "[no content]";
1870
+ input.push({
1871
+ type: "function_call_output",
1872
+ call_id: m.toolCallId,
1873
+ output: text || fallback
1874
+ });
1875
+ if (imageParts.length > 0) {
1876
+ input.push({
1877
+ role: "user",
1878
+ content: [
1879
+ {
1880
+ type: "input_text",
1881
+ text: toolImageFollowupHeader(m.toolName, imageParts.length)
1882
+ },
1883
+ ...imageParts.map((p) => ({
1884
+ type: "input_image",
1885
+ image_url: p.url
1886
+ }))
1887
+ ]
1888
+ });
1889
+ }
1890
+ }
1891
+ }
1892
+ return {
1893
+ instructions: systemParts.length > 0 ? systemParts.join("\n\n") : void 0,
1894
+ input
1895
+ };
1896
+ }
1897
+ function toResponsesTools(tools) {
1898
+ return tools.map((t) => ({
1899
+ type: "function",
1900
+ name: t.name,
1901
+ description: t.description,
1902
+ parameters: t.inputSchema,
1903
+ strict: false
1904
+ }));
1905
+ }
1906
+ function appendToolOutputsToInput(input, callId, toolName, result) {
1907
+ const content = toolResultToContent(result);
1908
+ if (typeof content === "string") {
1909
+ input.push({
1910
+ type: "function_call_output",
1911
+ call_id: callId,
1912
+ output: content
1913
+ });
1914
+ return;
1915
+ }
1916
+ const { text, imageParts } = partitionToolContent(content);
1917
+ input.push({
1918
+ type: "function_call_output",
1919
+ call_id: callId,
1920
+ output: text || "[image content; see next message]"
1921
+ });
1922
+ if (imageParts.length > 0) {
1923
+ input.push({
1924
+ role: "user",
1925
+ content: [
1926
+ {
1927
+ type: "input_text",
1928
+ text: toolImageFollowupHeader(toolName, imageParts.length)
1929
+ },
1930
+ ...imageParts.map((p) => ({
1931
+ type: "input_image",
1932
+ image_url: p.url
1933
+ }))
1934
+ ]
1935
+ });
1936
+ }
1937
+ }
1938
+ function buildResponsesBody(params, stream) {
1939
+ const body = {
1940
+ model: params.config.model,
1941
+ input: params.input,
1942
+ store: false,
1943
+ include: ["reasoning.encrypted_content"],
1944
+ reasoning: { effort: params.config.reasoningEffort ?? "low" },
1945
+ stream
1946
+ };
1947
+ if (params.instructions) body.instructions = params.instructions;
1948
+ if (params.tools && params.tools.length > 0) {
1949
+ body.tools = toResponsesTools(params.tools);
1950
+ }
1951
+ if (params.config.maxTokens !== void 0) {
1952
+ body.max_output_tokens = params.config.maxTokens;
1953
+ }
1954
+ return body;
1955
+ }
1956
+ function extractFunctionCalls(output) {
1957
+ const calls = [];
1958
+ for (const item of output) {
1959
+ if (!item || typeof item !== "object") continue;
1960
+ const row = item;
1961
+ if (row.type !== "function_call") continue;
1962
+ if (typeof row.call_id !== "string" || typeof row.name !== "string") {
1963
+ continue;
1964
+ }
1965
+ calls.push({
1966
+ call_id: row.call_id,
1967
+ name: row.name,
1968
+ arguments: typeof row.arguments === "string" ? row.arguments : "{}"
1969
+ });
1970
+ }
1971
+ return calls;
1972
+ }
1973
+ function extractMessageText(output) {
1974
+ const parts = [];
1975
+ for (const item of output) {
1976
+ if (!item || typeof item !== "object") continue;
1977
+ const row = item;
1978
+ if (row.type !== "message" || row.role !== "assistant") continue;
1979
+ const content = row.content;
1980
+ if (!Array.isArray(content)) continue;
1981
+ for (const block of content) {
1982
+ if (!block || typeof block !== "object") continue;
1983
+ const b = block;
1984
+ if (b.type === "output_text" && typeof b.text === "string") {
1985
+ parts.push(b.text);
1986
+ }
1987
+ }
1988
+ }
1989
+ return parts.join("");
1990
+ }
1991
+ function parseArgs(argsJson) {
1992
+ if (!argsJson) return {};
1993
+ try {
1994
+ return JSON.parse(argsJson);
1995
+ } catch {
1996
+ return {};
1997
+ }
1998
+ }
1999
+ async function* streamResponsesTurn(params) {
2000
+ const res = await fetch(buildEndpoint2(params.config, "/responses"), {
2001
+ method: "POST",
2002
+ headers: buildHeaders3(params.config),
2003
+ body: JSON.stringify(buildResponsesBody(params, true)),
2004
+ signal: params.signal
2005
+ });
2006
+ if (!res.ok || !res.body) {
2007
+ throw new Error(await readOpenAIError(res));
2008
+ }
2009
+ const callBuffers = /* @__PURE__ */ new Map();
2010
+ let nextIndex = 0;
2011
+ let completedOutput = [];
2012
+ for await (const ev of parseSSE(res.body, params.signal)) {
2013
+ if (!ev.data || ev.data === "[DONE]") continue;
2014
+ let parsed;
2015
+ try {
2016
+ parsed = JSON.parse(ev.data);
2017
+ } catch {
2018
+ continue;
2019
+ }
2020
+ const type = typeof parsed.type === "string" ? parsed.type : ev.event;
2021
+ if (type === "response.output_text.delta") {
2022
+ const delta = parsed.delta;
2023
+ if (typeof delta === "string" && delta.length > 0) {
2024
+ yield { type: "text-delta", delta };
2025
+ }
2026
+ continue;
2027
+ }
2028
+ if (type === "response.output_item.added") {
2029
+ const item = parsed.item;
2030
+ if (item?.type === "function_call") {
2031
+ const callId = typeof item.call_id === "string" ? item.call_id : `call_${nextIndex}`;
2032
+ const name = typeof item.name === "string" ? item.name : "";
2033
+ const idx = nextIndex++;
2034
+ callBuffers.set(callId, {
2035
+ index: idx,
2036
+ name,
2037
+ argsJson: "",
2038
+ started: true
2039
+ });
2040
+ yield {
2041
+ type: "tool-call-start",
2042
+ index: idx,
2043
+ toolCallId: callId,
2044
+ toolName: name
2045
+ };
2046
+ }
2047
+ continue;
2048
+ }
2049
+ if (type === "response.function_call_arguments.delta") {
2050
+ const callId = typeof parsed.call_id === "string" ? parsed.call_id : "";
2051
+ const delta = typeof parsed.delta === "string" ? parsed.delta : "";
2052
+ const buf = callBuffers.get(callId);
2053
+ if (buf && delta.length > 0) {
2054
+ buf.argsJson += delta;
2055
+ yield {
2056
+ type: "tool-call-args-delta",
2057
+ index: buf.index,
2058
+ toolCallId: callId,
2059
+ toolName: buf.name,
2060
+ argsDelta: delta
2061
+ };
2062
+ }
2063
+ continue;
2064
+ }
2065
+ if (type === "response.function_call_arguments.done") {
2066
+ const callId = typeof parsed.call_id === "string" ? parsed.call_id : "";
2067
+ const argsRaw = typeof parsed.arguments === "string" ? parsed.arguments : "";
2068
+ const buf = callBuffers.get(callId);
2069
+ if (buf) {
2070
+ if (argsRaw) buf.argsJson = argsRaw;
2071
+ yield {
2072
+ type: "tool-call-ready",
2073
+ index: buf.index,
2074
+ toolCallId: callId,
2075
+ toolName: buf.name,
2076
+ args: parseArgs(buf.argsJson || argsRaw)
2077
+ };
2078
+ }
2079
+ continue;
2080
+ }
2081
+ if (type === "response.completed") {
2082
+ const response = parsed.response;
2083
+ if (response && Array.isArray(response.output)) {
2084
+ completedOutput = response.output;
2085
+ }
2086
+ const usage = tokenUsageFromRecord(response?.usage);
2087
+ if (usage) {
2088
+ yield { type: "usage", usage };
2089
+ }
2090
+ continue;
2091
+ }
2092
+ if (type === "error") {
2093
+ const message = typeof parsed.message === "string" ? parsed.message : "OpenAI Responses stream error";
2094
+ yield { type: "error", message };
2095
+ return [];
2096
+ }
2097
+ }
2098
+ yield { type: "done" };
2099
+ return completedOutput;
2100
+ }
2101
+ async function completeResponsesTurn(params) {
2102
+ const res = await fetch(buildEndpoint2(params.config, "/responses"), {
2103
+ method: "POST",
2104
+ headers: buildHeaders3(params.config),
2105
+ body: JSON.stringify(buildResponsesBody(params, false)),
2106
+ signal: params.signal
2107
+ });
2108
+ if (!res.ok) {
2109
+ throw new Error(await readOpenAIError(res));
2110
+ }
2111
+ const json = await res.json();
2112
+ const status = json.status;
2113
+ if (status !== "completed" && status !== void 0) {
2114
+ throw new Error(`OpenAI response ended with status ${String(status)}`);
2115
+ }
2116
+ const output = Array.isArray(json.output) ? json.output : [];
2117
+ const fnCalls = extractFunctionCalls(output);
2118
+ const text = typeof json.output_text === "string" ? json.output_text : extractMessageText(output);
2119
+ return {
2120
+ text,
2121
+ output,
2122
+ toolCalls: fnCalls.map((c) => ({
2123
+ id: c.call_id,
2124
+ name: c.name,
2125
+ args: parseArgs(c.arguments)
2126
+ }))
2127
+ };
2128
+ }
2129
+
2130
+ // src/llm/providers/openai-responses-driver.ts
2131
+ var OpenAIResponsesDriver = class {
2132
+ constructor(config) {
2133
+ this.config = config;
2134
+ }
2135
+ managesToolLoop = true;
2136
+ stream(params) {
2137
+ return this.streamSingleTurn(params);
2138
+ }
2139
+ async complete(params) {
2140
+ const { instructions, input } = seedInputFromMessages(params.messages);
2141
+ const result = await completeResponsesTurn({
2142
+ config: this.config,
2143
+ instructions,
2144
+ input,
2145
+ tools: params.tools,
2146
+ signal: params.signal
2147
+ });
2148
+ return { text: result.text, toolCalls: result.toolCalls };
2149
+ }
2150
+ async *streamToolLoop(params) {
2151
+ const { instructions, input: seeded } = seedInputFromMessages(
2152
+ params.messages
2153
+ );
2154
+ const input = [...seeded];
2155
+ const maxSteps = params.maxSteps ?? 10;
2156
+ for (let step = 0; step < maxSteps; step++) {
2157
+ if (params.signal?.aborted) return;
2158
+ const turn = streamResponsesTurn({
2159
+ config: this.config,
2160
+ instructions,
2161
+ input,
2162
+ tools: params.tools,
2163
+ signal: params.signal
2164
+ });
2165
+ let output = [];
2166
+ for (; ; ) {
2167
+ const next = await turn.next();
2168
+ if (next.done) {
2169
+ output = next.value ?? [];
2170
+ break;
2171
+ }
2172
+ yield next.value;
2173
+ if (next.value.type === "error") return;
2174
+ }
2175
+ input.push(...output);
2176
+ const functionCalls = extractFunctionCalls(output);
2177
+ if (functionCalls.length === 0) return;
2178
+ for (const call of functionCalls) {
2179
+ if (params.signal?.aborted) return;
2180
+ let args = {};
2181
+ try {
2182
+ args = JSON.parse(call.arguments);
2183
+ } catch {
2184
+ args = {};
2185
+ }
2186
+ let result;
2187
+ let isError = false;
2188
+ try {
2189
+ result = await params.callTool(call.name, args);
2190
+ isError = isToolResultError(result);
2191
+ } catch (err) {
2192
+ isError = true;
2193
+ result = {
2194
+ isError: true,
2195
+ error: err instanceof Error ? err.message : String(err)
2196
+ };
2197
+ }
2198
+ appendToolOutputsToInput(input, call.call_id, call.name, result);
2199
+ yield {
2200
+ type: "tool-result",
2201
+ toolCallId: call.call_id,
2202
+ toolName: call.name,
2203
+ result,
2204
+ isError
2205
+ };
2206
+ }
2207
+ }
2208
+ }
2209
+ async runToolLoopNonStreaming(params) {
2210
+ const { instructions, input: seeded } = seedInputFromMessages(
2211
+ params.messages
2212
+ );
2213
+ const input = [...seeded];
2214
+ const maxSteps = params.maxSteps ?? 10;
2215
+ const transcriptToolCalls = [];
2216
+ let finalText = "";
2217
+ for (let step = 0; step < maxSteps; step++) {
2218
+ if (params.signal?.aborted) break;
2219
+ const turn = await completeResponsesTurn({
2220
+ config: this.config,
2221
+ instructions,
2222
+ input,
2223
+ tools: params.tools,
2224
+ signal: params.signal
2225
+ });
2226
+ input.push(...turn.output);
2227
+ if (turn.toolCalls.length === 0) {
2228
+ finalText = turn.text;
2229
+ break;
2230
+ }
2231
+ for (const tc of turn.toolCalls) {
2232
+ let result;
2233
+ let isError = false;
2234
+ try {
2235
+ result = await params.callTool(tc.name, tc.args);
2236
+ isError = isToolResultError(result);
2237
+ } catch (err) {
2238
+ isError = true;
2239
+ result = {
2240
+ isError: true,
2241
+ error: err instanceof Error ? err.message : String(err)
2242
+ };
2243
+ }
2244
+ transcriptToolCalls.push({
2245
+ toolName: tc.name,
2246
+ args: tc.args,
2247
+ result
2248
+ });
2249
+ appendToolOutputsToInput(input, tc.id, tc.name, result);
2250
+ void isError;
2251
+ }
2252
+ }
2253
+ return { content: finalText, toolCalls: transcriptToolCalls };
2254
+ }
2255
+ async *streamSingleTurn(params) {
2256
+ const { instructions, input } = seedInputFromMessages(params.messages);
2257
+ const turn = streamResponsesTurn({
2258
+ config: this.config,
2259
+ instructions,
2260
+ input,
2261
+ tools: params.tools,
2262
+ signal: params.signal
2263
+ });
2264
+ for (; ; ) {
2265
+ const next = await turn.next();
2266
+ if (next.done) return;
2267
+ yield next.value;
2268
+ if (next.value.type === "error") return;
2269
+ }
2270
+ }
2271
+ };
2272
+
2273
+ // src/llm/driver.ts
2274
+ function createLlmDriver(config) {
2275
+ if (config.provider === "openai") {
2276
+ return new OpenAIResponsesDriver(config);
2277
+ }
2278
+ return new RestLlmDriver(config);
2279
+ }
2280
+ var RestLlmDriver = class {
2281
+ constructor(config) {
2282
+ this.config = config;
2283
+ }
2284
+ stream(params) {
2285
+ return streamChat5({
2286
+ config: this.config,
2287
+ messages: params.messages,
2288
+ tools: params.tools,
2289
+ signal: params.signal
2290
+ });
2291
+ }
2292
+ async complete(params) {
2293
+ const result = await chat5({
2294
+ config: this.config,
2295
+ messages: params.messages,
2296
+ tools: params.tools,
2297
+ signal: params.signal
2298
+ });
2299
+ return { text: result.text, toolCalls: result.toolCalls };
2300
+ }
2301
+ };
2302
+
2303
+ // src/llm/toolLoop.ts
2304
+ async function* runToolLoop(params) {
2305
+ if (params.driver.managesToolLoop && params.driver.streamToolLoop) {
2306
+ yield* params.driver.streamToolLoop(params);
2307
+ return;
2308
+ }
2309
+ const { driver, tools, callTool, signal } = params;
2310
+ const maxSteps = params.maxSteps ?? 10;
2311
+ const messages = [...params.messages];
2312
+ for (let step = 0; step < maxSteps; step++) {
2313
+ if (signal?.aborted) return;
2314
+ const pendingToolCalls = [];
2315
+ let assistantText = "";
2316
+ try {
2317
+ for await (const ev of driver.stream({
2318
+ messages,
2319
+ tools,
2320
+ signal
2321
+ })) {
2322
+ if (ev.type === "text-delta") {
2323
+ assistantText += ev.delta;
2324
+ } else if (ev.type === "tool-call-ready") {
2325
+ pendingToolCalls.push({
2326
+ id: ev.toolCallId,
2327
+ name: ev.toolName,
2328
+ args: ev.args
2329
+ });
2330
+ }
2331
+ yield ev;
2332
+ }
2333
+ } catch (err) {
2334
+ yield {
2335
+ type: "error",
2336
+ message: err instanceof Error ? err.message : String(err)
2337
+ };
2338
+ return;
2339
+ }
2340
+ if (pendingToolCalls.length === 0) {
2341
+ return;
2342
+ }
2343
+ messages.push({
2344
+ role: "assistant",
2345
+ content: assistantText,
2346
+ toolCalls: pendingToolCalls
2347
+ });
2348
+ for (const tc of pendingToolCalls) {
2349
+ if (signal?.aborted) return;
2350
+ let result;
2351
+ let isError = false;
2352
+ try {
2353
+ result = await callTool(tc.name, tc.args);
2354
+ isError = isToolResultError(result);
2355
+ } catch (err) {
2356
+ isError = true;
2357
+ result = {
2358
+ isError: true,
2359
+ error: err instanceof Error ? err.message : String(err)
2360
+ };
2361
+ }
2362
+ messages.push({
2363
+ role: "tool",
2364
+ content: toolResultToContent(result),
2365
+ toolCallId: tc.id,
2366
+ toolName: tc.name,
2367
+ toolResult: result,
2368
+ toolIsError: isError
2369
+ });
2370
+ yield {
2371
+ type: "tool-result",
2372
+ toolCallId: tc.id,
2373
+ toolName: tc.name,
2374
+ result,
2375
+ isError
2376
+ };
2377
+ }
2378
+ }
2379
+ }
2380
+ async function runToolLoopNonStreaming(params) {
2381
+ if (params.driver.managesToolLoop && params.driver.runToolLoopNonStreaming) {
2382
+ return params.driver.runToolLoopNonStreaming(params);
2383
+ }
2384
+ const { driver, tools, callTool, signal } = params;
2385
+ const maxSteps = params.maxSteps ?? 10;
2386
+ const messages = [...params.messages];
2387
+ const transcriptToolCalls = [];
2388
+ let finalText = "";
2389
+ for (let step = 0; step < maxSteps; step++) {
2390
+ if (signal?.aborted) break;
2391
+ const { text, toolCalls } = await driver.complete({
2392
+ messages,
2393
+ tools,
2394
+ signal
2395
+ });
2396
+ if (toolCalls.length === 0) {
2397
+ finalText = text;
2398
+ break;
2399
+ }
2400
+ messages.push({
2401
+ role: "assistant",
2402
+ content: text,
2403
+ toolCalls
2404
+ });
2405
+ for (const tc of toolCalls) {
2406
+ let result;
2407
+ let isError = false;
2408
+ try {
2409
+ result = await callTool(tc.name, tc.args);
2410
+ isError = isToolResultError(result);
2411
+ } catch (err) {
2412
+ isError = true;
2413
+ result = {
2414
+ isError: true,
2415
+ error: err instanceof Error ? err.message : String(err)
2416
+ };
2417
+ }
2418
+ transcriptToolCalls.push({
2419
+ toolName: tc.name,
2420
+ args: tc.args,
2421
+ result
2422
+ });
2423
+ messages.push({
2424
+ role: "tool",
2425
+ content: toolResultToContent(result),
2426
+ toolCallId: tc.id,
2427
+ toolName: tc.name,
2428
+ toolResult: result,
2429
+ toolIsError: isError
2430
+ });
2431
+ }
2432
+ }
2433
+ return { content: finalText, toolCalls: transcriptToolCalls };
2434
+ }
2435
+
2436
+ // src/llm/native_runner.ts
2437
+ async function* streamNativeAgent(driver, options) {
2438
+ yield* runToolLoop({
2439
+ driver,
2440
+ messages: options.messages,
2441
+ tools: options.tools,
2442
+ callTool: options.callTool,
2443
+ maxSteps: options.maxSteps,
2444
+ signal: options.signal
2445
+ });
2446
+ }
2447
+ async function* streamNativeAgentSteps(driver, options) {
2448
+ let finalText = "";
2449
+ let pendingStep = null;
2450
+ for await (const ev of streamNativeAgent(driver, options)) {
2451
+ if (ev.type === "text-delta") {
2452
+ finalText += ev.delta;
2453
+ } else if (ev.type === "tool-call-ready") {
2454
+ pendingStep = {
2455
+ action: {
2456
+ tool: ev.toolName,
2457
+ toolInput: ev.args,
2458
+ log: `Calling tool ${ev.toolName}`
2459
+ },
2460
+ observation: ""
2461
+ };
2462
+ yield pendingStep;
2463
+ } else if (ev.type === "tool-result" && pendingStep) {
2464
+ const observation = typeof ev.result === "string" ? ev.result : JSON.stringify(ev.result ?? "");
2465
+ yield {
2466
+ action: pendingStep.action,
2467
+ observation
2468
+ };
2469
+ pendingStep = null;
2470
+ } else if (ev.type === "error") {
2471
+ throw new Error(ev.message);
2472
+ }
2473
+ }
2474
+ return finalText;
2475
+ }
2476
+ async function runNativeAgent(driver, options) {
2477
+ const result = await runToolLoopNonStreaming({
2478
+ driver,
2479
+ messages: options.messages,
2480
+ tools: options.tools,
2481
+ callTool: options.callTool,
2482
+ maxSteps: options.maxSteps,
2483
+ signal: options.signal
2484
+ });
2485
+ return result.content;
2486
+ }
2487
+
2488
+ // src/llm/provider_config.ts
2489
+ import { logger as logger3 } from "@mcp-use/client";
2490
+ var PROVIDER_ENV = {
2491
+ openai: ["OPENAI_API_KEY"],
2492
+ anthropic: ["ANTHROPIC_API_KEY"],
2493
+ google: ["GOOGLE_API_KEY", "GOOGLE_GENERATIVE_AI_API_KEY"],
2494
+ openrouter: ["OPENROUTER_API_KEY"],
2495
+ ollama: [],
2496
+ "openai-compatible": ["OPENAI_API_KEY"]
2497
+ };
2498
+ function resolveApiKey(provider, config) {
2499
+ if (config?.apiKey) return config.apiKey;
2500
+ const envVars = PROVIDER_ENV[provider] ?? [];
2501
+ if (typeof process !== "undefined" && process.env) {
2502
+ for (const envVar of envVars) {
2503
+ const key = process.env[envVar];
2504
+ if (key) {
2505
+ logger3.debug(`Using API key from ${envVar} for ${provider}`);
2506
+ return key;
2507
+ }
2508
+ }
2509
+ }
2510
+ if (provider === "ollama") return "";
2511
+ const hint = envVars.length > 0 ? envVars.join(" or ") : "apiKey in llmConfig";
2512
+ throw new Error(`API key not found for provider '${provider}'. Set ${hint}.`);
2513
+ }
2514
+ function parseLLMStringToProviderConfig(llmString, config) {
2515
+ const parts = llmString.split("/");
2516
+ if (parts.length < 2) {
2517
+ throw new Error(
2518
+ `Invalid LLM string '${llmString}'. Expected 'provider/model'.`
2519
+ );
2520
+ }
2521
+ const provider = parts[0].toLowerCase();
2522
+ const model = parts.slice(1).join("/");
2523
+ const supported = [
2524
+ "openai",
2525
+ "anthropic",
2526
+ "google",
2527
+ "openrouter",
2528
+ "ollama",
2529
+ "openai-compatible"
2530
+ ];
2531
+ if (!supported.includes(provider)) {
2532
+ throw new Error(
2533
+ `Unsupported provider '${provider}'. Supported: ${supported.join(", ")}`
2534
+ );
2535
+ }
2536
+ return {
2537
+ provider,
2538
+ model,
2539
+ apiKey: resolveApiKey(provider, config),
2540
+ temperature: config?.temperature,
2541
+ maxTokens: config?.maxTokens,
2542
+ baseUrl: config?.baseUrl,
2543
+ extraHeaders: config?.extraHeaders,
2544
+ credentials: config?.credentials
2545
+ };
2546
+ }
2547
+ function providerConfigFromOptions(provider, model, config) {
2548
+ return {
2549
+ provider,
2550
+ model,
2551
+ apiKey: resolveApiKey(provider, config),
2552
+ temperature: config?.temperature,
2553
+ maxTokens: config?.maxTokens,
2554
+ baseUrl: config?.baseUrl,
2555
+ extraHeaders: config?.extraHeaders,
2556
+ credentials: config?.credentials
2557
+ };
2558
+ }
2559
+
2560
+ // src/version.ts
2561
+ var VERSION = "2.0.0-beta.0";
2562
+ function getPackageVersion() {
2563
+ return VERSION;
2564
+ }
2565
+
2566
+ // src/agents/normalize_run_options.ts
2567
+ function normalizeRunOptions(queryOrOptions, maxSteps, manageConnector, _externalHistory, outputSchema, signal) {
2568
+ if (typeof queryOrOptions === "object" && queryOrOptions !== null) {
2569
+ return {
2570
+ prompt: queryOrOptions.prompt,
2571
+ maxSteps: queryOrOptions.maxSteps,
2572
+ manageConnector: queryOrOptions.manageConnector,
2573
+ messages: queryOrOptions.messages,
2574
+ schema: queryOrOptions.schema,
2575
+ signal: queryOrOptions.signal
2576
+ };
2577
+ }
2578
+ return {
2579
+ prompt: queryOrOptions,
2580
+ maxSteps,
2581
+ manageConnector,
2582
+ schema: outputSchema,
2583
+ signal
2584
+ };
2585
+ }
2586
+
2587
+ // src/agents/remote.ts
2588
+ import { toJSONSchema } from "zod";
2589
+ import { logger as logger4 } from "@mcp-use/client";
2590
+ var API_CHATS_ENDPOINT = "/api/v1/chats";
2591
+ var API_CHAT_EXECUTE_ENDPOINT = "/api/v1/chats/{chat_id}/execute";
2592
+ function normalizeRemoteRunOptions(queryOrOptions, maxSteps, manageConnector, externalHistory, outputSchema) {
2593
+ if (typeof queryOrOptions === "object" && queryOrOptions !== null) {
2594
+ const options = queryOrOptions;
2595
+ return {
2596
+ query: options.prompt ?? "",
2597
+ maxSteps: options.maxSteps,
2598
+ manageConnector: options.manageConnector,
2599
+ externalHistory: options.externalHistory,
2600
+ outputSchema: options.schema
2601
+ };
2602
+ }
2603
+ return {
2604
+ query: queryOrOptions,
2605
+ maxSteps,
2606
+ manageConnector,
2607
+ externalHistory,
2608
+ outputSchema
2609
+ };
2610
+ }
2611
+ var RemoteAgent = class {
2612
+ agentId;
2613
+ apiKey;
2614
+ baseUrl;
2615
+ chatId = null;
2616
+ constructor(options) {
2617
+ this.agentId = options.agentId;
2618
+ this.baseUrl = options.baseUrl ?? "https://cloud.manufact.com";
2619
+ const apiKey = options.apiKey ?? (typeof process !== "undefined" && process.env?.MCP_USE_API_KEY);
2620
+ if (!apiKey) {
2621
+ throw new Error(
2622
+ "API key is required for remote execution. Please provide it as a parameter or set the MCP_USE_API_KEY environment variable. You can get an API key from https://cloud.manufact.com"
2623
+ );
2624
+ }
2625
+ this.apiKey = apiKey;
2626
+ }
2627
+ pydanticToJsonSchema(schema) {
2628
+ return toJSONSchema(schema);
2629
+ }
2630
+ parseStructuredResponse(responseData, outputSchema) {
2631
+ let resultData;
2632
+ if (typeof responseData === "object" && responseData !== null) {
2633
+ if ("result" in responseData) {
2634
+ const outerResult = responseData.result;
2635
+ if (typeof outerResult === "object" && outerResult !== null && "result" in outerResult) {
2636
+ resultData = outerResult.result;
2637
+ } else {
2638
+ resultData = outerResult;
2639
+ }
2640
+ } else {
2641
+ resultData = responseData;
2642
+ }
2643
+ } else if (typeof responseData === "string") {
2644
+ try {
2645
+ resultData = JSON.parse(responseData);
2646
+ } catch {
2647
+ resultData = { content: responseData };
2648
+ }
2649
+ } else {
2650
+ resultData = responseData;
2651
+ }
2652
+ try {
2653
+ return outputSchema.parse(resultData);
2654
+ } catch (e) {
2655
+ logger4.warn(`Failed to parse structured output: ${e}`);
2656
+ const schemaShape = outputSchema._def?.shape();
2657
+ if (schemaShape && "content" in schemaShape) {
2658
+ return outputSchema.parse({ content: String(resultData) });
2659
+ }
2660
+ throw e;
2661
+ }
2662
+ }
2663
+ async createChatSession() {
2664
+ const chatPayload = {
2665
+ title: `Remote Agent Session - ${this.agentId}`,
2666
+ agent_id: this.agentId,
2667
+ type: "agent_execution"
2668
+ };
2669
+ const headers = {
2670
+ "Content-Type": "application/json",
2671
+ "x-api-key": this.apiKey
2672
+ };
2673
+ const chatUrl = `${this.baseUrl}${API_CHATS_ENDPOINT}`;
2674
+ logger4.debug(`\u{1F4DD} Creating chat session for agent ${this.agentId}`);
2675
+ try {
2676
+ const response = await fetch(chatUrl, {
2677
+ method: "POST",
2678
+ headers,
2679
+ body: JSON.stringify(chatPayload)
2680
+ });
2681
+ if (!response.ok) {
2682
+ const responseText = await response.text();
2683
+ const statusCode = response.status;
2684
+ if (statusCode === 404) {
2685
+ throw new Error(
2686
+ `Agent not found: Agent '${this.agentId}' does not exist or you don't have access to it. Please verify the agent ID and ensure it exists in your account.`
2687
+ );
2688
+ }
2689
+ throw new Error(
2690
+ `Failed to create chat session: ${statusCode} - ${responseText}`
2691
+ );
2692
+ }
2693
+ const chatData = await response.json();
2694
+ const chatId = chatData.id;
2695
+ logger4.debug(`\u2705 Chat session created: ${chatId}`);
2696
+ return chatId;
2697
+ } catch (e) {
2698
+ if (e instanceof Error) {
2699
+ throw new TypeError(`Failed to create chat session: ${e.message}`);
2700
+ }
2701
+ throw new Error(`Failed to create chat session: ${String(e)}`);
2702
+ }
2703
+ }
2704
+ async run(queryOrOptions, maxSteps, manageConnector, externalHistory, outputSchema) {
2705
+ const {
2706
+ query,
2707
+ maxSteps: steps,
2708
+ externalHistory: history,
2709
+ outputSchema: schema
2710
+ } = normalizeRemoteRunOptions(
2711
+ queryOrOptions,
2712
+ maxSteps,
2713
+ manageConnector,
2714
+ externalHistory,
2715
+ outputSchema
2716
+ );
2717
+ if (history !== void 0) {
2718
+ logger4.warn("External history is not yet supported for remote execution");
2719
+ }
2720
+ try {
2721
+ logger4.debug(`\u{1F310} Executing query on remote agent ${this.agentId}`);
2722
+ if (this.chatId === null) {
2723
+ this.chatId = await this.createChatSession();
2724
+ }
2725
+ const chatId = this.chatId;
2726
+ const executionPayload = {
2727
+ query,
2728
+ max_steps: steps ?? 10
2729
+ };
2730
+ if (schema) {
2731
+ executionPayload.output_schema = this.pydanticToJsonSchema(schema);
2732
+ logger4.debug(`\u{1F527} Using structured output with schema`);
2733
+ }
2734
+ const headers = {
2735
+ "Content-Type": "application/json",
2736
+ "x-api-key": this.apiKey
2737
+ };
2738
+ const executionUrl = `${this.baseUrl}${API_CHAT_EXECUTE_ENDPOINT.replace("{chat_id}", chatId)}`;
2739
+ logger4.debug(`\u{1F680} Executing agent in chat ${chatId}`);
2740
+ const response = await fetch(executionUrl, {
2741
+ method: "POST",
2742
+ headers,
2743
+ body: JSON.stringify(executionPayload),
2744
+ signal: AbortSignal.timeout(3e5)
2745
+ // 5 minute timeout
2746
+ });
2747
+ if (!response.ok) {
2748
+ const responseText = await response.text();
2749
+ const statusCode = response.status;
2750
+ if (statusCode === 401) {
2751
+ logger4.error(`\u274C Authentication failed: ${responseText}`);
2752
+ throw new Error(
2753
+ "Authentication failed: Invalid or missing API key. Please check your API key and ensure the MCP_USE_API_KEY environment variable is set correctly."
2754
+ );
2755
+ } else if (statusCode === 403) {
2756
+ logger4.error(`\u274C Access forbidden: ${responseText}`);
2757
+ throw new Error(
2758
+ `Access denied: You don't have permission to execute agent '${this.agentId}'. Check if the agent exists and you have the necessary permissions.`
2759
+ );
2760
+ } else if (statusCode === 404) {
2761
+ logger4.error(`\u274C Agent not found: ${responseText}`);
2762
+ throw new Error(
2763
+ `Agent not found: Agent '${this.agentId}' does not exist or you don't have access to it. Please verify the agent ID and ensure it exists in your account.`
2764
+ );
2765
+ } else if (statusCode === 422) {
2766
+ logger4.error(`\u274C Validation error: ${responseText}`);
2767
+ throw new Error(
2768
+ `Request validation failed: ${responseText}. Please check your query parameters and output schema format.`
2769
+ );
2770
+ } else if (statusCode === 500) {
2771
+ logger4.error(`\u274C Server error: ${responseText}`);
2772
+ throw new Error(
2773
+ "Internal server error occurred during agent execution. Please try again later or contact support if the issue persists."
2774
+ );
2775
+ } else {
2776
+ logger4.error(
2777
+ `\u274C Remote execution failed with status ${statusCode}: ${responseText}`
2778
+ );
2779
+ throw new Error(
2780
+ `Remote agent execution failed: ${statusCode} - ${responseText}`
2781
+ );
2782
+ }
2783
+ }
2784
+ const result = await response.json();
2785
+ logger4.debug(`\u{1F527} Response: ${JSON.stringify(result)}`);
2786
+ logger4.debug("\u2705 Remote execution completed successfully");
2787
+ if (typeof result === "object" && result !== null) {
2788
+ if (result.status === "error" || result.error !== null) {
2789
+ const errorMsg = result.error ?? String(result);
2790
+ logger4.error(`\u274C Remote agent execution failed: ${errorMsg}`);
2791
+ throw new Error(`Remote agent execution failed: ${errorMsg}`);
2792
+ }
2793
+ if (String(result).includes("failed to initialize")) {
2794
+ logger4.error(`\u274C Agent initialization failed: ${result}`);
2795
+ throw new Error(
2796
+ `Agent initialization failed on remote server. This usually indicates:
2797
+ \u2022 Invalid agent configuration (LLM model, system prompt)
2798
+ \u2022 Missing or invalid MCP server configurations
2799
+ \u2022 Network connectivity issues with MCP servers
2800
+ \u2022 Missing environment variables or credentials
2801
+ Raw error: ${result}`
2802
+ );
2803
+ }
2804
+ }
2805
+ if (schema) {
2806
+ return this.parseStructuredResponse(result, schema);
2807
+ }
2808
+ if (typeof result === "object" && result !== null && "result" in result) {
2809
+ return result.result;
2810
+ } else if (typeof result === "string") {
2811
+ return result;
2812
+ } else {
2813
+ return String(result);
2814
+ }
2815
+ } catch (e) {
2816
+ if (e instanceof Error) {
2817
+ if (e.name === "AbortError") {
2818
+ logger4.error(`\u274C Remote execution timed out: ${e}`);
2819
+ throw new Error(
2820
+ "Remote agent execution timed out. The server may be overloaded or the query is taking too long to process. Try again or use a simpler query."
2821
+ );
2822
+ }
2823
+ logger4.error(`\u274C Remote execution error: ${e}`);
2824
+ throw new Error(`Remote agent execution failed: ${e.message}`);
2825
+ }
2826
+ logger4.error(`\u274C Remote execution error: ${e}`);
2827
+ throw new Error(`Remote agent execution failed: ${String(e)}`);
2828
+ }
2829
+ }
2830
+ // eslint-disable-next-line require-yield
2831
+ async *stream(queryOrOptions, maxSteps, manageConnector, externalHistory, outputSchema) {
2832
+ const result = await this.run(
2833
+ queryOrOptions,
2834
+ maxSteps,
2835
+ manageConnector,
2836
+ externalHistory,
2837
+ outputSchema
2838
+ );
2839
+ return result;
2840
+ }
2841
+ async close() {
2842
+ logger4.debug("\u{1F50C} Remote agent client closed");
2843
+ }
2844
+ };
2845
+
2846
+ // src/agents/mcp_agent.ts
2847
+ var MCPAgent = class {
2848
+ static getPackageVersion() {
2849
+ return getPackageVersion();
2850
+ }
2851
+ driver;
2852
+ client;
2853
+ connectors = [];
2854
+ clientOwnedByAgent = false;
2855
+ nativeAdapter;
2856
+ providerTools = [];
2857
+ callTool;
2858
+ maxSteps;
2859
+ autoInitialize;
2860
+ systemPrompt;
2861
+ disallowedTools;
2862
+ exposeResourcesAsTools;
2863
+ exposePromptsAsTools;
2864
+ initialized = false;
2865
+ isRemote = false;
2866
+ remoteAgent = null;
2867
+ isSimplifiedMode = false;
2868
+ llmString;
2869
+ llmConfig;
2870
+ mcpServersConfig;
2871
+ explicitProviderConfig;
2872
+ conversationMessages = [];
2873
+ memoryEnabled;
2874
+ boundConnections;
2875
+ constructor(options) {
2876
+ if (options.agentId) {
2877
+ this.isRemote = true;
2878
+ this.remoteAgent = new RemoteAgent({
2879
+ agentId: options.agentId,
2880
+ apiKey: options.apiKey,
2881
+ baseUrl: options.baseUrl
2882
+ });
2883
+ this.maxSteps = options.maxSteps ?? 10;
2884
+ this.autoInitialize = options.autoInitialize ?? false;
2885
+ this.nativeAdapter = new NativeAdapter();
2886
+ this.systemPrompt = options.systemPrompt ?? "You are a helpful assistant with access to MCP tools.";
2887
+ this.disallowedTools = [];
2888
+ this.exposeResourcesAsTools = true;
2889
+ this.exposePromptsAsTools = true;
2890
+ this.memoryEnabled = options.memoryEnabled ?? true;
2891
+ return;
2892
+ }
2893
+ this.maxSteps = options.maxSteps ?? 10;
2894
+ this.autoInitialize = options.autoInitialize ?? false;
2895
+ this.systemPrompt = options.systemPrompt ?? "You are a helpful assistant with access to MCP tools.";
2896
+ this.disallowedTools = options.disallowedTools ?? [];
2897
+ this.exposeResourcesAsTools = options.exposeResourcesAsTools ?? true;
2898
+ this.exposePromptsAsTools = options.exposePromptsAsTools ?? true;
2899
+ this.memoryEnabled = options.memoryEnabled ?? true;
2900
+ this.nativeAdapter = new NativeAdapter(this.disallowedTools);
2901
+ this.llmConfig = options.llmConfig;
2902
+ this.resolveMcpServers(options.mcpServers);
2903
+ if (typeof options.llm === "string") {
2904
+ this.isSimplifiedMode = true;
2905
+ this.llmString = options.llm;
2906
+ if (!this.hasLiveConnections() && (!this.mcpServersConfig || Object.keys(this.mcpServersConfig).length === 0) && !options.client && !options.connectors?.length) {
2907
+ throw new Error(
2908
+ "Simplified mode requires mcpServers, or an existing client/connectors."
2909
+ );
2910
+ }
2911
+ } else {
2912
+ this.explicitProviderConfig = options.llm;
2913
+ this.client = options.client;
2914
+ this.connectors = options.connectors ?? [];
2915
+ if (!this.hasLiveConnections() && !this.client && this.connectors.length === 0 && (!this.mcpServersConfig || Object.keys(this.mcpServersConfig).length === 0)) {
2916
+ throw new Error(
2917
+ "Explicit mode requires mcpServers, client, or connectors."
2918
+ );
2919
+ }
2920
+ }
2921
+ if (options.client) this.client = options.client;
2922
+ if (options.connectors?.length) this.connectors = options.connectors;
2923
+ if (this.hasLiveConnections() && this.explicitProviderConfig) {
2924
+ this.bindConnections(this.boundConnections, this.explicitProviderConfig);
2925
+ } else if (this.hasLiveConnections() && this.llmString) {
2926
+ this.driver = createLlmDriver(
2927
+ parseLLMStringToProviderConfig(this.llmString, this.llmConfig)
2928
+ );
2929
+ this.bindConnections(
2930
+ this.boundConnections,
2931
+ parseLLMStringToProviderConfig(this.llmString, this.llmConfig)
2932
+ );
2933
+ }
2934
+ }
2935
+ resolveMcpServers(mcpServers) {
2936
+ if (!mcpServers) return;
2937
+ if (Array.isArray(mcpServers)) {
2938
+ this.boundConnections = mcpServers;
2939
+ return;
2940
+ }
2941
+ this.mcpServersConfig = mcpServers;
2942
+ }
2943
+ hasLiveConnections() {
2944
+ return (this.boundConnections?.length ?? 0) > 0;
2945
+ }
2946
+ async initialize() {
2947
+ if (this.isRemote) {
2948
+ this.initialized = true;
2949
+ return;
2950
+ }
2951
+ if (this.initialized) return;
2952
+ if (this.isSimplifiedMode) {
2953
+ if (!this.client && this.mcpServersConfig) {
2954
+ const { MCPClient } = await import("@mcp-use/client");
2955
+ this.client = new MCPClient({ mcpServers: this.mcpServersConfig });
2956
+ this.clientOwnedByAgent = true;
2957
+ }
2958
+ if (this.llmString) {
2959
+ this.driver = createLlmDriver(
2960
+ parseLLMStringToProviderConfig(this.llmString, this.llmConfig)
2961
+ );
2962
+ }
2963
+ } else if (this.explicitProviderConfig) {
2964
+ this.driver = createLlmDriver(this.explicitProviderConfig);
2965
+ }
2966
+ if (!this.driver) {
2967
+ throw new Error("LLM driver not configured.");
2968
+ }
2969
+ if (!this.hasLiveConnections()) {
2970
+ await this.loadTools();
2971
+ }
2972
+ this.initialized = true;
2973
+ logger5.debug("MCPAgent initialized");
2974
+ }
2975
+ async loadTools() {
2976
+ const entries = [];
2977
+ if (this.client) {
2978
+ if (!this.client.activeSessions || Object.keys(this.client.activeSessions).length === 0) {
2979
+ await this.client.createAllSessions();
2980
+ }
2981
+ const sessions = this.client.getAllActiveSessions();
2982
+ const connectors = Object.values(sessions).map((s) => s.connector);
2983
+ entries.push(
2984
+ ...await this.nativeAdapter.createToolsFromConnectors(connectors)
2985
+ );
2986
+ if (this.exposeResourcesAsTools) {
2987
+ entries.push(
2988
+ ...await this.nativeAdapter.createResourcesFromConnectors(
2989
+ connectors
2990
+ )
2991
+ );
2992
+ }
2993
+ if (this.exposePromptsAsTools) {
2994
+ entries.push(
2995
+ ...await this.nativeAdapter.createPromptsFromConnectors(connectors)
2996
+ );
2997
+ }
2998
+ } else {
2999
+ for (const connector of this.connectors) {
3000
+ if (!connector.isClientConnected) await connector.connect();
3001
+ }
3002
+ entries.push(
3003
+ ...await this.nativeAdapter.createToolsFromConnectors(this.connectors)
3004
+ );
3005
+ if (this.exposeResourcesAsTools) {
3006
+ entries.push(
3007
+ ...await this.nativeAdapter.createResourcesFromConnectors(
3008
+ this.connectors
3009
+ )
3010
+ );
3011
+ }
3012
+ if (this.exposePromptsAsTools) {
3013
+ entries.push(
3014
+ ...await this.nativeAdapter.createPromptsFromConnectors(
3015
+ this.connectors
3016
+ )
3017
+ );
3018
+ }
3019
+ }
3020
+ this.providerTools = this.nativeAdapter.toProviderTools(entries);
3021
+ this.callTool = this.nativeAdapter.createCallTool();
3022
+ }
3023
+ bindConnections(connections, providerConfig) {
3024
+ const disallowed = new Set(this.disallowedTools);
3025
+ const usedNames = /* @__PURE__ */ new Set();
3026
+ const routes = /* @__PURE__ */ new Map();
3027
+ const reserveName = (name) => {
3028
+ if (!usedNames.has(name)) {
3029
+ usedNames.add(name);
3030
+ return name;
3031
+ }
3032
+ let i = 2;
3033
+ while (usedNames.has(`${name}_${i}`)) i++;
3034
+ const fallback = `${name}_${i}`;
3035
+ usedNames.add(fallback);
3036
+ return fallback;
3037
+ };
3038
+ const providerTools = [];
3039
+ for (const connection of connections) {
3040
+ for (const tool of connection.tools ?? []) {
3041
+ if (disallowed.has(tool.name)) continue;
3042
+ const name = reserveName(tool.name);
3043
+ routes.set(name, { connection, mcpName: tool.name });
3044
+ providerTools.push({
3045
+ name,
3046
+ description: tool.description,
3047
+ inputSchema: tool.inputSchema ?? {
3048
+ type: "object",
3049
+ properties: {}
3050
+ }
3051
+ });
3052
+ }
3053
+ }
3054
+ this.providerTools = providerTools;
3055
+ this.callTool = async (name, args) => {
3056
+ const route = routes.get(name);
3057
+ if (!route) {
3058
+ throw new Error(`Unknown tool: ${name}`);
3059
+ }
3060
+ return route.connection.callTool(route.mcpName, args);
3061
+ };
3062
+ this.driver = createLlmDriver(providerConfig);
3063
+ this.initialized = true;
3064
+ }
3065
+ buildMessages(options) {
3066
+ const messages = [
3067
+ { role: "system", content: this.systemPrompt }
3068
+ ];
3069
+ if (this.memoryEnabled && this.conversationMessages.length > 0) {
3070
+ messages.push(...this.conversationMessages);
3071
+ }
3072
+ if (options.messages?.length) {
3073
+ messages.push(...options.messages);
3074
+ }
3075
+ if (options.prompt) {
3076
+ messages.push({ role: "user", content: options.prompt });
3077
+ }
3078
+ return messages;
3079
+ }
3080
+ getConversationHistory() {
3081
+ return [...this.conversationMessages];
3082
+ }
3083
+ clearConversationHistory() {
3084
+ this.conversationMessages = [];
3085
+ }
3086
+ setSystemMessage(message) {
3087
+ this.systemPrompt = message;
3088
+ }
3089
+ async ensureReady(manageConnector = true) {
3090
+ if (manageConnector && !this.initialized) {
3091
+ if (this.autoInitialize) {
3092
+ await this.initialize();
3093
+ } else {
3094
+ throw new Error("MCPAgent not initialized. Call initialize() first.");
3095
+ }
3096
+ }
3097
+ if (!this.driver || !this.callTool) {
3098
+ throw new Error("MCPAgent driver or tools not ready.");
3099
+ }
3100
+ }
3101
+ nativeRunParams(options) {
3102
+ return {
3103
+ messages: this.buildMessages(options),
3104
+ tools: this.providerTools,
3105
+ callTool: this.callTool,
3106
+ maxSteps: options.maxSteps ?? this.maxSteps,
3107
+ signal: options.signal
3108
+ };
3109
+ }
3110
+ async run(queryOrOptions, maxSteps, manageConnector, externalHistory, outputSchema, signal) {
3111
+ const options = normalizeRunOptions(
3112
+ queryOrOptions,
3113
+ maxSteps,
3114
+ manageConnector,
3115
+ externalHistory,
3116
+ outputSchema,
3117
+ signal
3118
+ );
3119
+ if (options.schema) {
3120
+ throw new Error(
3121
+ "Structured output requires @mcp-use/agent/langchain or pass a JSON schema via prompt."
3122
+ );
3123
+ }
3124
+ if (this.isRemote && this.remoteAgent) {
3125
+ return this.remoteAgent.run(
3126
+ options.prompt ?? "",
3127
+ options.maxSteps,
3128
+ options.manageConnector
3129
+ );
3130
+ }
3131
+ await this.ensureReady(options.manageConnector ?? true);
3132
+ const result = await runNativeAgent(
3133
+ this.driver,
3134
+ this.nativeRunParams(options)
3135
+ );
3136
+ if (this.memoryEnabled && options.prompt) {
3137
+ this.conversationMessages.push({
3138
+ role: "user",
3139
+ content: options.prompt
3140
+ });
3141
+ this.conversationMessages.push({
3142
+ role: "assistant",
3143
+ content: result
3144
+ });
3145
+ }
3146
+ return result;
3147
+ }
3148
+ async *stream(queryOrOptions, maxSteps, manageConnector, externalHistory, outputSchema, signal) {
3149
+ const options = normalizeRunOptions(
3150
+ queryOrOptions,
3151
+ maxSteps,
3152
+ manageConnector,
3153
+ externalHistory,
3154
+ outputSchema,
3155
+ signal
3156
+ );
3157
+ if (this.isRemote && this.remoteAgent) {
3158
+ const result2 = await this.remoteAgent.run(
3159
+ options.prompt ?? "",
3160
+ options.maxSteps,
3161
+ options.manageConnector
3162
+ );
3163
+ return result2;
3164
+ }
3165
+ await this.ensureReady(options.manageConnector ?? true);
3166
+ const result = yield* streamNativeAgentSteps(
3167
+ this.driver,
3168
+ this.nativeRunParams(options)
3169
+ );
3170
+ if (this.memoryEnabled && options.prompt) {
3171
+ this.conversationMessages.push({
3172
+ role: "user",
3173
+ content: options.prompt
3174
+ });
3175
+ this.conversationMessages.push({
3176
+ role: "assistant",
3177
+ content: result
3178
+ });
3179
+ }
3180
+ return result;
3181
+ }
3182
+ async *streamEvents(queryOrOptions, maxSteps, manageConnector, externalHistory, outputSchema, signal) {
3183
+ const options = normalizeRunOptions(
3184
+ queryOrOptions,
3185
+ maxSteps,
3186
+ manageConnector,
3187
+ externalHistory,
3188
+ outputSchema,
3189
+ signal
3190
+ );
3191
+ if (this.isRemote && this.remoteAgent) {
3192
+ throw new Error("streamEvents is not supported for remote agents.");
3193
+ }
3194
+ await this.ensureReady(options.manageConnector ?? true);
3195
+ yield* streamNativeAgent(this.driver, this.nativeRunParams(options));
3196
+ }
3197
+ /** Single-shot completion without tools (sampling, props generation). */
3198
+ async chat(options) {
3199
+ await this.ensureReady();
3200
+ const result = await this.driver.complete({
3201
+ messages: options.messages,
3202
+ tools: [],
3203
+ signal: options.signal
3204
+ });
3205
+ return result.text;
3206
+ }
3207
+ async close() {
3208
+ if (this.clientOwnedByAgent && this.client) {
3209
+ await this.client.closeAllSessions?.();
3210
+ }
3211
+ this.initialized = false;
3212
+ }
3213
+ };
3214
+
3215
+ // src/llm/chat.ts
3216
+ async function completeChat(params) {
3217
+ const driver = createLlmDriver(params.config);
3218
+ const result = await driver.complete({
3219
+ messages: params.messages,
3220
+ tools: [],
3221
+ signal: params.signal
3222
+ });
3223
+ return result.text;
3224
+ }
3225
+
3226
+ // src/agents/prompts/index.ts
3227
+ var CODE_MODE_PROMPT = "Use code execution mode to discover and call MCP tools programmatically.";
3228
+ var PROMPTS = {
3229
+ CODE_MODE: CODE_MODE_PROMPT
3230
+ };
3231
+ export {
3232
+ BaseAdapter,
3233
+ DEFAULT_OLLAMA_BASE_URL,
3234
+ LlmRequestError,
3235
+ MCPAgent,
3236
+ NativeAdapter,
3237
+ OllamaCorsError,
3238
+ PROMPTS,
3239
+ RemoteAgent,
3240
+ buildOllamaApiUrl,
3241
+ completeChat as chat,
3242
+ completeChat,
3243
+ convertMessagesToProvider,
3244
+ normalizeOllamaBaseUrl,
3245
+ parseLLMStringToProviderConfig,
3246
+ providerConfigFromOptions
3247
+ };
3248
+ //# sourceMappingURL=index.js.map