@n0ts123/mcplink-core 0.0.1 → 0.0.3
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.
- package/README.md +215 -204
- package/dist/index.d.ts +100 -53
- package/dist/index.js +389 -68
- package/dist/index.js.map +1 -1
- package/package.json +5 -6
package/dist/index.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
2
|
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
3
3
|
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
4
|
+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
4
5
|
import { generateText, streamText } from 'ai';
|
|
5
6
|
import { z } from 'zod';
|
|
7
|
+
export { createOpenAI } from '@ai-sdk/openai';
|
|
8
|
+
export { createAnthropic } from '@ai-sdk/anthropic';
|
|
6
9
|
|
|
7
10
|
// src/MCPManager.ts
|
|
8
11
|
var MCPManager = class {
|
|
@@ -19,6 +22,9 @@ var MCPManager = class {
|
|
|
19
22
|
if (config.type === "sse") {
|
|
20
23
|
const sseConfig = config;
|
|
21
24
|
transport = new SSEClientTransport(new URL(sseConfig.url));
|
|
25
|
+
} else if (config.type === "streamable-http") {
|
|
26
|
+
const httpConfig = config;
|
|
27
|
+
transport = new StreamableHTTPClientTransport(new URL(httpConfig.url));
|
|
22
28
|
} else {
|
|
23
29
|
const stdioConfig = config;
|
|
24
30
|
const processEnv = {};
|
|
@@ -86,11 +92,16 @@ var MCPManager = class {
|
|
|
86
92
|
if (stdioConfig.env && Object.keys(stdioConfig.env).length > 0) {
|
|
87
93
|
console.log(` \u73AF\u5883\u53D8\u91CF: ${Object.keys(stdioConfig.env).join(", ")}`);
|
|
88
94
|
}
|
|
89
|
-
} else {
|
|
95
|
+
} else if (config.type === "sse") {
|
|
90
96
|
const sseConfig = config;
|
|
91
97
|
console.log(`
|
|
92
98
|
\u{1F527} [MCP] \u6B63\u5728\u8FDE\u63A5 SSE \u670D\u52A1\u5668 "${id}"...`);
|
|
93
99
|
console.log(` URL: ${sseConfig.url}`);
|
|
100
|
+
} else if (config.type === "streamable-http") {
|
|
101
|
+
const httpConfig = config;
|
|
102
|
+
console.log(`
|
|
103
|
+
\u{1F527} [MCP] \u6B63\u5728\u8FDE\u63A5 Streamable HTTP \u670D\u52A1\u5668 "${id}"...`);
|
|
104
|
+
console.log(` URL: ${httpConfig.url}`);
|
|
94
105
|
}
|
|
95
106
|
try {
|
|
96
107
|
await server.client.connect(server.transport);
|
|
@@ -248,32 +259,108 @@ var MCPLinkEventType = /* @__PURE__ */ ((MCPLinkEventType2) => {
|
|
|
248
259
|
MCPLinkEventType2["TEXT_END"] = "text_end";
|
|
249
260
|
MCPLinkEventType2["TOOL_CALL_START"] = "tool_call_start";
|
|
250
261
|
MCPLinkEventType2["TOOL_CALL_DELTA"] = "tool_call_delta";
|
|
251
|
-
MCPLinkEventType2["TOOL_CALL_END"] = "tool_call_end";
|
|
252
262
|
MCPLinkEventType2["TOOL_EXECUTING"] = "tool_executing";
|
|
253
263
|
MCPLinkEventType2["TOOL_RESULT"] = "tool_result";
|
|
264
|
+
MCPLinkEventType2["IMMEDIATE_RESULT"] = "immediate_result";
|
|
254
265
|
MCPLinkEventType2["ITERATION_START"] = "iteration_start";
|
|
255
266
|
MCPLinkEventType2["ITERATION_END"] = "iteration_end";
|
|
256
267
|
MCPLinkEventType2["COMPLETE"] = "complete";
|
|
257
268
|
MCPLinkEventType2["ERROR"] = "error";
|
|
258
|
-
MCPLinkEventType2["TODO_START"] = "todo_start";
|
|
259
|
-
MCPLinkEventType2["TODO_ITEM_ADD"] = "todo_item_add";
|
|
260
|
-
MCPLinkEventType2["TODO_ITEM_UPDATE"] = "todo_item_update";
|
|
261
|
-
MCPLinkEventType2["TODO_END"] = "todo_end";
|
|
262
269
|
return MCPLinkEventType2;
|
|
263
270
|
})(MCPLinkEventType || {});
|
|
264
271
|
|
|
265
272
|
// src/Agent.ts
|
|
266
|
-
var DEFAULT_SYSTEM_PROMPT = `\u4F60\u662F\u4E00\u4E2A\
|
|
273
|
+
var DEFAULT_SYSTEM_PROMPT = `\u4F60\u662F\u4E00\u4E2A\u4E13\u4E1A\u3001\u53CB\u597D\u7684\u667A\u80FD\u52A9\u624B\u3002
|
|
274
|
+
|
|
275
|
+
## \u56DE\u590D\u8981\u6C42
|
|
276
|
+
- \u7B80\u6D01\u6E05\u6670\uFF0C\u91CD\u70B9\u7A81\u51FA
|
|
277
|
+
- \u7528\u5217\u8868\u5448\u73B0\u5173\u952E\u4FE1\u606F
|
|
278
|
+
- \u8BED\u6C14\u793C\u8C8C\u81EA\u7136\uFF0C\u50CF\u4E13\u4E1A\u52A9\u624B
|
|
279
|
+
- \u6709\u7ED3\u8BBA\u65F6\u76F4\u63A5\u7ED9\u51FA\uFF0C\u9700\u8981\u8865\u5145\u4FE1\u606F\u65F6\u7B80\u5355\u8BE2\u95EE`;
|
|
267
280
|
var Agent = class {
|
|
268
281
|
model;
|
|
269
282
|
mcpManager;
|
|
270
283
|
systemPrompt;
|
|
271
284
|
maxIterations;
|
|
285
|
+
immediateResultMatchers;
|
|
286
|
+
parallelToolCalls;
|
|
287
|
+
enableThinkingPhase;
|
|
272
288
|
constructor(model, mcpManager, options = {}) {
|
|
273
289
|
this.model = model;
|
|
274
290
|
this.mcpManager = mcpManager;
|
|
275
291
|
this.systemPrompt = options.systemPrompt || DEFAULT_SYSTEM_PROMPT;
|
|
276
292
|
this.maxIterations = options.maxIterations || 10;
|
|
293
|
+
this.immediateResultMatchers = options.immediateResultMatchers || [];
|
|
294
|
+
this.parallelToolCalls = options.parallelToolCalls ?? true;
|
|
295
|
+
this.enableThinkingPhase = options.enableThinkingPhase ?? true;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* 生成工具描述文本(用于思考阶段)
|
|
299
|
+
*/
|
|
300
|
+
generateToolsDescription(tools) {
|
|
301
|
+
if (tools.length === 0) {
|
|
302
|
+
return "\u5F53\u524D\u6CA1\u6709\u53EF\u7528\u7684\u5DE5\u5177\u3002";
|
|
303
|
+
}
|
|
304
|
+
let description = "";
|
|
305
|
+
for (const tool of tools) {
|
|
306
|
+
description += `### ${tool.name}
|
|
307
|
+
`;
|
|
308
|
+
description += `\u63CF\u8FF0: ${tool.description}
|
|
309
|
+
`;
|
|
310
|
+
if (tool.inputSchema.properties) {
|
|
311
|
+
description += `\u53C2\u6570:
|
|
312
|
+
`;
|
|
313
|
+
for (const [key, prop] of Object.entries(tool.inputSchema.properties)) {
|
|
314
|
+
const propInfo = prop;
|
|
315
|
+
const required = tool.inputSchema.required?.includes(key) ? "\u5FC5\u586B" : "\u53EF\u9009";
|
|
316
|
+
description += ` - ${key} (${propInfo.type || "any"}, ${required}): ${propInfo.description || ""}
|
|
317
|
+
`;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
description += "\n";
|
|
321
|
+
}
|
|
322
|
+
return description;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* 思考阶段的系统提示词
|
|
326
|
+
*/
|
|
327
|
+
THINKING_PHASE_PROMPT = `\u4F60\u6B63\u5728\u601D\u8003\u5982\u4F55\u5E2E\u52A9\u7528\u6237\u3002\u8BF7\u7528\u81EA\u7136\u8BED\u8A00\u5206\u6790\uFF1A
|
|
328
|
+
|
|
329
|
+
1. \u7528\u6237\u60F3\u8981\u4EC0\u4E48\uFF1F
|
|
330
|
+
2. \u6211\u76EE\u524D\u638C\u63E1\u4E86\u54EA\u4E9B\u4FE1\u606F\uFF1F
|
|
331
|
+
3. \u8FD8\u9700\u8981\u505A\u4EC0\u4E48\u624D\u80FD\u56DE\u7B54\u7528\u6237\uFF1F
|
|
332
|
+
|
|
333
|
+
\u8981\u6C42\uFF1A
|
|
334
|
+
- \u50CF\u5185\u5FC3\u72EC\u767D\u4E00\u6837\u81EA\u7136\u8868\u8FBE
|
|
335
|
+
- \u4F53\u73B0\u4F60\u8BA4\u771F\u5206\u6790\u4E86\u95EE\u9898
|
|
336
|
+
- \u8BF4\u6E05\u695A\u63A5\u4E0B\u6765\u7684\u8BA1\u5212
|
|
337
|
+
- \u4E0D\u8981\u8F93\u51FA\u7ED9\u7528\u6237\u770B\u7684\u6B63\u5F0F\u56DE\u590D\uFF08\u5982\u4EA7\u54C1\u5217\u8868\u3001\u7ED3\u8BBA\u7B49\uFF09"`;
|
|
338
|
+
/**
|
|
339
|
+
* 检查工具返回结果是否匹配即时结果匹配器
|
|
340
|
+
* @param result 工具返回的结果
|
|
341
|
+
* @returns 如果匹配返回 true,否则返回 false
|
|
342
|
+
*/
|
|
343
|
+
matchImmediateResult(result) {
|
|
344
|
+
if (!this.immediateResultMatchers.length) {
|
|
345
|
+
return false;
|
|
346
|
+
}
|
|
347
|
+
if (typeof result !== "object" || result === null) {
|
|
348
|
+
return false;
|
|
349
|
+
}
|
|
350
|
+
const resultObj = result;
|
|
351
|
+
for (const matcher of this.immediateResultMatchers) {
|
|
352
|
+
let matched = true;
|
|
353
|
+
for (const [key, value] of Object.entries(matcher)) {
|
|
354
|
+
if (resultObj[key] !== value) {
|
|
355
|
+
matched = false;
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
if (matched) {
|
|
360
|
+
return true;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
return false;
|
|
277
364
|
}
|
|
278
365
|
/**
|
|
279
366
|
* 将 MCP 工具转换为 Vercel AI SDK 格式
|
|
@@ -290,18 +377,31 @@ var Agent = class {
|
|
|
290
377
|
return tools;
|
|
291
378
|
}
|
|
292
379
|
/**
|
|
293
|
-
*
|
|
380
|
+
* JSON Schema 到 Zod 的完整递归转换
|
|
381
|
+
* 支持嵌套对象、对象数组、枚举等所有常见类型
|
|
294
382
|
*/
|
|
295
383
|
jsonSchemaToZod(schema) {
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
384
|
+
return this.convertSchemaToZod(schema, schema.required || []);
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* 递归转换 JSON Schema 节点为 Zod 类型
|
|
388
|
+
*/
|
|
389
|
+
convertSchemaToZod(schema, parentRequired = [], key) {
|
|
390
|
+
const type = schema.type;
|
|
391
|
+
const description = schema.description;
|
|
392
|
+
const enumValues = schema.enum;
|
|
393
|
+
let zodType;
|
|
394
|
+
if (enumValues && enumValues.length > 0) {
|
|
395
|
+
if (enumValues.every((v) => typeof v === "string")) {
|
|
396
|
+
zodType = z.enum(enumValues);
|
|
397
|
+
} else if (enumValues.every((v) => typeof v === "number")) {
|
|
398
|
+
const literals = enumValues.map((v) => z.literal(v));
|
|
399
|
+
zodType = literals.length === 1 ? literals[0] : z.union([literals[0], literals[1], ...literals.slice(2)]);
|
|
400
|
+
} else {
|
|
401
|
+
zodType = z.unknown();
|
|
402
|
+
}
|
|
403
|
+
} else {
|
|
404
|
+
switch (type) {
|
|
305
405
|
case "string":
|
|
306
406
|
zodType = z.string();
|
|
307
407
|
break;
|
|
@@ -314,27 +414,45 @@ var Agent = class {
|
|
|
314
414
|
case "boolean":
|
|
315
415
|
zodType = z.boolean();
|
|
316
416
|
break;
|
|
317
|
-
case "
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
417
|
+
case "null":
|
|
418
|
+
zodType = z.null();
|
|
419
|
+
break;
|
|
420
|
+
case "object": {
|
|
421
|
+
const properties = schema.properties;
|
|
422
|
+
const required = schema.required || [];
|
|
423
|
+
if (properties) {
|
|
424
|
+
const shape = {};
|
|
425
|
+
for (const [propKey, propSchema] of Object.entries(properties)) {
|
|
426
|
+
let propZod = this.convertSchemaToZod(propSchema, required, propKey);
|
|
427
|
+
if (!required.includes(propKey)) {
|
|
428
|
+
propZod = propZod.optional();
|
|
429
|
+
}
|
|
430
|
+
shape[propKey] = propZod;
|
|
431
|
+
}
|
|
432
|
+
zodType = z.object(shape);
|
|
433
|
+
} else {
|
|
434
|
+
zodType = z.record(z.unknown());
|
|
435
|
+
}
|
|
436
|
+
break;
|
|
437
|
+
}
|
|
438
|
+
case "array": {
|
|
439
|
+
const items = schema.items;
|
|
440
|
+
if (items) {
|
|
441
|
+
const itemsRequired = items.required || [];
|
|
442
|
+
zodType = z.array(this.convertSchemaToZod(items, itemsRequired));
|
|
322
443
|
} else {
|
|
323
444
|
zodType = z.array(z.unknown());
|
|
324
445
|
}
|
|
325
446
|
break;
|
|
447
|
+
}
|
|
326
448
|
default:
|
|
327
449
|
zodType = z.unknown();
|
|
328
450
|
}
|
|
329
|
-
if (propSchema.description) {
|
|
330
|
-
zodType = zodType.describe(propSchema.description);
|
|
331
|
-
}
|
|
332
|
-
if (!required.includes(key)) {
|
|
333
|
-
zodType = zodType.optional();
|
|
334
|
-
}
|
|
335
|
-
shape[key] = zodType;
|
|
336
451
|
}
|
|
337
|
-
|
|
452
|
+
if (description) {
|
|
453
|
+
zodType = zodType.describe(description);
|
|
454
|
+
}
|
|
455
|
+
return zodType;
|
|
338
456
|
}
|
|
339
457
|
/**
|
|
340
458
|
* 执行对话
|
|
@@ -457,6 +575,7 @@ var Agent = class {
|
|
|
457
575
|
*/
|
|
458
576
|
async *chatStream(userMessage, options) {
|
|
459
577
|
const startTime = Date.now();
|
|
578
|
+
const toolCallRecords = [];
|
|
460
579
|
const messages = [{ role: "system", content: this.systemPrompt }];
|
|
461
580
|
if (options?.history && options.history.length > 0) {
|
|
462
581
|
for (const msg of options.history) {
|
|
@@ -481,6 +600,53 @@ var Agent = class {
|
|
|
481
600
|
timestamp: Date.now(),
|
|
482
601
|
data: { iteration, maxIterations: this.maxIterations }
|
|
483
602
|
};
|
|
603
|
+
if (this.enableThinkingPhase && hasTools) {
|
|
604
|
+
yield {
|
|
605
|
+
type: "thinking_start" /* THINKING_START */,
|
|
606
|
+
timestamp: Date.now(),
|
|
607
|
+
data: {}
|
|
608
|
+
};
|
|
609
|
+
const toolsDescription = this.generateToolsDescription(mcpTools);
|
|
610
|
+
const thinkingMessages = [
|
|
611
|
+
{
|
|
612
|
+
role: "system",
|
|
613
|
+
content: `${this.THINKING_PHASE_PROMPT}
|
|
614
|
+
|
|
615
|
+
## \u53EF\u7528\u5DE5\u5177
|
|
616
|
+
${toolsDescription}`
|
|
617
|
+
},
|
|
618
|
+
...messages.slice(1)
|
|
619
|
+
// 跳过原来的 system 消息,使用历史消息
|
|
620
|
+
];
|
|
621
|
+
const thinkingStream = streamText({
|
|
622
|
+
model: this.model,
|
|
623
|
+
messages: thinkingMessages
|
|
624
|
+
// 不传 tools,强制 AI 输出文本思考
|
|
625
|
+
});
|
|
626
|
+
let thinkingContent = "";
|
|
627
|
+
for await (const chunk of thinkingStream.fullStream) {
|
|
628
|
+
if (chunk.type === "text-delta") {
|
|
629
|
+
thinkingContent += chunk.textDelta;
|
|
630
|
+
yield {
|
|
631
|
+
type: "thinking_delta" /* THINKING_DELTA */,
|
|
632
|
+
timestamp: Date.now(),
|
|
633
|
+
data: { content: chunk.textDelta }
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
yield {
|
|
638
|
+
type: "thinking_end" /* THINKING_END */,
|
|
639
|
+
timestamp: Date.now(),
|
|
640
|
+
data: {}
|
|
641
|
+
};
|
|
642
|
+
if (thinkingContent) {
|
|
643
|
+
messages.push({
|
|
644
|
+
role: "assistant",
|
|
645
|
+
content: `[\u5185\u90E8\u51B3\u7B56]
|
|
646
|
+
${thinkingContent}`
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
}
|
|
484
650
|
const stream = streamText({
|
|
485
651
|
model: this.model,
|
|
486
652
|
messages,
|
|
@@ -613,12 +779,12 @@ var Agent = class {
|
|
|
613
779
|
}
|
|
614
780
|
};
|
|
615
781
|
sentToolCallStarts.add(chunk.toolCallId);
|
|
782
|
+
toolCalls.push({
|
|
783
|
+
toolCallId: chunk.toolCallId,
|
|
784
|
+
toolName: chunk.toolName,
|
|
785
|
+
args: chunk.args
|
|
786
|
+
});
|
|
616
787
|
}
|
|
617
|
-
toolCalls.push({
|
|
618
|
-
toolCallId: chunk.toolCallId,
|
|
619
|
-
toolName: chunk.toolName,
|
|
620
|
-
args: chunk.args
|
|
621
|
-
});
|
|
622
788
|
break;
|
|
623
789
|
case "tool-call-streaming-start":
|
|
624
790
|
currentToolCall = {
|
|
@@ -720,42 +886,126 @@ var Agent = class {
|
|
|
720
886
|
}
|
|
721
887
|
const toolResults = [];
|
|
722
888
|
for (const toolCall of toolCalls) {
|
|
723
|
-
const toolName = toolCall.toolName;
|
|
724
|
-
const toolArgs = toolCall.args;
|
|
725
|
-
const toolCallId = toolCall.toolCallId;
|
|
726
889
|
yield {
|
|
727
890
|
type: "tool_executing" /* TOOL_EXECUTING */,
|
|
728
891
|
timestamp: Date.now(),
|
|
729
|
-
data: { toolName, toolCallId, toolArgs }
|
|
730
|
-
};
|
|
731
|
-
const toolStartTime = Date.now();
|
|
732
|
-
let result;
|
|
733
|
-
let isError = false;
|
|
734
|
-
try {
|
|
735
|
-
result = await this.mcpManager.callTool(toolName, toolArgs);
|
|
736
|
-
} catch (error) {
|
|
737
|
-
result = error instanceof Error ? error.message : String(error);
|
|
738
|
-
isError = true;
|
|
739
|
-
}
|
|
740
|
-
const duration = Date.now() - toolStartTime;
|
|
741
|
-
yield {
|
|
742
|
-
type: "tool_result" /* TOOL_RESULT */,
|
|
743
|
-
timestamp: Date.now(),
|
|
744
892
|
data: {
|
|
745
|
-
toolName,
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
duration,
|
|
749
|
-
isError
|
|
893
|
+
toolName: toolCall.toolName,
|
|
894
|
+
toolCallId: toolCall.toolCallId,
|
|
895
|
+
toolArgs: toolCall.args
|
|
750
896
|
}
|
|
751
897
|
};
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
898
|
+
}
|
|
899
|
+
if (this.parallelToolCalls && toolCalls.length > 1) {
|
|
900
|
+
const executePromises = toolCalls.map(async (toolCall) => {
|
|
901
|
+
const toolStartTime = Date.now();
|
|
902
|
+
let result;
|
|
903
|
+
let isError = false;
|
|
904
|
+
try {
|
|
905
|
+
result = await this.mcpManager.callTool(toolCall.toolName, toolCall.args);
|
|
906
|
+
} catch (error) {
|
|
907
|
+
result = error instanceof Error ? error.message : String(error);
|
|
908
|
+
isError = true;
|
|
909
|
+
}
|
|
910
|
+
const duration = Date.now() - toolStartTime;
|
|
911
|
+
return {
|
|
912
|
+
toolCallId: toolCall.toolCallId,
|
|
913
|
+
toolName: toolCall.toolName,
|
|
914
|
+
args: toolCall.args,
|
|
915
|
+
result,
|
|
916
|
+
isError,
|
|
917
|
+
duration
|
|
918
|
+
};
|
|
758
919
|
});
|
|
920
|
+
const results = await Promise.all(executePromises);
|
|
921
|
+
for (const r of results) {
|
|
922
|
+
yield {
|
|
923
|
+
type: "tool_result" /* TOOL_RESULT */,
|
|
924
|
+
timestamp: Date.now(),
|
|
925
|
+
data: {
|
|
926
|
+
toolName: r.toolName,
|
|
927
|
+
toolResult: r.result,
|
|
928
|
+
toolCallId: r.toolCallId,
|
|
929
|
+
duration: r.duration,
|
|
930
|
+
isError: r.isError
|
|
931
|
+
}
|
|
932
|
+
};
|
|
933
|
+
if (!r.isError && this.matchImmediateResult(r.result)) {
|
|
934
|
+
yield {
|
|
935
|
+
type: "immediate_result" /* IMMEDIATE_RESULT */,
|
|
936
|
+
timestamp: Date.now(),
|
|
937
|
+
data: {
|
|
938
|
+
toolName: r.toolName,
|
|
939
|
+
toolCallId: r.toolCallId,
|
|
940
|
+
immediateResult: r.result
|
|
941
|
+
}
|
|
942
|
+
};
|
|
943
|
+
}
|
|
944
|
+
toolResults.push({
|
|
945
|
+
toolCallId: r.toolCallId,
|
|
946
|
+
toolName: r.toolName,
|
|
947
|
+
result: r.result,
|
|
948
|
+
isError: r.isError,
|
|
949
|
+
duration: r.duration
|
|
950
|
+
});
|
|
951
|
+
toolCallRecords.push({
|
|
952
|
+
name: r.toolName,
|
|
953
|
+
arguments: r.args,
|
|
954
|
+
result: r.result,
|
|
955
|
+
duration: r.duration
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
} else {
|
|
959
|
+
for (const toolCall of toolCalls) {
|
|
960
|
+
const toolName = toolCall.toolName;
|
|
961
|
+
const toolArgs = toolCall.args;
|
|
962
|
+
const toolCallId = toolCall.toolCallId;
|
|
963
|
+
const toolStartTime = Date.now();
|
|
964
|
+
let result;
|
|
965
|
+
let isError = false;
|
|
966
|
+
try {
|
|
967
|
+
result = await this.mcpManager.callTool(toolName, toolArgs);
|
|
968
|
+
} catch (error) {
|
|
969
|
+
result = error instanceof Error ? error.message : String(error);
|
|
970
|
+
isError = true;
|
|
971
|
+
}
|
|
972
|
+
const duration = Date.now() - toolStartTime;
|
|
973
|
+
yield {
|
|
974
|
+
type: "tool_result" /* TOOL_RESULT */,
|
|
975
|
+
timestamp: Date.now(),
|
|
976
|
+
data: {
|
|
977
|
+
toolName,
|
|
978
|
+
toolResult: result,
|
|
979
|
+
toolCallId,
|
|
980
|
+
duration,
|
|
981
|
+
isError
|
|
982
|
+
}
|
|
983
|
+
};
|
|
984
|
+
if (!isError && this.matchImmediateResult(result)) {
|
|
985
|
+
yield {
|
|
986
|
+
type: "immediate_result" /* IMMEDIATE_RESULT */,
|
|
987
|
+
timestamp: Date.now(),
|
|
988
|
+
data: {
|
|
989
|
+
toolName,
|
|
990
|
+
toolCallId,
|
|
991
|
+
immediateResult: result
|
|
992
|
+
}
|
|
993
|
+
};
|
|
994
|
+
}
|
|
995
|
+
toolResults.push({
|
|
996
|
+
toolCallId,
|
|
997
|
+
toolName,
|
|
998
|
+
result,
|
|
999
|
+
isError,
|
|
1000
|
+
duration
|
|
1001
|
+
});
|
|
1002
|
+
toolCallRecords.push({
|
|
1003
|
+
name: toolName,
|
|
1004
|
+
arguments: toolArgs,
|
|
1005
|
+
result,
|
|
1006
|
+
duration
|
|
1007
|
+
});
|
|
1008
|
+
}
|
|
759
1009
|
}
|
|
760
1010
|
messages.push({
|
|
761
1011
|
role: "assistant",
|
|
@@ -804,11 +1054,45 @@ var PromptBasedAgent = class {
|
|
|
804
1054
|
mcpManager;
|
|
805
1055
|
systemPrompt;
|
|
806
1056
|
maxIterations;
|
|
1057
|
+
immediateResultMatchers;
|
|
1058
|
+
parallelToolCalls;
|
|
1059
|
+
// PromptBasedAgent 本身通过 prompt 实现思考,此配置保留以保持接口一致
|
|
1060
|
+
enableThinkingPhase;
|
|
807
1061
|
constructor(model, mcpManager, options = {}) {
|
|
808
1062
|
this.model = model;
|
|
809
1063
|
this.mcpManager = mcpManager;
|
|
810
1064
|
this.systemPrompt = options.systemPrompt || "";
|
|
811
1065
|
this.maxIterations = options.maxIterations || 10;
|
|
1066
|
+
this.immediateResultMatchers = options.immediateResultMatchers || [];
|
|
1067
|
+
this.parallelToolCalls = options.parallelToolCalls ?? true;
|
|
1068
|
+
this.enableThinkingPhase = options.enableThinkingPhase ?? false;
|
|
1069
|
+
}
|
|
1070
|
+
/**
|
|
1071
|
+
* 检查工具返回结果是否匹配即时结果匹配器
|
|
1072
|
+
* @param result 工具返回的结果
|
|
1073
|
+
* @returns 如果匹配返回 true,否则返回 false
|
|
1074
|
+
*/
|
|
1075
|
+
matchImmediateResult(result) {
|
|
1076
|
+
if (!this.immediateResultMatchers.length) {
|
|
1077
|
+
return false;
|
|
1078
|
+
}
|
|
1079
|
+
if (typeof result !== "object" || result === null) {
|
|
1080
|
+
return false;
|
|
1081
|
+
}
|
|
1082
|
+
const resultObj = result;
|
|
1083
|
+
for (const matcher of this.immediateResultMatchers) {
|
|
1084
|
+
let matched = true;
|
|
1085
|
+
for (const [key, value] of Object.entries(matcher)) {
|
|
1086
|
+
if (resultObj[key] !== value) {
|
|
1087
|
+
matched = false;
|
|
1088
|
+
break;
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
if (matched) {
|
|
1092
|
+
return true;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
return false;
|
|
812
1096
|
}
|
|
813
1097
|
/**
|
|
814
1098
|
* 生成工具列表描述
|
|
@@ -1167,6 +1451,17 @@ ${this.BUILT_IN_PROMPT}`;
|
|
|
1167
1451
|
timestamp: Date.now(),
|
|
1168
1452
|
data: { toolName: toolCall.name, toolResult: result, toolCallId, duration, isError }
|
|
1169
1453
|
};
|
|
1454
|
+
if (!isError && this.matchImmediateResult(result)) {
|
|
1455
|
+
yield {
|
|
1456
|
+
type: "immediate_result" /* IMMEDIATE_RESULT */,
|
|
1457
|
+
timestamp: Date.now(),
|
|
1458
|
+
data: {
|
|
1459
|
+
toolName: toolCall.name,
|
|
1460
|
+
toolCallId,
|
|
1461
|
+
immediateResult: result
|
|
1462
|
+
}
|
|
1463
|
+
};
|
|
1464
|
+
}
|
|
1170
1465
|
messages.push({ role: "assistant", content: fullResponse });
|
|
1171
1466
|
const resultStr = typeof result === "string" ? result : JSON.stringify(result, null, 2);
|
|
1172
1467
|
messages.push({
|
|
@@ -1274,11 +1569,17 @@ var MCPLink = class {
|
|
|
1274
1569
|
}
|
|
1275
1570
|
this.agent = new Agent(this.model, this.mcpManager, {
|
|
1276
1571
|
systemPrompt: config.systemPrompt,
|
|
1277
|
-
maxIterations: config.maxIterations
|
|
1572
|
+
maxIterations: config.maxIterations,
|
|
1573
|
+
immediateResultMatchers: config.immediateResultMatchers,
|
|
1574
|
+
parallelToolCalls: config.parallelToolCalls,
|
|
1575
|
+
enableThinkingPhase: config.enableThinkingPhase
|
|
1278
1576
|
});
|
|
1279
1577
|
this.promptBasedAgent = new PromptBasedAgent(this.model, this.mcpManager, {
|
|
1280
1578
|
systemPrompt: config.systemPrompt,
|
|
1281
|
-
maxIterations: config.maxIterations
|
|
1579
|
+
maxIterations: config.maxIterations,
|
|
1580
|
+
immediateResultMatchers: config.immediateResultMatchers,
|
|
1581
|
+
parallelToolCalls: config.parallelToolCalls,
|
|
1582
|
+
enableThinkingPhase: config.enableThinkingPhase
|
|
1282
1583
|
});
|
|
1283
1584
|
if (config.usePromptBasedTools === true) {
|
|
1284
1585
|
this.detectedNativeSupport = false;
|
|
@@ -1389,7 +1690,17 @@ var MCPLink = class {
|
|
|
1389
1690
|
this.config.systemPrompt = prompt;
|
|
1390
1691
|
this.agent = new Agent(this.model, this.mcpManager, {
|
|
1391
1692
|
systemPrompt: prompt,
|
|
1392
|
-
maxIterations: this.config.maxIterations
|
|
1693
|
+
maxIterations: this.config.maxIterations,
|
|
1694
|
+
immediateResultMatchers: this.config.immediateResultMatchers,
|
|
1695
|
+
parallelToolCalls: this.config.parallelToolCalls,
|
|
1696
|
+
enableThinkingPhase: this.config.enableThinkingPhase
|
|
1697
|
+
});
|
|
1698
|
+
this.promptBasedAgent = new PromptBasedAgent(this.model, this.mcpManager, {
|
|
1699
|
+
systemPrompt: prompt,
|
|
1700
|
+
maxIterations: this.config.maxIterations,
|
|
1701
|
+
immediateResultMatchers: this.config.immediateResultMatchers,
|
|
1702
|
+
parallelToolCalls: this.config.parallelToolCalls,
|
|
1703
|
+
enableThinkingPhase: this.config.enableThinkingPhase
|
|
1393
1704
|
});
|
|
1394
1705
|
}
|
|
1395
1706
|
/**
|
|
@@ -1400,7 +1711,17 @@ var MCPLink = class {
|
|
|
1400
1711
|
this.config.model = model;
|
|
1401
1712
|
this.agent = new Agent(this.model, this.mcpManager, {
|
|
1402
1713
|
systemPrompt: this.config.systemPrompt,
|
|
1403
|
-
maxIterations: this.config.maxIterations
|
|
1714
|
+
maxIterations: this.config.maxIterations,
|
|
1715
|
+
immediateResultMatchers: this.config.immediateResultMatchers,
|
|
1716
|
+
parallelToolCalls: this.config.parallelToolCalls,
|
|
1717
|
+
enableThinkingPhase: this.config.enableThinkingPhase
|
|
1718
|
+
});
|
|
1719
|
+
this.promptBasedAgent = new PromptBasedAgent(this.model, this.mcpManager, {
|
|
1720
|
+
systemPrompt: this.config.systemPrompt,
|
|
1721
|
+
maxIterations: this.config.maxIterations,
|
|
1722
|
+
immediateResultMatchers: this.config.immediateResultMatchers,
|
|
1723
|
+
parallelToolCalls: this.config.parallelToolCalls,
|
|
1724
|
+
enableThinkingPhase: this.config.enableThinkingPhase
|
|
1404
1725
|
});
|
|
1405
1726
|
}
|
|
1406
1727
|
};
|