mcp-use 0.1.7 → 0.1.9

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 (35) hide show
  1. package/README.md +196 -0
  2. package/dist/examples/ai_sdk_example.d.ts +23 -0
  3. package/dist/examples/ai_sdk_example.d.ts.map +1 -0
  4. package/dist/examples/ai_sdk_example.js +213 -0
  5. package/dist/examples/stream_example.d.ts +12 -0
  6. package/dist/examples/stream_example.d.ts.map +1 -0
  7. package/dist/examples/stream_example.js +198 -0
  8. package/dist/examples/structured_output.d.ts +9 -0
  9. package/dist/examples/structured_output.d.ts.map +1 -0
  10. package/dist/examples/structured_output.js +95 -0
  11. package/dist/index.d.ts +2 -0
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +2 -0
  14. package/dist/src/agents/mcp_agent.d.ts +24 -4
  15. package/dist/src/agents/mcp_agent.d.ts.map +1 -1
  16. package/dist/src/agents/mcp_agent.js +355 -50
  17. package/dist/src/agents/utils/ai_sdk.d.ts +22 -0
  18. package/dist/src/agents/utils/ai_sdk.d.ts.map +1 -0
  19. package/dist/src/agents/utils/ai_sdk.js +62 -0
  20. package/dist/src/agents/utils/index.d.ts +2 -0
  21. package/dist/src/agents/utils/index.d.ts.map +1 -0
  22. package/dist/src/agents/utils/index.js +1 -0
  23. package/dist/tests/ai_sdk_compatibility.test.d.ts +13 -0
  24. package/dist/tests/ai_sdk_compatibility.test.d.ts.map +1 -0
  25. package/dist/tests/ai_sdk_compatibility.test.js +214 -0
  26. package/dist/tests/stream_events.test.d.ts +2 -0
  27. package/dist/tests/stream_events.test.d.ts.map +1 -0
  28. package/dist/tests/stream_events.test.js +306 -0
  29. package/dist/tests/stream_events_simple.test.d.ts +7 -0
  30. package/dist/tests/stream_events_simple.test.d.ts.map +1 -0
  31. package/dist/tests/stream_events_simple.test.js +179 -0
  32. package/dist/vitest.config.d.ts +3 -0
  33. package/dist/vitest.config.d.ts.map +1 -0
  34. package/dist/vitest.config.js +21 -0
  35. package/package.json +16 -5
@@ -22,12 +22,12 @@ export class MCPAgent {
22
22
  systemPrompt;
23
23
  systemPromptTemplateOverride;
24
24
  additionalInstructions;
25
- initialized = false;
25
+ _initialized = false;
26
26
  conversationHistory = [];
27
- agentExecutor = null;
27
+ _agentExecutor = null;
28
28
  sessions = {};
29
29
  systemMessage = null;
30
- tools = [];
30
+ _tools = [];
31
31
  adapter;
32
32
  serverManager = null;
33
33
  telemetry;
@@ -67,6 +67,19 @@ export class MCPAgent {
67
67
  const [provider, name] = extractModelInfo(this.llm);
68
68
  this.modelProvider = provider;
69
69
  this.modelName = name;
70
+ // Make getters configurable for test mocking
71
+ Object.defineProperty(this, 'agentExecutor', {
72
+ get: () => this._agentExecutor,
73
+ configurable: true,
74
+ });
75
+ Object.defineProperty(this, 'tools', {
76
+ get: () => this._tools,
77
+ configurable: true,
78
+ });
79
+ Object.defineProperty(this, 'initialized', {
80
+ get: () => this._initialized,
81
+ configurable: true,
82
+ });
70
83
  }
71
84
  async initialize() {
72
85
  logger.info('šŸš€ Initializing MCP agent and connecting to services...');
@@ -75,11 +88,11 @@ export class MCPAgent {
75
88
  await this.serverManager.initialize();
76
89
  // Get server management tools
77
90
  const managementTools = this.serverManager.tools;
78
- this.tools = managementTools;
79
- this.tools.push(...this.additionalTools);
91
+ this._tools = managementTools;
92
+ this._tools.push(...this.additionalTools);
80
93
  logger.info(`šŸ”§ Server manager mode active with ${managementTools.length} management tools`);
81
94
  // Create the system message based on available tools
82
- await this.createSystemMessageFromTools(this.tools);
95
+ await this.createSystemMessageFromTools(this._tools);
83
96
  }
84
97
  else {
85
98
  // Standard initialization - if using client, get or create sessions
@@ -94,9 +107,9 @@ export class MCPAgent {
94
107
  logger.info(`āœ… Created ${Object.keys(this.sessions).length} new sessions`);
95
108
  }
96
109
  // Create LangChain tools directly from the client using the adapter
97
- this.tools = await LangChainAdapter.createTools(this.client);
98
- this.tools.push(...this.additionalTools);
99
- logger.info(`šŸ› ļø Created ${this.tools.length} LangChain tools from client`);
110
+ this._tools = await LangChainAdapter.createTools(this.client);
111
+ this._tools.push(...this.additionalTools);
112
+ logger.info(`šŸ› ļø Created ${this._tools.length} LangChain tools from client`);
100
113
  }
101
114
  else {
102
115
  // Using direct connector - only establish connection
@@ -107,18 +120,18 @@ export class MCPAgent {
107
120
  }
108
121
  }
109
122
  // Create LangChain tools using the adapter with connectors
110
- this.tools = await this.adapter.createToolsFromConnectors(this.connectors);
111
- this.tools.push(...this.additionalTools);
112
- logger.info(`šŸ› ļø Created ${this.tools.length} LangChain tools from connectors`);
123
+ this._tools = await this.adapter.createToolsFromConnectors(this.connectors);
124
+ this._tools.push(...this.additionalTools);
125
+ logger.info(`šŸ› ļø Created ${this._tools.length} LangChain tools from connectors`);
113
126
  }
114
127
  // Get all tools for system message generation
115
- logger.info(`🧰 Found ${this.tools.length} tools across all connectors`);
128
+ logger.info(`🧰 Found ${this._tools.length} tools across all connectors`);
116
129
  // Create the system message based on available tools
117
- await this.createSystemMessageFromTools(this.tools);
130
+ await this.createSystemMessageFromTools(this._tools);
118
131
  }
119
132
  // Create the agent executor and mark initialized
120
- this.agentExecutor = this.createAgent();
121
- this.initialized = true;
133
+ this._agentExecutor = this.createAgent();
134
+ this._initialized = true;
122
135
  logger.info('✨ Agent initialization complete');
123
136
  }
124
137
  async createSystemMessageFromTools(tools) {
@@ -142,12 +155,12 @@ export class MCPAgent {
142
155
  ]);
143
156
  const agent = createToolCallingAgent({
144
157
  llm: this.llm,
145
- tools: this.tools,
158
+ tools: this._tools,
146
159
  prompt,
147
160
  });
148
161
  return new AgentExecutor({
149
162
  agent,
150
- tools: this.tools,
163
+ tools: this._tools,
151
164
  maxIterations: this.maxSteps,
152
165
  verbose: this.verbose,
153
166
  returnIntermediateSteps: true,
@@ -172,15 +185,15 @@ export class MCPAgent {
172
185
  this.conversationHistory = this.conversationHistory.filter(m => !(m instanceof SystemMessage));
173
186
  this.conversationHistory.unshift(this.systemMessage);
174
187
  }
175
- if (this.initialized && this.tools.length) {
176
- this.agentExecutor = this.createAgent();
188
+ if (this._initialized && this._tools.length) {
189
+ this._agentExecutor = this.createAgent();
177
190
  logger.debug('Agent recreated with new system message');
178
191
  }
179
192
  }
180
193
  setDisallowedTools(disallowedTools) {
181
194
  this.disallowedTools = disallowedTools;
182
195
  this.adapter = new LangChainAdapter(this.disallowedTools);
183
- if (this.initialized) {
196
+ if (this._initialized) {
184
197
  logger.debug('Agent already initialized. Changes will take effect on next initialization.');
185
198
  }
186
199
  }
@@ -198,37 +211,68 @@ export class MCPAgent {
198
211
  }
199
212
  }
200
213
  }
201
- /**
202
- * Runs the agent and returns a promise for the final result.
203
- */
204
- async run(query, maxSteps, manageConnector, externalHistory) {
205
- const generator = this.stream(query, maxSteps, manageConnector, externalHistory);
214
+ async run(query, maxSteps, manageConnector, externalHistory, outputSchema) {
215
+ const generator = this.stream(query, maxSteps, manageConnector, externalHistory, outputSchema);
206
216
  return this._consumeAndReturn(generator);
207
217
  }
208
218
  /**
209
219
  * Runs the agent and yields intermediate steps as an async generator.
220
+ * If outputSchema is provided, returns structured output of type T.
210
221
  */
211
- async *stream(query, maxSteps, manageConnector = true, externalHistory) {
222
+ async *stream(query, maxSteps, manageConnector = true, externalHistory, outputSchema) {
212
223
  let result = '';
213
224
  let initializedHere = false;
214
225
  const startTime = Date.now();
215
226
  const toolsUsedNames = [];
216
227
  let stepsTaken = 0;
217
228
  let success = false;
229
+ // Schema-aware setup for structured output
230
+ let structuredLlm = null;
231
+ let schemaDescription = '';
232
+ if (outputSchema) {
233
+ query = this._enhanceQueryWithSchema(query, outputSchema);
234
+ // Check if withStructuredOutput method exists
235
+ if ('withStructuredOutput' in this.llm && typeof this.llm.withStructuredOutput === 'function') {
236
+ structuredLlm = this.llm.withStructuredOutput(outputSchema);
237
+ }
238
+ else {
239
+ // Fallback: use the same LLM but we'll handle structure in our helper method
240
+ structuredLlm = this.llm;
241
+ }
242
+ // Get schema description for feedback
243
+ try {
244
+ const schemaType = outputSchema;
245
+ if (schemaType._def && schemaType._def.shape) {
246
+ const fields = [];
247
+ for (const [key, fieldSchema] of Object.entries(schemaType._def.shape)) {
248
+ const field = fieldSchema;
249
+ const isOptional = field.isOptional?.() ?? field._def?.typeName === 'ZodOptional';
250
+ const isNullable = field.isNullable?.() ?? field._def?.typeName === 'ZodNullable';
251
+ const description = field._def?.description || field.description || key;
252
+ fields.push(`- ${key}: ${description} ${(isOptional || isNullable) ? '(optional)' : '(required)'}`);
253
+ }
254
+ schemaDescription = fields.join('\n');
255
+ }
256
+ }
257
+ catch (e) {
258
+ logger.warn(`Could not extract schema details: ${e}`);
259
+ schemaDescription = `Schema: ${outputSchema.constructor.name}`;
260
+ }
261
+ }
218
262
  try {
219
- if (manageConnector && !this.initialized) {
263
+ if (manageConnector && !this._initialized) {
220
264
  await this.initialize();
221
265
  initializedHere = true;
222
266
  }
223
- else if (!this.initialized && this.autoInitialize) {
267
+ else if (!this._initialized && this.autoInitialize) {
224
268
  await this.initialize();
225
269
  initializedHere = true;
226
270
  }
227
- if (!this.agentExecutor) {
271
+ if (!this._agentExecutor) {
228
272
  throw new Error('MCP agent failed to initialize');
229
273
  }
230
274
  const steps = maxSteps ?? this.maxSteps;
231
- this.agentExecutor.maxIterations = steps;
275
+ this._agentExecutor.maxIterations = steps;
232
276
  const display_query = query.length > 50 ? `${query.slice(0, 50).replace(/\n/g, ' ')}...` : query.replace(/\n/g, ' ');
233
277
  logger.info(`šŸ’¬ Received query: '${display_query}'`);
234
278
  // —–– Record user message
@@ -244,34 +288,73 @@ export class MCPAgent {
244
288
  }
245
289
  const intermediateSteps = [];
246
290
  const inputs = { input: query, chat_history: langchainHistory };
247
- let nameToToolMap = Object.fromEntries(this.tools.map(t => [t.name, t]));
291
+ let nameToToolMap = Object.fromEntries(this._tools.map(t => [t.name, t]));
248
292
  logger.info(`šŸ Starting agent execution with max_steps=${steps}`);
249
293
  for (let stepNum = 0; stepNum < steps; stepNum++) {
250
294
  stepsTaken = stepNum + 1;
251
295
  if (this.useServerManager && this.serverManager) {
252
296
  const currentTools = this.serverManager.tools;
253
297
  const currentToolNames = new Set(currentTools.map(t => t.name));
254
- const existingToolNames = new Set(this.tools.map(t => t.name));
255
- const changed = currentTools.length !== this.tools.length
298
+ const existingToolNames = new Set(this._tools.map(t => t.name));
299
+ const changed = currentTools.length !== this._tools.length
256
300
  || [...currentToolNames].some(n => !existingToolNames.has(n));
257
301
  if (changed) {
258
302
  logger.info(`šŸ”„ Tools changed before step ${stepNum + 1}, updating agent. New tools: ${[...currentToolNames].join(', ')}`);
259
- this.tools = currentTools;
260
- this.tools.push(...this.additionalTools);
261
- await this.createSystemMessageFromTools(this.tools);
262
- this.agentExecutor = this.createAgent();
263
- this.agentExecutor.maxIterations = steps;
264
- nameToToolMap = Object.fromEntries(this.tools.map(t => [t.name, t]));
303
+ this._tools = currentTools;
304
+ this._tools.push(...this.additionalTools);
305
+ await this.createSystemMessageFromTools(this._tools);
306
+ this._agentExecutor = this.createAgent();
307
+ this._agentExecutor.maxIterations = steps;
308
+ nameToToolMap = Object.fromEntries(this._tools.map(t => [t.name, t]));
265
309
  }
266
310
  }
267
311
  logger.info(`šŸ‘£ Step ${stepNum + 1}/${steps}`);
268
312
  try {
269
313
  logger.debug('Starting agent step execution');
270
- const nextStepOutput = await this.agentExecutor._takeNextStep(nameToToolMap, inputs, intermediateSteps);
314
+ const nextStepOutput = await this._agentExecutor._takeNextStep(nameToToolMap, inputs, intermediateSteps);
271
315
  if (nextStepOutput.returnValues) {
272
316
  logger.info(`āœ… Agent finished at step ${stepNum + 1}`);
273
317
  result = nextStepOutput.returnValues?.output ?? 'No output generated';
274
- break;
318
+ // If structured output is requested, attempt to create it
319
+ if (outputSchema && structuredLlm) {
320
+ try {
321
+ logger.info('šŸ”§ Attempting structured output...');
322
+ const structuredResult = await this._attemptStructuredOutput(result, structuredLlm, outputSchema, schemaDescription);
323
+ // Add the final response to conversation history if memory is enabled
324
+ if (this.memoryEnabled) {
325
+ this.addToHistory(new AIMessage(`Structured result: ${JSON.stringify(structuredResult)}`));
326
+ }
327
+ logger.info('āœ… Structured output successful');
328
+ success = true;
329
+ return structuredResult;
330
+ }
331
+ catch (e) {
332
+ logger.warn(`āš ļø Structured output failed: ${e}`);
333
+ // Continue execution to gather missing information
334
+ const missingInfoPrompt = `
335
+ The current result cannot be formatted into the required structure.
336
+ Error: ${String(e)}
337
+
338
+ Current information: ${result}
339
+
340
+ Please continue working to gather the missing information needed for:
341
+ ${schemaDescription}
342
+
343
+ Focus on finding the specific missing details.
344
+ `;
345
+ // Add this as feedback and continue the loop
346
+ inputs.input = missingInfoPrompt;
347
+ if (this.memoryEnabled) {
348
+ this.addToHistory(new HumanMessage(missingInfoPrompt));
349
+ }
350
+ logger.info('šŸ”„ Continuing execution to gather missing information...');
351
+ continue;
352
+ }
353
+ }
354
+ else {
355
+ // Regular execution without structured output
356
+ break;
357
+ }
275
358
  }
276
359
  const stepArray = nextStepOutput;
277
360
  intermediateSteps.push(...stepArray);
@@ -280,7 +363,9 @@ export class MCPAgent {
280
363
  const { action, observation } = step;
281
364
  const toolName = action.tool;
282
365
  toolsUsedNames.push(toolName);
283
- let toolInputStr = String(action.toolInput);
366
+ let toolInputStr = typeof action.toolInput === 'string'
367
+ ? action.toolInput
368
+ : JSON.stringify(action.toolInput, null, 2);
284
369
  if (toolInputStr.length > 100)
285
370
  toolInputStr = `${toolInputStr.slice(0, 97)}...`;
286
371
  logger.info(`šŸ”§ Tool call: ${toolName} with input: ${toolInputStr}`);
@@ -293,7 +378,7 @@ export class MCPAgent {
293
378
  // Detect direct return
294
379
  if (stepArray.length) {
295
380
  const lastStep = stepArray[stepArray.length - 1];
296
- const toolReturn = await this.agentExecutor._getToolReturn(lastStep);
381
+ const toolReturn = await this._agentExecutor._getToolReturn(lastStep);
297
382
  if (toolReturn) {
298
383
  logger.info(`šŸ† Tool returned directly at step ${stepNum + 1}`);
299
384
  result = toolReturn.returnValues?.output ?? 'No output generated';
@@ -318,11 +403,31 @@ export class MCPAgent {
318
403
  logger.warn(`āš ļø Agent stopped after reaching max iterations (${steps})`);
319
404
  result = `Agent stopped after reaching the maximum number of steps (${steps}).`;
320
405
  }
321
- if (this.memoryEnabled) {
406
+ // If structured output was requested but not achieved, attempt one final time
407
+ if (outputSchema && structuredLlm && !success) {
408
+ try {
409
+ logger.info('šŸ”§ Final attempt at structured output...');
410
+ const structuredResult = await this._attemptStructuredOutput(result, structuredLlm, outputSchema, schemaDescription);
411
+ // Add the final response to conversation history if memory is enabled
412
+ if (this.memoryEnabled) {
413
+ this.addToHistory(new AIMessage(`Structured result: ${JSON.stringify(structuredResult)}`));
414
+ }
415
+ logger.info('āœ… Final structured output successful');
416
+ success = true;
417
+ return structuredResult;
418
+ }
419
+ catch (e) {
420
+ logger.error(`āŒ Final structured output attempt failed: ${e}`);
421
+ throw new Error(`Failed to generate structured output after ${steps} steps: ${e}`);
422
+ }
423
+ }
424
+ // Add the final response to conversation history if memory is enabled (regular case)
425
+ if (this.memoryEnabled && !outputSchema) {
322
426
  this.addToHistory(new AIMessage(result));
323
427
  }
324
428
  logger.info('šŸŽ‰ Agent execution complete');
325
429
  success = true;
430
+ // Return regular result
326
431
  return result;
327
432
  }
328
433
  catch (e) {
@@ -352,8 +457,8 @@ export class MCPAgent {
352
457
  modelName: this.modelName,
353
458
  serverCount,
354
459
  serverIdentifiers: this.connectors.map(connector => connector.publicIdentifier),
355
- totalToolsAvailable: this.tools.length,
356
- toolsAvailableNames: this.tools.map(t => t.name),
460
+ totalToolsAvailable: this._tools.length,
461
+ toolsAvailableNames: this._tools.map(t => t.name),
357
462
  maxStepsConfigured: this.maxSteps,
358
463
  memoryEnabled: this.memoryEnabled,
359
464
  useServerManager: this.useServerManager,
@@ -377,8 +482,8 @@ export class MCPAgent {
377
482
  async close() {
378
483
  logger.info('šŸ”Œ Closing MCPAgent resources…');
379
484
  try {
380
- this.agentExecutor = null;
381
- this.tools = [];
485
+ this._agentExecutor = null;
486
+ this._tools = [];
382
487
  if (this.client) {
383
488
  logger.info('šŸ”„ Closing sessions through client');
384
489
  await this.client.closeAllSessions();
@@ -395,8 +500,208 @@ export class MCPAgent {
395
500
  }
396
501
  }
397
502
  finally {
398
- this.initialized = false;
503
+ this._initialized = false;
399
504
  logger.info('šŸ‘‹ Agent closed successfully');
400
505
  }
401
506
  }
507
+ /**
508
+ * Yields LangChain StreamEvent objects from the underlying streamEvents() method.
509
+ * This provides token-level streaming and fine-grained event updates.
510
+ */
511
+ async *streamEvents(query, maxSteps, manageConnector = true, externalHistory) {
512
+ let initializedHere = false;
513
+ const startTime = Date.now();
514
+ let success = false;
515
+ let eventCount = 0;
516
+ let totalResponseLength = 0;
517
+ try {
518
+ // Initialize if needed
519
+ if (manageConnector && !this._initialized) {
520
+ await this.initialize();
521
+ initializedHere = true;
522
+ }
523
+ else if (!this._initialized && this.autoInitialize) {
524
+ await this.initialize();
525
+ initializedHere = true;
526
+ }
527
+ const agentExecutor = this.agentExecutor;
528
+ if (!agentExecutor) {
529
+ throw new Error('MCP agent failed to initialize');
530
+ }
531
+ // Set max iterations
532
+ const steps = maxSteps ?? this.maxSteps;
533
+ agentExecutor.maxIterations = steps;
534
+ const display_query = query.length > 50 ? `${query.slice(0, 50).replace(/\n/g, ' ')}...` : query.replace(/\n/g, ' ');
535
+ logger.info(`šŸ’¬ Received query for streamEvents: '${display_query}'`);
536
+ // Add user message to history if memory enabled
537
+ if (this.memoryEnabled) {
538
+ this.addToHistory(new HumanMessage(query));
539
+ }
540
+ // Prepare history
541
+ const historyToUse = externalHistory ?? this.conversationHistory;
542
+ const langchainHistory = [];
543
+ for (const msg of historyToUse) {
544
+ if (msg instanceof HumanMessage || msg instanceof AIMessage) {
545
+ langchainHistory.push(msg);
546
+ }
547
+ }
548
+ // Prepare inputs
549
+ const inputs = { input: query, chat_history: langchainHistory };
550
+ // Stream events from the agent executor
551
+ const eventStream = agentExecutor.streamEvents(inputs, { version: 'v2' });
552
+ // Yield each event
553
+ for await (const event of eventStream) {
554
+ eventCount++;
555
+ // Skip null or invalid events
556
+ if (!event || typeof event !== 'object') {
557
+ continue;
558
+ }
559
+ // Track response length for telemetry
560
+ if (event.event === 'on_chat_model_stream' && event.data?.chunk?.content) {
561
+ totalResponseLength += event.data.chunk.content.length;
562
+ }
563
+ yield event;
564
+ // Handle final message for history
565
+ if (event.event === 'on_chain_end' && event.data?.output) {
566
+ const output = event.data.output;
567
+ if (typeof output === 'string' && this.memoryEnabled) {
568
+ this.addToHistory(new AIMessage(output));
569
+ }
570
+ else if (output?.output && typeof output.output === 'string' && this.memoryEnabled) {
571
+ this.addToHistory(new AIMessage(output.output));
572
+ }
573
+ }
574
+ }
575
+ logger.info(`šŸŽ‰ StreamEvents complete - ${eventCount} events emitted`);
576
+ success = true;
577
+ }
578
+ catch (e) {
579
+ logger.error(`āŒ Error during streamEvents: ${e}`);
580
+ if (initializedHere && manageConnector) {
581
+ logger.info('🧹 Cleaning up resources after initialization error in streamEvents');
582
+ await this.close();
583
+ }
584
+ throw e;
585
+ }
586
+ finally {
587
+ // Track telemetry
588
+ const executionTimeMs = Date.now() - startTime;
589
+ let serverCount = 0;
590
+ if (this.client) {
591
+ serverCount = Object.keys(await this.client.getAllActiveSessions()).length;
592
+ }
593
+ else if (this.connectors) {
594
+ serverCount = this.connectors.length;
595
+ }
596
+ const conversationHistoryLength = this.memoryEnabled ? this.conversationHistory.length : 0;
597
+ await this.telemetry.trackAgentExecution({
598
+ executionMethod: 'streamEvents',
599
+ query,
600
+ success,
601
+ modelProvider: this.modelProvider,
602
+ modelName: this.modelName,
603
+ serverCount,
604
+ serverIdentifiers: this.connectors.map(connector => connector.publicIdentifier),
605
+ totalToolsAvailable: this._tools.length,
606
+ toolsAvailableNames: this._tools.map(t => t.name),
607
+ maxStepsConfigured: this.maxSteps,
608
+ memoryEnabled: this.memoryEnabled,
609
+ useServerManager: this.useServerManager,
610
+ maxStepsUsed: maxSteps ?? null,
611
+ manageConnector,
612
+ externalHistoryUsed: externalHistory !== undefined,
613
+ response: `[STREAMED RESPONSE - ${totalResponseLength} chars]`,
614
+ executionTimeMs,
615
+ errorType: success ? null : 'streaming_error',
616
+ conversationHistoryLength,
617
+ });
618
+ // Clean up if needed
619
+ if (manageConnector && !this.client && initializedHere) {
620
+ logger.info('🧹 Closing agent after streamEvents completion');
621
+ await this.close();
622
+ }
623
+ }
624
+ }
625
+ /**
626
+ * Attempt to create structured output from raw result with validation.
627
+ */
628
+ async _attemptStructuredOutput(rawResult, structuredLlm, outputSchema, schemaDescription) {
629
+ const formatPrompt = `
630
+ Please format the following information according to the specified schema.
631
+ Extract and structure the relevant information from the content below.
632
+
633
+ Required schema fields:
634
+ ${schemaDescription}
635
+
636
+ Content to format:
637
+ ${rawResult}
638
+
639
+ Please provide the information in the requested structured format.
640
+ If any required information is missing, you must indicate this clearly.
641
+ `;
642
+ const structuredResult = await structuredLlm.invoke(formatPrompt);
643
+ // Validate that the result is complete (basic check)
644
+ try {
645
+ // Use Zod to validate the structured result
646
+ const validatedResult = outputSchema.parse(structuredResult);
647
+ // Additional validation for required fields
648
+ const schemaType = outputSchema;
649
+ if (schemaType._def && schemaType._def.shape) {
650
+ for (const [fieldName, fieldSchema] of Object.entries(schemaType._def.shape)) {
651
+ const field = fieldSchema;
652
+ const isOptional = field.isOptional?.() ?? field._def?.typeName === 'ZodOptional';
653
+ const isNullable = field.isNullable?.() ?? field._def?.typeName === 'ZodNullable';
654
+ if (!isOptional && !isNullable) {
655
+ const value = validatedResult[fieldName];
656
+ if (value === null || value === undefined
657
+ || (typeof value === 'string' && !value.trim())
658
+ || (Array.isArray(value) && value.length === 0)) {
659
+ throw new Error(`Required field '${fieldName}' is missing or empty`);
660
+ }
661
+ }
662
+ }
663
+ }
664
+ return validatedResult;
665
+ }
666
+ catch (e) {
667
+ logger.debug(`Validation details: ${e}`);
668
+ throw e; // Re-raise to trigger retry logic
669
+ }
670
+ }
671
+ /**
672
+ * Enhance the query with schema information to make the agent aware of required fields.
673
+ */
674
+ _enhanceQueryWithSchema(query, outputSchema) {
675
+ const schemaFields = [];
676
+ try {
677
+ // Get field information from the schema
678
+ const schemaType = outputSchema;
679
+ if (schemaType._def && schemaType._def.shape) {
680
+ for (const [fieldName, fieldSchema] of Object.entries(schemaType._def.shape)) {
681
+ const field = fieldSchema;
682
+ const description = field._def?.description || field.description || fieldName;
683
+ const isOptional = field.isOptional?.() ?? field._def?.typeName === 'ZodOptional';
684
+ const isNullable = field.isNullable?.() ?? field._def?.typeName === 'ZodNullable';
685
+ schemaFields.push(`- ${fieldName}: ${description} ${(isOptional || isNullable) ? '(optional)' : '(required)'}`);
686
+ }
687
+ }
688
+ const schemaDescription = schemaFields.join('\n');
689
+ // Enhance the query with schema awareness
690
+ const enhancedQuery = `
691
+ ${query}
692
+
693
+ IMPORTANT: Your response must include sufficient information to populate the following structured output:
694
+
695
+ ${schemaDescription}
696
+
697
+ Make sure you gather ALL the required information during your task execution.
698
+ If any required information is missing, continue working to find it.
699
+ `;
700
+ return enhancedQuery;
701
+ }
702
+ catch (e) {
703
+ logger.warn(`Could not extract schema details: ${e}`);
704
+ return query;
705
+ }
706
+ }
402
707
  }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * AI SDK Integration Utilities
3
+ *
4
+ * Utility functions for integrating MCPAgent's streamEvents with Vercel AI SDK.
5
+ * These utilities help convert stream events to AI SDK compatible formats.
6
+ */
7
+ import type { StreamEvent } from '@langchain/core/tracers/log_stream';
8
+ /**
9
+ * Converts streamEvents to AI SDK compatible stream (basic version)
10
+ * Only yields the actual content tokens from chat model streams
11
+ */
12
+ export declare function streamEventsToAISDK(streamEvents: AsyncGenerator<StreamEvent, void, void>): AsyncGenerator<string, void, void>;
13
+ /**
14
+ * Converts async generator to ReadableStream for AI SDK compatibility
15
+ */
16
+ export declare function createReadableStreamFromGenerator(generator: AsyncGenerator<string, void, void>): ReadableStream<string>;
17
+ /**
18
+ * Enhanced adapter that includes tool information along with chat content
19
+ * Yields both content tokens and tool usage notifications
20
+ */
21
+ export declare function streamEventsToAISDKWithTools(streamEvents: AsyncGenerator<StreamEvent, void, void>): AsyncGenerator<string, void, void>;
22
+ //# sourceMappingURL=ai_sdk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai_sdk.d.ts","sourceRoot":"","sources":["../../../../src/agents/utils/ai_sdk.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAA;AAErE;;;GAGG;AACH,wBAAuB,mBAAmB,CACxC,YAAY,EAAE,cAAc,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,CAAC,GACpD,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CASpC;AAED;;GAEG;AACH,wBAAgB,iCAAiC,CAC/C,SAAS,EAAE,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,GAC5C,cAAc,CAAC,MAAM,CAAC,CAcxB;AAED;;;GAGG;AACH,wBAAuB,4BAA4B,CACjD,YAAY,EAAE,cAAc,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,CAAC,GACpD,cAAc,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAqBpC"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * AI SDK Integration Utilities
3
+ *
4
+ * Utility functions for integrating MCPAgent's streamEvents with Vercel AI SDK.
5
+ * These utilities help convert stream events to AI SDK compatible formats.
6
+ */
7
+ /**
8
+ * Converts streamEvents to AI SDK compatible stream (basic version)
9
+ * Only yields the actual content tokens from chat model streams
10
+ */
11
+ export async function* streamEventsToAISDK(streamEvents) {
12
+ for await (const event of streamEvents) {
13
+ if (event.event === 'on_chat_model_stream' && event.data?.chunk?.text) {
14
+ const textContent = event.data.chunk.text;
15
+ if (typeof textContent === 'string' && textContent.length > 0) {
16
+ yield textContent;
17
+ }
18
+ }
19
+ }
20
+ }
21
+ /**
22
+ * Converts async generator to ReadableStream for AI SDK compatibility
23
+ */
24
+ export function createReadableStreamFromGenerator(generator) {
25
+ return new ReadableStream({
26
+ async start(controller) {
27
+ try {
28
+ for await (const chunk of generator) {
29
+ controller.enqueue(chunk);
30
+ }
31
+ controller.close();
32
+ }
33
+ catch (error) {
34
+ controller.error(error);
35
+ }
36
+ },
37
+ });
38
+ }
39
+ /**
40
+ * Enhanced adapter that includes tool information along with chat content
41
+ * Yields both content tokens and tool usage notifications
42
+ */
43
+ export async function* streamEventsToAISDKWithTools(streamEvents) {
44
+ for await (const event of streamEvents) {
45
+ switch (event.event) {
46
+ case 'on_chat_model_stream':
47
+ if (event.data?.chunk?.text) {
48
+ const textContent = event.data.chunk.text;
49
+ if (typeof textContent === 'string' && textContent.length > 0) {
50
+ yield textContent;
51
+ }
52
+ }
53
+ break;
54
+ case 'on_tool_start':
55
+ yield `\nšŸ”§ Using tool: ${event.name}\n`;
56
+ break;
57
+ case 'on_tool_end':
58
+ yield `\nāœ… Tool completed: ${event.name}\n`;
59
+ break;
60
+ }
61
+ }
62
+ }
@@ -0,0 +1,2 @@
1
+ export { createReadableStreamFromGenerator, streamEventsToAISDK, streamEventsToAISDKWithTools, } from './ai_sdk.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/agents/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iCAAiC,EACjC,mBAAmB,EACnB,4BAA4B,GAC7B,MAAM,aAAa,CAAA"}
@@ -0,0 +1 @@
1
+ export { createReadableStreamFromGenerator, streamEventsToAISDK, streamEventsToAISDKWithTools, } from './ai_sdk.js';