@aipack-ai/multi-agent 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +44 -3
- package/dist/index.js +503 -44
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Result, Tool, Request, Runtime, RuntimeOptions } from '@aipack-ai/agent';
|
|
2
|
+
import { McpServerHost } from '@aipack-ai/mcp';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* core/types.ts - 多Agent编排核心类型
|
|
@@ -450,7 +451,14 @@ interface MCPToolCallResult {
|
|
|
450
451
|
*
|
|
451
452
|
* // 处理工具调用
|
|
452
453
|
* const result = await bridge.handleCall({ name: 'ma_run', arguments: { input: '...' } });
|
|
454
|
+
*
|
|
455
|
+
* // M3:经标准 stdio MCP Server 暴露(补齐传输层,供 Claude Desktop 等拉起)
|
|
456
|
+
* import { runStdioServer } from '@aipack-ai/mcp';
|
|
457
|
+
* await runStdioServer(bridge.toMcpServerHost());
|
|
453
458
|
* ```
|
|
459
|
+
*
|
|
460
|
+
* M3 起,run/status 核心逻辑在 handleCall(legacy)与 asTools(统一路径)间共享,
|
|
461
|
+
* 避免与 packages/mcp 的协议实现重复。
|
|
454
462
|
*/
|
|
455
463
|
declare class MCPBridge {
|
|
456
464
|
private graph;
|
|
@@ -461,13 +469,46 @@ declare class MCPBridge {
|
|
|
461
469
|
name: string;
|
|
462
470
|
version: string;
|
|
463
471
|
};
|
|
464
|
-
/** 列出所有可用 MCP
|
|
472
|
+
/** 列出所有可用 MCP 工具(legacy 形状:MCPToolDefinition[]) */
|
|
465
473
|
listTools(): MCPToolDefinition[];
|
|
466
|
-
/**
|
|
474
|
+
/** run 工具核心:执行图并序列化为 MCP 形状结果 */
|
|
475
|
+
private runTool;
|
|
476
|
+
/** status 工具核心:图执行状态序列化为 MCP 形状结果 */
|
|
477
|
+
private statusTool;
|
|
478
|
+
/** 处理 MCP 工具调用(legacy API,行为保持不变) */
|
|
467
479
|
handleCall(request: MCPToolCallRequest): Promise<MCPToolCallResult>;
|
|
480
|
+
/**
|
|
481
|
+
* 将 AgentGraph 暴露为 agent 原生 `Tool[]`(JSON Schema 参数 + execute)。
|
|
482
|
+
* 可直接喂给 `@aipack-ai/mcp` 的 `createMcpServerHost({ tools })`,
|
|
483
|
+
* 再经 `runStdioServer` 拉起为标准 stdio MCP Server——补齐 MCPBridge
|
|
484
|
+
* 原本缺失的传输层("由宿主环境负责实际的 MCP 传输" 这一缺口)。
|
|
485
|
+
*
|
|
486
|
+
* 工具 `${prefix}run` / `${prefix}status` 与 legacy `listTools()`/`handleCall()`
|
|
487
|
+
* 共享 `runTool` / `statusTool` 核心,语义一致。
|
|
488
|
+
*/
|
|
489
|
+
asTools(): Tool[];
|
|
490
|
+
/**
|
|
491
|
+
* 构建一个 `McpServerHost`(来自 `@aipack-ai/mcp`),把本 AgentGraph 作为
|
|
492
|
+
* 标准 MCP Server 暴露。配合 `runStdioServer(host)` 即可经 stdin/stdout
|
|
493
|
+
* 服务外部 MCP 客户端(Claude Desktop / Cursor)。
|
|
494
|
+
*
|
|
495
|
+
* 与 legacy `handleCall()` 共享 `runTool` / `statusTool` 核心,保证语义一致。
|
|
496
|
+
*/
|
|
497
|
+
toMcpServerHost(): McpServerHost;
|
|
468
498
|
}
|
|
469
499
|
/** 创建 MCPBridge */
|
|
470
500
|
declare function createMCPBridge(graph: AgentGraph, opts?: MCPBridgeOpts): MCPBridge;
|
|
501
|
+
/**
|
|
502
|
+
* 便捷工厂:从 AgentGraph 直接构建一个 `McpServerHost`(@aipack-ai/mcp),
|
|
503
|
+
* 供 `runStdioServer(host)` 拉起为标准 stdio MCP Server。
|
|
504
|
+
*
|
|
505
|
+
* ```typescript
|
|
506
|
+
* import { runStdioServer } from '@aipack-ai/mcp';
|
|
507
|
+
* const host = createMultiAgentMcpServerHost(graph, { serverName: 'my-graph' });
|
|
508
|
+
* await runStdioServer(host);
|
|
509
|
+
* ```
|
|
510
|
+
*/
|
|
511
|
+
declare function createMultiAgentMcpServerHost(graph: AgentGraph, opts?: MCPBridgeOpts): McpServerHost;
|
|
471
512
|
|
|
472
513
|
/**
|
|
473
514
|
* extensions/debug.ts - 可视化调试扩展
|
|
@@ -520,4 +561,4 @@ declare class GraphDebugger {
|
|
|
520
561
|
/** 创建 GraphDebugger */
|
|
521
562
|
declare function createDebugger(graph: AgentGraph): GraphDebugger;
|
|
522
563
|
|
|
523
|
-
export { type AgentEdge, type AgentGraph, type AgentNode, type DebateOpts, type EventBus, type EventListener, GraphDebugger, type GraphExecutionState, type GraphTrace, MCPBridge, type MCPBridgeOpts, type MCPToolCallRequest, type MCPToolCallResult, type MCPToolDefinition, type MCPToolParameter, type MapReduceOpts, type MultiAgentEvent, type MultiAgentResult, type NodeExecutionState, type PipelineOpts, type RouterOpts, type ScheduleMode, type SharedContext, SimpleEventBus, SimpleToolRegistry, type SupervisorOpts, type ToolRegistry, type TraceStep, createAgentGraph, createDebate, createDebugger, createMCPBridge, createMapReduce, createPipeline, createRouter, createSharedContext, createSupervisor };
|
|
564
|
+
export { type AgentEdge, type AgentGraph, type AgentNode, type DebateOpts, type EventBus, type EventListener, GraphDebugger, type GraphExecutionState, type GraphTrace, MCPBridge, type MCPBridgeOpts, type MCPToolCallRequest, type MCPToolCallResult, type MCPToolDefinition, type MCPToolParameter, type MapReduceOpts, type MultiAgentEvent, type MultiAgentResult, type NodeExecutionState, type PipelineOpts, type RouterOpts, type ScheduleMode, type SharedContext, SimpleEventBus, SimpleToolRegistry, type SupervisorOpts, type ToolRegistry, type TraceStep, createAgentGraph, createDebate, createDebugger, createMCPBridge, createMapReduce, createMultiAgentMcpServerHost, createPipeline, createRouter, createSharedContext, createSupervisor };
|
package/dist/index.js
CHANGED
|
@@ -1086,6 +1086,9 @@ var AgentRuntime = class _AgentRuntime {
|
|
|
1086
1086
|
}
|
|
1087
1087
|
return this;
|
|
1088
1088
|
}
|
|
1089
|
+
unregisterTool(name) {
|
|
1090
|
+
return this._globalTools.delete(name);
|
|
1091
|
+
}
|
|
1089
1092
|
setModel(model) {
|
|
1090
1093
|
this._model = model;
|
|
1091
1094
|
return this;
|
|
@@ -3570,6 +3573,392 @@ function createMapReduce(mapper, reducer, opts) {
|
|
|
3570
3573
|
return new MapReduceGraphImpl(mapper, reducer, opts);
|
|
3571
3574
|
}
|
|
3572
3575
|
|
|
3576
|
+
// ../mcp/src/client/jsonrpc.ts
|
|
3577
|
+
var METHOD_NOT_FOUND = -32601;
|
|
3578
|
+
var INVALID_PARAMS = -32602;
|
|
3579
|
+
var INTERNAL_ERROR = -32603;
|
|
3580
|
+
function createNotification(method, params) {
|
|
3581
|
+
const n = { jsonrpc: "2.0", method };
|
|
3582
|
+
if (params !== void 0) n.params = params;
|
|
3583
|
+
return n;
|
|
3584
|
+
}
|
|
3585
|
+
function createSuccessResponse(id, result) {
|
|
3586
|
+
return { jsonrpc: "2.0", id, result };
|
|
3587
|
+
}
|
|
3588
|
+
function createErrorResponse(id, code, message, data) {
|
|
3589
|
+
const err = { jsonrpc: "2.0", id, error: { code, message } };
|
|
3590
|
+
if (data !== void 0) err.error.data = data;
|
|
3591
|
+
return err;
|
|
3592
|
+
}
|
|
3593
|
+
function hasOwn(o, k) {
|
|
3594
|
+
return typeof o === "object" && o !== null && Object.prototype.hasOwnProperty.call(o, k);
|
|
3595
|
+
}
|
|
3596
|
+
function classify(obj) {
|
|
3597
|
+
if (typeof obj !== "object" || obj === null) return null;
|
|
3598
|
+
const o = obj;
|
|
3599
|
+
if (o.jsonrpc !== "2.0") return null;
|
|
3600
|
+
if (hasOwn(o, "result") || hasOwn(o, "error")) {
|
|
3601
|
+
return o;
|
|
3602
|
+
}
|
|
3603
|
+
if (hasOwn(o, "method") && typeof o.method === "string") {
|
|
3604
|
+
if (hasOwn(o, "id") && o.id !== null) return o;
|
|
3605
|
+
if (!hasOwn(o, "id") || o.id === null) return o;
|
|
3606
|
+
}
|
|
3607
|
+
return null;
|
|
3608
|
+
}
|
|
3609
|
+
function isResponse(m) {
|
|
3610
|
+
return "result" in m || "error" in m;
|
|
3611
|
+
}
|
|
3612
|
+
function isRequest(m) {
|
|
3613
|
+
return !isResponse(m) && "id" in m && m.id !== null;
|
|
3614
|
+
}
|
|
3615
|
+
function isNotification(m) {
|
|
3616
|
+
return !isResponse(m) && !("id" in m && m.id !== null);
|
|
3617
|
+
}
|
|
3618
|
+
|
|
3619
|
+
// ../mcp/src/client/protocol.ts
|
|
3620
|
+
var MCP_PROTOCOL_VERSION = "2025-06-18";
|
|
3621
|
+
function createListChangedNotification() {
|
|
3622
|
+
return createNotification("notifications/tools/list_changed");
|
|
3623
|
+
}
|
|
3624
|
+
function parseToolCallParams(params) {
|
|
3625
|
+
const p = params ?? {};
|
|
3626
|
+
return {
|
|
3627
|
+
name: typeof p.name === "string" ? p.name : void 0,
|
|
3628
|
+
arguments: p.arguments
|
|
3629
|
+
};
|
|
3630
|
+
}
|
|
3631
|
+
function parseResourceReadParams(params) {
|
|
3632
|
+
const p = params ?? {};
|
|
3633
|
+
return { uri: typeof p.uri === "string" ? p.uri : void 0 };
|
|
3634
|
+
}
|
|
3635
|
+
function parsePromptGetParams(params) {
|
|
3636
|
+
const p = params ?? {};
|
|
3637
|
+
return {
|
|
3638
|
+
name: typeof p.name === "string" ? p.name : void 0,
|
|
3639
|
+
arguments: p.arguments
|
|
3640
|
+
};
|
|
3641
|
+
}
|
|
3642
|
+
function createInitializeResult(serverInfo, capabilities) {
|
|
3643
|
+
return {
|
|
3644
|
+
protocolVersion: MCP_PROTOCOL_VERSION,
|
|
3645
|
+
capabilities,
|
|
3646
|
+
serverInfo
|
|
3647
|
+
};
|
|
3648
|
+
}
|
|
3649
|
+
function buildToolsListResult(tools, nextCursor) {
|
|
3650
|
+
const list = tools.map((t) => {
|
|
3651
|
+
const out = { name: t.name };
|
|
3652
|
+
if (t.description !== void 0) out.description = t.description;
|
|
3653
|
+
out.inputSchema = t.inputSchema ?? { type: "object", properties: {} };
|
|
3654
|
+
return out;
|
|
3655
|
+
});
|
|
3656
|
+
const r = { tools: list };
|
|
3657
|
+
if (nextCursor) r.nextCursor = nextCursor;
|
|
3658
|
+
return r;
|
|
3659
|
+
}
|
|
3660
|
+
function buildToolCallResult(content, isError) {
|
|
3661
|
+
const r = { content: content.length ? content : [{ type: "text", text: "[empty result]" }] };
|
|
3662
|
+
if (isError) r.isError = true;
|
|
3663
|
+
return r;
|
|
3664
|
+
}
|
|
3665
|
+
function buildResourcesListResult(resources, nextCursor) {
|
|
3666
|
+
const list = resources.map((r0) => {
|
|
3667
|
+
const out = { uri: r0.uri };
|
|
3668
|
+
if (r0.name !== void 0) out.name = r0.name;
|
|
3669
|
+
if (r0.description !== void 0) out.description = r0.description;
|
|
3670
|
+
if (r0.mimeType !== void 0) out.mimeType = r0.mimeType;
|
|
3671
|
+
return out;
|
|
3672
|
+
});
|
|
3673
|
+
const r = { resources: list };
|
|
3674
|
+
if (nextCursor) r.nextCursor = nextCursor;
|
|
3675
|
+
return r;
|
|
3676
|
+
}
|
|
3677
|
+
function buildResourceReadResult(resource) {
|
|
3678
|
+
const contents = { uri: resource.uri };
|
|
3679
|
+
if (resource.mimeType !== void 0) contents.mimeType = resource.mimeType;
|
|
3680
|
+
if (resource.text !== void 0) contents.text = resource.text;
|
|
3681
|
+
else if (resource.blob !== void 0) contents.blob = resource.blob;
|
|
3682
|
+
return { contents: [contents] };
|
|
3683
|
+
}
|
|
3684
|
+
function buildPromptsListResult(prompts, nextCursor) {
|
|
3685
|
+
const list = prompts.map((p0) => {
|
|
3686
|
+
const out = { name: p0.name };
|
|
3687
|
+
if (p0.description !== void 0) out.description = p0.description;
|
|
3688
|
+
if (p0.arguments !== void 0) out.arguments = p0.arguments;
|
|
3689
|
+
return out;
|
|
3690
|
+
});
|
|
3691
|
+
const r = { prompts: list };
|
|
3692
|
+
if (nextCursor) r.nextCursor = nextCursor;
|
|
3693
|
+
return r;
|
|
3694
|
+
}
|
|
3695
|
+
function buildPromptGetResult(messages) {
|
|
3696
|
+
return { messages: messages ?? [] };
|
|
3697
|
+
}
|
|
3698
|
+
function parseCreateMessageResult(payload) {
|
|
3699
|
+
const r = payload ?? {};
|
|
3700
|
+
const content = r.content ?? { type: "text", text: "" };
|
|
3701
|
+
return {
|
|
3702
|
+
role: "assistant",
|
|
3703
|
+
content: typeof content.type === "string" ? content : { type: "text", text: "" },
|
|
3704
|
+
model: typeof r.model === "string" ? r.model : "unknown",
|
|
3705
|
+
stopReason: r.stopReason,
|
|
3706
|
+
stopSequence: typeof r.stopSequence === "string" ? r.stopSequence : void 0,
|
|
3707
|
+
usage: r.usage
|
|
3708
|
+
};
|
|
3709
|
+
}
|
|
3710
|
+
|
|
3711
|
+
// ../mcp/src/server/host.ts
|
|
3712
|
+
function mapAgentContentToMcp(blocks) {
|
|
3713
|
+
const out = [];
|
|
3714
|
+
for (const b of blocks) {
|
|
3715
|
+
out.push(mapOneAgentBlock(b));
|
|
3716
|
+
}
|
|
3717
|
+
return out.length ? out : [{ type: "text", text: "[empty result]" }];
|
|
3718
|
+
}
|
|
3719
|
+
function mapOneAgentBlock(b) {
|
|
3720
|
+
if (b.type === "text") {
|
|
3721
|
+
const t = b;
|
|
3722
|
+
return { type: "text", text: t.text };
|
|
3723
|
+
}
|
|
3724
|
+
if (b.type === "image") {
|
|
3725
|
+
const img = b;
|
|
3726
|
+
if (typeof img.data === "string" && typeof img.mimeType === "string") {
|
|
3727
|
+
return { type: "image", data: img.data, mimeType: img.mimeType };
|
|
3728
|
+
}
|
|
3729
|
+
return { type: "text", text: "[image: missing data/mimeType]" };
|
|
3730
|
+
}
|
|
3731
|
+
return { type: "text", text: JSON.stringify(b) };
|
|
3732
|
+
}
|
|
3733
|
+
function toolResultToMcpCallResult(result) {
|
|
3734
|
+
const isError = isToolResultError(result);
|
|
3735
|
+
return { content: mapAgentContentToMcp(result.content ?? []), isError: isError ? true : void 0 };
|
|
3736
|
+
}
|
|
3737
|
+
function isToolResultError(result) {
|
|
3738
|
+
const d = result.details;
|
|
3739
|
+
if (d && typeof d === "object" && "error" in d) {
|
|
3740
|
+
const e = d.error;
|
|
3741
|
+
return !!e || typeof e === "string";
|
|
3742
|
+
}
|
|
3743
|
+
return false;
|
|
3744
|
+
}
|
|
3745
|
+
var McpServerHost = class {
|
|
3746
|
+
serverInfo;
|
|
3747
|
+
toolsResolver;
|
|
3748
|
+
resourcesResolver;
|
|
3749
|
+
promptsResolver;
|
|
3750
|
+
authorize;
|
|
3751
|
+
toolTimeoutMs;
|
|
3752
|
+
onNotification;
|
|
3753
|
+
samplingEnabled;
|
|
3754
|
+
outboundRequest;
|
|
3755
|
+
capabilities;
|
|
3756
|
+
constructor(options) {
|
|
3757
|
+
this.serverInfo = { name: options.name, version: options.version ?? "0.1.0" };
|
|
3758
|
+
this.toolsResolver = typeof options.tools === "function" ? options.tools : () => options.tools;
|
|
3759
|
+
if (options.resources) {
|
|
3760
|
+
this.resourcesResolver = typeof options.resources === "function" ? options.resources : () => options.resources;
|
|
3761
|
+
}
|
|
3762
|
+
if (options.prompts) {
|
|
3763
|
+
this.promptsResolver = typeof options.prompts === "function" ? options.prompts : () => options.prompts;
|
|
3764
|
+
}
|
|
3765
|
+
this.authorize = options.authorize;
|
|
3766
|
+
this.toolTimeoutMs = options.toolTimeoutMs;
|
|
3767
|
+
this.onNotification = options.onNotification;
|
|
3768
|
+
this.outboundRequest = options.onOutboundRequest;
|
|
3769
|
+
this.samplingEnabled = options.sampling === true || !!options.onOutboundRequest;
|
|
3770
|
+
this.capabilities = this.computeCapabilities();
|
|
3771
|
+
}
|
|
3772
|
+
getServerInfo() {
|
|
3773
|
+
return { ...this.serverInfo };
|
|
3774
|
+
}
|
|
3775
|
+
getCapabilities() {
|
|
3776
|
+
return { ...this.capabilities };
|
|
3777
|
+
}
|
|
3778
|
+
computeCapabilities() {
|
|
3779
|
+
const caps = { tools: {} };
|
|
3780
|
+
if (this.resourcesResolver) caps.resources = {};
|
|
3781
|
+
if (this.promptsResolver) caps.prompts = {};
|
|
3782
|
+
if (this.samplingEnabled) caps.sampling = {};
|
|
3783
|
+
return caps;
|
|
3784
|
+
}
|
|
3785
|
+
/** 主动通知客户端工具列表已变更 */
|
|
3786
|
+
notifyToolsListChanged() {
|
|
3787
|
+
this.onNotification?.(createListChangedNotification());
|
|
3788
|
+
}
|
|
3789
|
+
/**
|
|
3790
|
+
* 注入出站请求通道(由传输层如 stdio-runner 调用):写入 JSON-RPC 请求
|
|
3791
|
+
* 并关联响应。注入后 `sampleLLM` 可向外部 client 请求 LLM 补全。
|
|
3792
|
+
*/
|
|
3793
|
+
setOutboundRequest(fn) {
|
|
3794
|
+
this.outboundRequest = fn;
|
|
3795
|
+
if (!this.samplingEnabled) {
|
|
3796
|
+
this.samplingEnabled = true;
|
|
3797
|
+
this.capabilities = this.computeCapabilities();
|
|
3798
|
+
}
|
|
3799
|
+
}
|
|
3800
|
+
/**
|
|
3801
|
+
* 经出站通道向外部 client 请求 LLM 补全(sampling/createMessage)。
|
|
3802
|
+
* 需传输层(stdio-runner)已注入出站通道;未注入则抛错。
|
|
3803
|
+
*/
|
|
3804
|
+
async sampleLLM(params) {
|
|
3805
|
+
if (!this.outboundRequest) {
|
|
3806
|
+
throw new Error("sampling unavailable: outbound request channel not attached");
|
|
3807
|
+
}
|
|
3808
|
+
const raw = await this.outboundRequest("sampling/createMessage", params);
|
|
3809
|
+
return parseCreateMessageResult(raw);
|
|
3810
|
+
}
|
|
3811
|
+
/**
|
|
3812
|
+
* 处理一条入站 JSON-RPC 消息。
|
|
3813
|
+
* - 请求 → 返回响应(JsonRpcResponse)
|
|
3814
|
+
* - 通知 → 返回 null(不回写)
|
|
3815
|
+
* - 响应 / 非法消息 → 返回 null
|
|
3816
|
+
*/
|
|
3817
|
+
async handleRequest(input) {
|
|
3818
|
+
const msg = classify(input);
|
|
3819
|
+
if (!msg) return null;
|
|
3820
|
+
if (isResponse(msg)) return null;
|
|
3821
|
+
if (isNotification(msg)) {
|
|
3822
|
+
return null;
|
|
3823
|
+
}
|
|
3824
|
+
if (!isRequest(msg)) return null;
|
|
3825
|
+
return this.onRequest(msg);
|
|
3826
|
+
}
|
|
3827
|
+
async onRequest(req) {
|
|
3828
|
+
try {
|
|
3829
|
+
switch (req.method) {
|
|
3830
|
+
case "initialize":
|
|
3831
|
+
return createSuccessResponse(
|
|
3832
|
+
req.id,
|
|
3833
|
+
createInitializeResult(this.serverInfo, this.capabilities)
|
|
3834
|
+
);
|
|
3835
|
+
case "notifications/initialized":
|
|
3836
|
+
return createSuccessResponse(req.id, {});
|
|
3837
|
+
case "tools/list":
|
|
3838
|
+
return createSuccessResponse(
|
|
3839
|
+
req.id,
|
|
3840
|
+
buildToolsListResult(await this.toToolInfos(await this.toolsResolver()))
|
|
3841
|
+
);
|
|
3842
|
+
case "tools/call":
|
|
3843
|
+
return createSuccessResponse(req.id, await this.handleToolCall(req));
|
|
3844
|
+
case "ping":
|
|
3845
|
+
return createSuccessResponse(req.id, {});
|
|
3846
|
+
case "resources/list":
|
|
3847
|
+
if (!this.resourcesResolver) break;
|
|
3848
|
+
return createSuccessResponse(
|
|
3849
|
+
req.id,
|
|
3850
|
+
buildResourcesListResult(await this.resourcesResolver())
|
|
3851
|
+
);
|
|
3852
|
+
case "resources/read": {
|
|
3853
|
+
if (!this.resourcesResolver) break;
|
|
3854
|
+
const { uri } = parseResourceReadParams(req.params);
|
|
3855
|
+
if (!uri) return createErrorResponse(req.id, INVALID_PARAMS, "resources/read requires uri");
|
|
3856
|
+
const found = (await this.resourcesResolver()).find((r) => r.uri === uri);
|
|
3857
|
+
if (!found) return createErrorResponse(req.id, INVALID_PARAMS, `resource not found: ${uri}`);
|
|
3858
|
+
return createSuccessResponse(req.id, buildResourceReadResult(found));
|
|
3859
|
+
}
|
|
3860
|
+
case "prompts/list":
|
|
3861
|
+
if (!this.promptsResolver) break;
|
|
3862
|
+
return createSuccessResponse(
|
|
3863
|
+
req.id,
|
|
3864
|
+
buildPromptsListResult(await this.promptsResolver())
|
|
3865
|
+
);
|
|
3866
|
+
case "prompts/get": {
|
|
3867
|
+
if (!this.promptsResolver) break;
|
|
3868
|
+
const { name } = parsePromptGetParams(req.params);
|
|
3869
|
+
if (!name) return createErrorResponse(req.id, INVALID_PARAMS, "prompts/get requires name");
|
|
3870
|
+
const found = (await this.promptsResolver()).find((p) => p.name === name);
|
|
3871
|
+
if (!found) return createErrorResponse(req.id, INVALID_PARAMS, `prompt not found: ${name}`);
|
|
3872
|
+
return createSuccessResponse(req.id, buildPromptGetResult(found.messages ?? []));
|
|
3873
|
+
}
|
|
3874
|
+
default:
|
|
3875
|
+
break;
|
|
3876
|
+
}
|
|
3877
|
+
return createErrorResponse(
|
|
3878
|
+
req.id,
|
|
3879
|
+
METHOD_NOT_FOUND,
|
|
3880
|
+
`method not found: ${req.method}`
|
|
3881
|
+
);
|
|
3882
|
+
} catch (err) {
|
|
3883
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
3884
|
+
return createErrorResponse(req.id, INTERNAL_ERROR, message);
|
|
3885
|
+
}
|
|
3886
|
+
}
|
|
3887
|
+
async handleToolCall(req) {
|
|
3888
|
+
const { name, arguments: args } = parseToolCallParams(req.params);
|
|
3889
|
+
if (!name) {
|
|
3890
|
+
return buildToolCallResult(
|
|
3891
|
+
[{ type: "text", text: "tools/call requires name" }],
|
|
3892
|
+
true
|
|
3893
|
+
);
|
|
3894
|
+
}
|
|
3895
|
+
const tools = await this.toolsResolver();
|
|
3896
|
+
const tool = tools.find((t) => t.name === name);
|
|
3897
|
+
if (!tool) {
|
|
3898
|
+
return buildToolCallResult(
|
|
3899
|
+
[{ type: "text", text: `unknown tool: ${name}` }],
|
|
3900
|
+
true
|
|
3901
|
+
);
|
|
3902
|
+
}
|
|
3903
|
+
const prepared = tool.prepareArguments ? tool.prepareArguments(args) : args;
|
|
3904
|
+
if (this.authorize) {
|
|
3905
|
+
const allowed = await this.authorize({
|
|
3906
|
+
toolName: tool.name,
|
|
3907
|
+
permissions: tool.permissions ?? [],
|
|
3908
|
+
args: prepared
|
|
3909
|
+
});
|
|
3910
|
+
if (!allowed) {
|
|
3911
|
+
return buildToolCallResult(
|
|
3912
|
+
[{ type: "text", text: `permission denied: ${tool.name}` }],
|
|
3913
|
+
true
|
|
3914
|
+
);
|
|
3915
|
+
}
|
|
3916
|
+
}
|
|
3917
|
+
let result;
|
|
3918
|
+
try {
|
|
3919
|
+
result = await this.callWithTimeout(tool, prepared);
|
|
3920
|
+
} catch (err) {
|
|
3921
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
3922
|
+
return buildToolCallResult(
|
|
3923
|
+
[{ type: "text", text: `tool execution failed: ${message}` }],
|
|
3924
|
+
true
|
|
3925
|
+
);
|
|
3926
|
+
}
|
|
3927
|
+
const mapped = toolResultToMcpCallResult(result);
|
|
3928
|
+
return buildToolCallResult(mapped.content, mapped.isError);
|
|
3929
|
+
}
|
|
3930
|
+
callWithTimeout(tool, args) {
|
|
3931
|
+
if (!this.toolTimeoutMs) return tool.execute("mcp", args);
|
|
3932
|
+
return new Promise((resolve, reject) => {
|
|
3933
|
+
const ac = new AbortController();
|
|
3934
|
+
const timer = setTimeout(() => {
|
|
3935
|
+
ac.abort();
|
|
3936
|
+
reject(new Error(`tools/call timeout: ${tool.name} (${this.toolTimeoutMs}ms)`));
|
|
3937
|
+
}, this.toolTimeoutMs);
|
|
3938
|
+
tool.execute("mcp", args, ac.signal).then(
|
|
3939
|
+
(r) => {
|
|
3940
|
+
clearTimeout(timer);
|
|
3941
|
+
resolve(r);
|
|
3942
|
+
},
|
|
3943
|
+
(e) => {
|
|
3944
|
+
clearTimeout(timer);
|
|
3945
|
+
reject(e);
|
|
3946
|
+
}
|
|
3947
|
+
);
|
|
3948
|
+
});
|
|
3949
|
+
}
|
|
3950
|
+
toToolInfos(tools) {
|
|
3951
|
+
return tools.map((t) => ({
|
|
3952
|
+
name: t.name,
|
|
3953
|
+
description: t.description,
|
|
3954
|
+
inputSchema: t.parameters
|
|
3955
|
+
}));
|
|
3956
|
+
}
|
|
3957
|
+
};
|
|
3958
|
+
function createMcpServerHost(options) {
|
|
3959
|
+
return new McpServerHost(options);
|
|
3960
|
+
}
|
|
3961
|
+
|
|
3573
3962
|
// extensions/mcp-bridge.ts
|
|
3574
3963
|
var MCPBridge = class {
|
|
3575
3964
|
graph;
|
|
@@ -3589,7 +3978,7 @@ var MCPBridge = class {
|
|
|
3589
3978
|
version: this.opts.serverVersion
|
|
3590
3979
|
};
|
|
3591
3980
|
}
|
|
3592
|
-
/** 列出所有可用 MCP
|
|
3981
|
+
/** 列出所有可用 MCP 工具(legacy 形状:MCPToolDefinition[]) */
|
|
3593
3982
|
listTools() {
|
|
3594
3983
|
const prefix = this.opts.toolPrefix;
|
|
3595
3984
|
return [
|
|
@@ -3612,53 +4001,62 @@ var MCPBridge = class {
|
|
|
3612
4001
|
}
|
|
3613
4002
|
];
|
|
3614
4003
|
}
|
|
3615
|
-
|
|
4004
|
+
// ─── 核心逻辑(handleCall 与 asTools 共享,单一来源)──────────────
|
|
4005
|
+
/** run 工具核心:执行图并序列化为 MCP 形状结果 */
|
|
4006
|
+
async runTool(input) {
|
|
4007
|
+
const inputText = input;
|
|
4008
|
+
if (!inputText) {
|
|
4009
|
+
return {
|
|
4010
|
+
isError: true,
|
|
4011
|
+
content: [{ type: "text", text: "\u7F3A\u5C11\u5FC5\u9700\u53C2\u6570: input" }]
|
|
4012
|
+
};
|
|
4013
|
+
}
|
|
4014
|
+
const result = await this.graph.run(inputText);
|
|
4015
|
+
return {
|
|
4016
|
+
content: [
|
|
4017
|
+
{
|
|
4018
|
+
type: "text",
|
|
4019
|
+
text: JSON.stringify({
|
|
4020
|
+
success: result.success,
|
|
4021
|
+
content: result.content,
|
|
4022
|
+
lastAgentId: result.lastAgentId,
|
|
4023
|
+
stepsCompleted: result.stepsCompleted,
|
|
4024
|
+
stopReason: result.stopReason,
|
|
4025
|
+
totalUsage: result.totalUsage
|
|
4026
|
+
}, null, 2)
|
|
4027
|
+
}
|
|
4028
|
+
]
|
|
4029
|
+
};
|
|
4030
|
+
}
|
|
4031
|
+
/** status 工具核心:图执行状态序列化为 MCP 形状结果 */
|
|
4032
|
+
statusTool() {
|
|
4033
|
+
const state = this.graph.getState();
|
|
4034
|
+
return {
|
|
4035
|
+
content: [
|
|
4036
|
+
{
|
|
4037
|
+
type: "text",
|
|
4038
|
+
text: JSON.stringify({
|
|
4039
|
+
currentAgentId: state.currentAgentId,
|
|
4040
|
+
stepsCompleted: state.stepsCompleted,
|
|
4041
|
+
finished: state.finished,
|
|
4042
|
+
error: state.error,
|
|
4043
|
+
nodeStates: Object.fromEntries(state.nodeStates)
|
|
4044
|
+
}, null, 2)
|
|
4045
|
+
}
|
|
4046
|
+
]
|
|
4047
|
+
};
|
|
4048
|
+
}
|
|
4049
|
+
/** 处理 MCP 工具调用(legacy API,行为保持不变) */
|
|
3616
4050
|
async handleCall(request) {
|
|
3617
4051
|
const prefix = this.opts.toolPrefix;
|
|
3618
|
-
const
|
|
3619
|
-
const
|
|
4052
|
+
const runToolName = `${prefix}run`;
|
|
4053
|
+
const statusToolName = `${prefix}status`;
|
|
3620
4054
|
try {
|
|
3621
|
-
if (request.name ===
|
|
3622
|
-
|
|
3623
|
-
if (!input) {
|
|
3624
|
-
return {
|
|
3625
|
-
isError: true,
|
|
3626
|
-
content: [{ type: "text", text: "\u7F3A\u5C11\u5FC5\u9700\u53C2\u6570: input" }]
|
|
3627
|
-
};
|
|
3628
|
-
}
|
|
3629
|
-
const result = await this.graph.run(input);
|
|
3630
|
-
return {
|
|
3631
|
-
content: [
|
|
3632
|
-
{
|
|
3633
|
-
type: "text",
|
|
3634
|
-
text: JSON.stringify({
|
|
3635
|
-
success: result.success,
|
|
3636
|
-
content: result.content,
|
|
3637
|
-
lastAgentId: result.lastAgentId,
|
|
3638
|
-
stepsCompleted: result.stepsCompleted,
|
|
3639
|
-
stopReason: result.stopReason,
|
|
3640
|
-
totalUsage: result.totalUsage
|
|
3641
|
-
}, null, 2)
|
|
3642
|
-
}
|
|
3643
|
-
]
|
|
3644
|
-
};
|
|
4055
|
+
if (request.name === runToolName) {
|
|
4056
|
+
return await this.runTool(request.arguments.input);
|
|
3645
4057
|
}
|
|
3646
|
-
if (request.name ===
|
|
3647
|
-
|
|
3648
|
-
return {
|
|
3649
|
-
content: [
|
|
3650
|
-
{
|
|
3651
|
-
type: "text",
|
|
3652
|
-
text: JSON.stringify({
|
|
3653
|
-
currentAgentId: state.currentAgentId,
|
|
3654
|
-
stepsCompleted: state.stepsCompleted,
|
|
3655
|
-
finished: state.finished,
|
|
3656
|
-
error: state.error,
|
|
3657
|
-
nodeStates: Object.fromEntries(state.nodeStates)
|
|
3658
|
-
}, null, 2)
|
|
3659
|
-
}
|
|
3660
|
-
]
|
|
3661
|
-
};
|
|
4058
|
+
if (request.name === statusToolName) {
|
|
4059
|
+
return this.statusTool();
|
|
3662
4060
|
}
|
|
3663
4061
|
return {
|
|
3664
4062
|
isError: true,
|
|
@@ -3676,10 +4074,70 @@ var MCPBridge = class {
|
|
|
3676
4074
|
};
|
|
3677
4075
|
}
|
|
3678
4076
|
}
|
|
4077
|
+
// ─── M3 统一:暴露为 agent 原生 Tool[],接入 McpServerHost / stdio 传输 ──
|
|
4078
|
+
/**
|
|
4079
|
+
* 将 AgentGraph 暴露为 agent 原生 `Tool[]`(JSON Schema 参数 + execute)。
|
|
4080
|
+
* 可直接喂给 `@aipack-ai/mcp` 的 `createMcpServerHost({ tools })`,
|
|
4081
|
+
* 再经 `runStdioServer` 拉起为标准 stdio MCP Server——补齐 MCPBridge
|
|
4082
|
+
* 原本缺失的传输层("由宿主环境负责实际的 MCP 传输" 这一缺口)。
|
|
4083
|
+
*
|
|
4084
|
+
* 工具 `${prefix}run` / `${prefix}status` 与 legacy `listTools()`/`handleCall()`
|
|
4085
|
+
* 共享 `runTool` / `statusTool` 核心,语义一致。
|
|
4086
|
+
*/
|
|
4087
|
+
asTools() {
|
|
4088
|
+
const prefix = this.opts.toolPrefix;
|
|
4089
|
+
return [
|
|
4090
|
+
{
|
|
4091
|
+
name: `${prefix}run`,
|
|
4092
|
+
description: "\u8FD0\u884C\u591AAgent\u7F16\u6392\u56FE\uFF0C\u4F20\u5165\u7528\u6237\u8F93\u5165\uFF0C\u8FD4\u56DE\u6267\u884C\u7ED3\u679C",
|
|
4093
|
+
parameters: {
|
|
4094
|
+
type: "object",
|
|
4095
|
+
properties: { input: { type: "string", description: "\u7528\u6237\u8F93\u5165\u6587\u672C" } },
|
|
4096
|
+
required: ["input"]
|
|
4097
|
+
},
|
|
4098
|
+
permissions: [],
|
|
4099
|
+
execute: async (_id, args) => {
|
|
4100
|
+
const input = args?.input;
|
|
4101
|
+
return toToolResult(await this.runTool(input));
|
|
4102
|
+
}
|
|
4103
|
+
},
|
|
4104
|
+
{
|
|
4105
|
+
name: `${prefix}status`,
|
|
4106
|
+
description: "\u83B7\u53D6\u5F53\u524D\u56FE\u6267\u884C\u72B6\u6001",
|
|
4107
|
+
parameters: { type: "object", properties: {} },
|
|
4108
|
+
permissions: [],
|
|
4109
|
+
execute: async () => toToolResult(this.statusTool())
|
|
4110
|
+
}
|
|
4111
|
+
];
|
|
4112
|
+
}
|
|
4113
|
+
/**
|
|
4114
|
+
* 构建一个 `McpServerHost`(来自 `@aipack-ai/mcp`),把本 AgentGraph 作为
|
|
4115
|
+
* 标准 MCP Server 暴露。配合 `runStdioServer(host)` 即可经 stdin/stdout
|
|
4116
|
+
* 服务外部 MCP 客户端(Claude Desktop / Cursor)。
|
|
4117
|
+
*
|
|
4118
|
+
* 与 legacy `handleCall()` 共享 `runTool` / `statusTool` 核心,保证语义一致。
|
|
4119
|
+
*/
|
|
4120
|
+
toMcpServerHost() {
|
|
4121
|
+
return createMcpServerHost({
|
|
4122
|
+
name: this.opts.serverName,
|
|
4123
|
+
version: this.opts.serverVersion,
|
|
4124
|
+
tools: this.asTools()
|
|
4125
|
+
});
|
|
4126
|
+
}
|
|
3679
4127
|
};
|
|
4128
|
+
function toToolResult(r) {
|
|
4129
|
+
const isError = r.isError === true;
|
|
4130
|
+
return {
|
|
4131
|
+
content: r.content,
|
|
4132
|
+
details: isError ? { error: r.content[0]?.text ?? "error" } : void 0
|
|
4133
|
+
};
|
|
4134
|
+
}
|
|
3680
4135
|
function createMCPBridge(graph, opts) {
|
|
3681
4136
|
return new MCPBridge(graph, opts);
|
|
3682
4137
|
}
|
|
4138
|
+
function createMultiAgentMcpServerHost(graph, opts) {
|
|
4139
|
+
return new MCPBridge(graph, opts).toMcpServerHost();
|
|
4140
|
+
}
|
|
3683
4141
|
|
|
3684
4142
|
// extensions/debug.ts
|
|
3685
4143
|
var GraphDebugger = class {
|
|
@@ -3847,6 +4305,7 @@ export {
|
|
|
3847
4305
|
createDebugger,
|
|
3848
4306
|
createMCPBridge,
|
|
3849
4307
|
createMapReduce,
|
|
4308
|
+
createMultiAgentMcpServerHost,
|
|
3850
4309
|
createPipeline,
|
|
3851
4310
|
createRouter,
|
|
3852
4311
|
createSharedContext,
|