aws-runtime-bridge 1.9.153 → 1.9.168
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/CHANGELOG.md +766 -0
- package/dist/adapter/AcodeSdkAdapter.d.ts +57 -6
- package/dist/adapter/AcodeSdkAdapter.js +4 -8
- package/dist/adapter/ClaudeSdkAdapter.d.ts +2 -0
- package/dist/adapter/ClaudeSdkAdapter.js +3 -3
- package/dist/adapter/CodexSdkAdapter.d.ts +2 -0
- package/dist/adapter/CodexSdkAdapter.js +3 -3
- package/dist/adapter/OpencodeSdkAdapter.d.ts +2 -0
- package/dist/adapter/OpencodeSdkAdapter.js +3 -3
- package/dist/adapter/prompts.d.ts +1 -1
- package/dist/adapter/prompts.js +1 -1
- package/dist/adapter/types.d.ts +41 -20
- package/dist/adapter/types.js +1 -1
- package/dist/browser/frame-encode.d.ts +25 -0
- package/dist/browser/frame-encode.js +2 -0
- package/dist/browser/screencast-differ.d.ts +2 -3
- package/dist/browser/screencast-differ.js +1 -1
- package/dist/browser/screencast-manager.js +1 -1
- package/dist/browser/types.d.ts +5 -1
- package/dist/browser/types.js +1 -1
- package/dist/desktop/desktop-mcp-client.js +2 -2
- package/dist/routes/acode-todos.js +1 -1
- package/dist/routes/background-tasks.js +3 -3
- package/dist/routes/capabilities.js +1 -1
- package/dist/routes/dashboard.d.ts +2 -0
- package/dist/routes/dashboard.js +4 -4
- package/dist/routes/git.js +22 -22
- package/dist/routes/instance.js +1 -1
- package/dist/routes/launch.js +10 -10
- package/dist/routes/ltr.js +1 -1
- package/dist/routes/mcp-extra.js +2 -2
- package/dist/routes/mcp.d.ts +4 -0
- package/dist/routes/mcp.js +1 -1
- package/dist/routes/plugins.js +1 -1
- package/dist/routes/pty.d.ts +11 -3
- package/dist/routes/pty.js +3 -3
- package/dist/routes/runtime-binding.js +1 -1
- package/dist/routes/sessions.d.ts +18 -74
- package/dist/routes/sessions.js +1 -1
- package/dist/routes/skills.js +1 -1
- package/dist/routes/sub-agents.js +8 -8
- package/dist/routes/terminal.d.ts +24 -2
- package/dist/routes/terminal.js +34 -36
- package/dist/services/agent-process-manager.js +1 -1
- package/dist/services/agent-pty-manager.js +4 -4
- package/dist/services/aws-client-agent-mcp.js +2 -2
- package/dist/services/capability-config.d.ts +8 -0
- package/dist/services/capability-config.js +2 -2
- package/dist/services/desktop-mcp-manager.d.ts +3 -1
- package/dist/services/desktop-mcp-manager.js +1 -1
- package/dist/services/instance-ai-config-service.js +1 -1
- package/dist/services/instance-features.d.ts +26 -2
- package/dist/services/instance-features.js +1 -1
- package/dist/services/instance-init-service.js +1 -1
- package/dist/services/launch-manager.d.ts +9 -1
- package/dist/services/launch-manager.js +6 -6
- package/dist/services/launch-metrics.d.ts +1 -1
- package/dist/services/launch-metrics.js +4 -3
- package/dist/services/mcp-deploy.d.ts +4 -0
- package/dist/services/mcp-env-injector.d.ts +12 -0
- package/dist/services/mcp-env-injector.js +2 -0
- package/dist/services/mcp-launch-binding-queue.d.ts +8 -0
- package/dist/services/mcp-launch-binding-queue.js +1 -1
- package/dist/services/orphan-monitor.js +1 -1
- package/dist/services/panel-env.d.ts +6 -2
- package/dist/services/panel-env.js +1 -1
- package/dist/services/plugin-manager.js +9 -9
- package/dist/services/process-detector.d.ts +23 -3
- package/dist/services/process-detector.js +13 -13
- package/dist/services/runtime-resources-snapshot.d.ts +3 -0
- package/dist/services/runtime-resources-snapshot.js +3 -0
- package/dist/services/session-output.d.ts +13 -0
- package/dist/services/session-output.js +4 -4
- package/dist/services/tunnel-client.js +1 -1
- package/dist/services/workspace-files.js +1 -1
- package/dist/services/workspace-watch.js +1 -1
- package/dist/types.d.ts +4 -0
- package/dist/utils/env-safety.d.ts +15 -0
- package/dist/utils/env-safety.js +2 -0
- package/dist/utils/lifecycle-log.d.ts +2 -0
- package/dist/utils/lifecycle-log.js +3 -0
- package/dist/utils/mcp-utils.js +1 -1
- package/package/acode/dist/ask-user-question-tool.js +1 -1
- package/package/acode/dist/await-complete-tool.js +1 -1
- package/package/acode/dist/background-command-manager.js +4 -4
- package/package/acode/dist/background-command-tools.js +1 -1
- package/package/acode/dist/built-in-file-tools.d.ts +31 -2
- package/package/acode/dist/built-in-file-tools.js +2 -2
- package/package/acode/dist/built-in-symbols-tool.js +1 -1
- package/package/acode/dist/builtins/shellCommandPreparation.d.ts +2 -0
- package/package/acode/dist/builtins/shellCommandPreparation.js +2 -2
- package/package/acode/dist/compaction.d.ts +10 -0
- package/package/acode/dist/compaction.js +6 -6
- package/package/acode/dist/context-overflow.d.ts +19 -0
- package/package/acode/dist/context-overflow.js +2 -0
- package/package/acode/dist/grammars/grammars/tree-sitter-lua.wasm +0 -0
- package/package/acode/dist/index.d.ts +4 -1
- package/package/acode/dist/index.js +1 -1
- package/package/acode/dist/mcpToolNames.d.ts +4 -0
- package/package/acode/dist/mcpToolNames.js +1 -1
- package/package/acode/dist/parsers/ast-cache.d.ts +12 -1
- package/package/acode/dist/parsers/ast-cache.js +1 -1
- package/package/acode/dist/parsers/language-queries.js +1 -1
- package/package/acode/dist/parsers/symbol-extractor.js +2 -2
- package/package/acode/dist/parsers/tree-sitter-loader.d.ts +1 -1
- package/package/acode/dist/parsers/tree-sitter-loader.js +1 -1
- package/package/acode/dist/plugin-types.d.ts +5 -0
- package/package/acode/dist/plugin-types.js +1 -0
- package/package/acode/dist/read-file-state.d.ts +48 -0
- package/package/acode/dist/read-file-state.js +2 -0
- package/package/acode/dist/runtime-environment.d.ts +2 -0
- package/package/acode/dist/runtime-environment.js +3 -2
- package/package/acode/dist/runtime.d.ts +124 -10
- package/package/acode/dist/runtime.js +27 -23
- package/package/acode/dist/skill-tool.js +3 -3
- package/package/acode/dist/sub-agent-manager.js +1 -1
- package/package/acode/dist/sub-agent-tools.js +5 -5
- package/package/acode/dist/todo-tool.js +3 -3
- package/package/acode/dist/tool-allocation.js +1 -1
- package/package/acode/dist/tool-concurrency/index.d.ts +5 -0
- package/package/acode/dist/tool-concurrency/index.js +2 -0
- package/package/acode/dist/tool-concurrency/observability.d.ts +46 -0
- package/package/acode/dist/tool-concurrency/observability.js +3 -0
- package/package/acode/dist/tool-concurrency/resource-lock.d.ts +25 -0
- package/package/acode/dist/tool-concurrency/resource-lock.js +2 -0
- package/package/acode/dist/tool-concurrency/scheduler.d.ts +30 -0
- package/package/acode/dist/tool-concurrency/scheduler.js +2 -0
- package/package/acode/dist/tool-concurrency/types.d.ts +80 -0
- package/package/acode/dist/tool-concurrency/types.js +2 -0
- package/package/acode/dist/tool-group-manager.d.ts +128 -0
- package/package/acode/dist/tool-group-manager.js +18 -0
- package/package/acode/dist/types.d.ts +20 -2
- package/package/acode/package.json +3 -3
- package/package/aws-client-agent-mcp/README.md +1 -0
- package/package/aws-client-agent-mcp/dist/agent-client.d.ts +20 -32
- package/package/aws-client-agent-mcp/dist/agent-client.js +1 -1
- package/package/aws-client-agent-mcp/dist/http-client.d.ts +10 -0
- package/package/aws-client-agent-mcp/dist/http-client.js +1 -1
- package/package/aws-client-agent-mcp/dist/logger.d.ts +2 -1
- package/package/aws-client-agent-mcp/dist/logger.js +2 -2
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +65 -10
- package/package/aws-client-agent-mcp/dist/mcp-server.js +30 -30
- package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +42 -7
- package/package/aws-client-agent-mcp/dist/mcp-tools.js +196 -21
- package/package/aws-client-agent-mcp/dist/memory-store.d.ts +2 -0
- package/package/aws-client-agent-mcp/dist/memory-store.js +3 -3
- package/package/aws-client-agent-mcp/dist/message-buffer.js +1 -1
- package/package/aws-client-agent-mcp/dist/office/office-equation.d.ts +5 -0
- package/package/aws-client-agent-mcp/dist/office/office-equation.js +2 -0
- package/package/aws-client-agent-mcp/dist/office/office-image.d.ts +12 -0
- package/package/aws-client-agent-mcp/dist/office/office-image.js +2 -0
- package/package/aws-client-agent-mcp/dist/office/office-workspace.d.ts +40 -0
- package/package/aws-client-agent-mcp/dist/office/office-workspace.js +2 -0
- package/package/aws-client-agent-mcp/dist/status-reporter.js +1 -1
- package/package/aws-client-agent-mcp/dist/tool-groups.d.ts +4 -0
- package/package/aws-client-agent-mcp/dist/tool-groups.js +2 -2
- package/package/aws-client-agent-mcp/dist/types.d.ts +56 -3
- package/package/aws-client-agent-mcp/dist/websocket-client.js +1 -1
- package/package/aws-client-agent-mcp/package.json +2 -1
- package/package.json +1 -1
- package/package/acode/dist/capability-prompt.d.ts +0 -16
- package/package/acode/dist/capability-prompt.js +0 -3
- package/package/acode/dist/plugin-tools.d.ts +0 -14
- package/package/acode/dist/plugin-tools.js +0 -9
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const b="mcp:";function $(h){return`${b}${h}`}function S(h){return h.startsWith(b)}class N{constructor(e){this.groups=new Map,this.expandedGroups=new Set,this.stateOf=e.stateOf}register(e){this.groups.set(e.key,e)}unregister(e){this.groups.delete(e),this.expandedGroups.delete(e)}getRegistration(e){return this.groups.get(e)}getAllGroups(){return Array.from(this.groups.values())}getConfigState(e){return this.stateOf(e)??"disabled"}isEnabled(e){return this.getConfigState(e)!=="disabled"}isExpanded(e){return this.expandedGroups.has(e)}expand(e){return this.groups.has(e)?this.expandedGroups.has(e)?0:(this.expandedGroups.add(e),1):-1}collapse(e){return this.groups.has(e)?this.expandedGroups.delete(e)?1:0:-1}resetExpanded(){this.expandedGroups.clear()}shouldShowToLLM(e){if(!e)return!0;const o=this.groups.get(e);if(!o)return!0;const s=this.getConfigState(e);return s==="disabled"?!1:s==="collapsed"&&o.collapsible?this.expandedGroups.has(e):!0}getGroupForExposedName(e){const o=e.indexOf("__"),s=o>0?e.slice(0,o):void 0,c=o>=0&&o<e.length-2?e.slice(o+2):void 0,r=()=>[...this.groups].filter(([,t])=>!t.serverName);for(const[t,a]of r())if(!(!a.toolNames||a.toolNames.length===0)){for(const d of a.toolNames)if(e===d||c!==void 0&&c===d)return t}for(const[t,a]of r())if(e.startsWith(`${t}_`)||c!==void 0&&(c.startsWith(`${t}_`)||c===t))return t;if(s){for(const[t,a]of this.groups)if(a.serverName&&a.serverName===s)return t}}findGroupByServerName(e){for(const[o,s]of this.groups)if(s.serverName===e)return o}shouldShowToLLMByName(e){const o=this.getGroupForExposedName(e);return this.shouldShowToLLM(o)}claimedToolNamesBySubGroups(){const e=new Set;for(const o of this.groups.values())if(!o.serverName)for(const s of o.toolNames??[])e.add(s);return e}listToolManifests(e,o){const s=this.groups.get(e);if(!s)return[];if(s.toolNames&&s.toolNames.length>0)return o.filter(r=>{const t=r.exposedName.includes("__")?r.exposedName.slice(r.exposedName.indexOf("__")+2):r.exposedName;return s.toolNames.includes(t)}).map(r=>({name:r.exposedName,description:r.description,inputSchema:r.inputSchema}));const c=`${e}_`;return o.filter(r=>{const t=r.exposedName.includes("__")?r.exposedName.slice(r.exposedName.indexOf("__")+2):r.exposedName;return t===e||t.startsWith(c)}).map(r=>({name:r.exposedName,description:r.description,inputSchema:r.inputSchema}))}buildCapabilityPrompt(){const e=[],o=[],s=[];for(const t of this.groups.values()){const a=this.getConfigState(t.key);a==="disabled"?s.push(t):a==="collapsed"&&t.collapsible?o.push(t):e.push(t)}const c=t=>`- ${t.key}\uFF1A${t.label}${t.summary?` \u2014\u2014 ${t.summary}`:""}`,r=["## \u53EF\u7528\u80FD\u529B",""];if(e.length>0||o.length>0){r.push("\u5DF2\u5F00\u542F\uFF1A");for(const t of e)r.push(`${c(t)}\uFF08\u5DE5\u5177\u5DF2\u53EF\u76F4\u63A5\u8C03\u7528\uFF09`);for(const t of o)r.push(`${c(t)}\uFF08\u5DE5\u5177\u5DF2\u6536\u8D77\uFF09`);o.length>0&&(r.push(""),r.push('\u6807\u8BB0\u300C\u5DE5\u5177\u5DF2\u6536\u8D77\u300D\u7684\u80FD\u529B\uFF1A\u5DE5\u5177\u9ED8\u8BA4\u6536\u8D77\u4EE5\u4FDD\u6301\u5DE5\u5177\u5217\u8868\u7A33\u5B9A\u5E76\u8282\u7701\u4E0A\u4E0B\u6587\uFF0C\u4EFB\u52A1\u9700\u8981\u65F6\u5148\u8C03\u7528 expand_tools({ group: "<\u4E0A\u8FF0\u7EC4 key>" }) \u5C55\u5F00\uFF0C\u5DE5\u5177\u5B9A\u4E49\u968F\u7ED3\u679C\u8FD4\u56DE\u540E\u5373\u53EF\u7ECF call_tool \u8C03\u7528\u3002\u6BCF\u6B21\u53EA\u80FD\u5C55\u5F00\u4E00\u4E2A\u7EC4\u3002group \u53C2\u6570\u5FC5\u987B\u9010\u5B57\u53D6\u81EA\u4E0A\u65B9\u6E05\u5355\u91CC\u7684\u7EC4 key\uFF1B\u6E05\u5355\u5916\u7684 key\uFF08\u5305\u62EC\u6309 mcp:{server\u540D} \u81EA\u884C\u63A8\u6D4B\u62FC\u51FA\u7684\uFF09\u5E76\u4E0D\u5B58\u5728\uFF0Cexpand_tools \u53EA\u4F1A\u8FD4\u56DE\u300C\u672A\u77E5\u5DE5\u5177\u7EC4\u300D\u2014\u2014\u9700\u8981\u6E05\u5355\u5916\u7684\u80FD\u529B\u65F6\u8BF4\u660E\u5B83\u672A\u5F00\u542F\u6216\u4E0D\u53EF\u7528\uFF0C\u4E0D\u8981\u81C6\u9020 key \u91CD\u8BD5\u3002'))}else r.push("\u5F53\u524D\u6CA1\u6709\u5DF2\u5F00\u542F\u7684\u6269\u5C55\u80FD\u529B\u3002");if(s.length>0){r.push(""),r.push("\u672A\u5F00\u542F\uFF08\u5DE5\u5177\u4E0D\u5728\u4F60\u7684\u5217\u8868\u4E2D\uFF09\u3002\u82E5\u4EFB\u52A1\u786E\u5B9E\u9700\u8981\uFF0C\u8BF7\u544A\u77E5\u7528\u6237\u53BB\u300C\u80FD\u529B\u914D\u7F6E\u300D\u4E2D\u5F00\u542F\u5BF9\u5E94\u5F00\u5173\uFF0C\u4E0D\u8981\u81EA\u884C\u5047\u8BBE\u4F60\u6709\u8BE5\u80FD\u529B\uFF1A");for(const t of s)r.push(`${c(t)}\uFF08\u9700\u7528\u6237\u5728\u300C\u80FD\u529B\u914D\u7F6E\u300D\u4E2D\u5F00\u542F\uFF09`)}return r.join(`
|
|
2
|
+
`)}registerFromMeta(e,o,s,c){this.groups.has(e)||this.register({key:e,label:o??e,summary:s??"",collapsible:!0})}addToolName(e,o){const s=this.groups.get(e);s&&(s.toolNames&&s.toolNames.includes(o)||(s.toolNames?s.toolNames.push(o):s.toolNames=[o]))}}function k(h){const{toolGroupManager:e,getAllTools:o,capabilityToolRelay:s}=h,c=()=>{const r=[];for(const t of e.getAllGroups())!t.collapsible||e.getConfigState(t.key)!=="collapsed"||r.push(`- ${t.key}\uFF1A${t.label}${t.summary?` \u2014\u2014 ${t.summary}`:""}`);return r.length===0?"":`
|
|
3
|
+
|
|
4
|
+
\u5F53\u524D\u53EF\u5C55\u5F00\u7684\u6536\u7EB3\u7EC4\uFF1A
|
|
5
|
+
`+r.join(`
|
|
6
|
+
`)};return{kind:"builtin",toolName:"expand_tools",exposedName:"expand_tools",description:'\u5C55\u5F00/\u6536\u8D77\u6536\u7EB3\u5DE5\u5177\u7EC4\u3002\u6536\u7EB3\u7EC4\u7684\u5DE5\u5177\u9ED8\u8BA4\u4E0D\u51FA\u73B0\u5728\u5DE5\u5177\u5217\u8868\u4E2D\uFF1B\u5C55\u5F00\u540E\u5DE5\u5177\u5B9A\u4E49\u968F\u672C\u5DE5\u5177\u7ED3\u679C\u8FD4\u56DE\uFF0C\u53EF\u7ECF call_tool \u8C03\u7528\u3002\u53C2\u6570\uFF1Agroup \u4E3A\u5177\u4F53\u7EC4 key\uFF08\u5982 pencil\u3001task\u3001mcp:my-server\uFF09\uFF0Caction \u4E3A "expand"\uFF08\u9ED8\u8BA4\uFF09\u6216 "collapse"\u3002\u4E0D\u652F\u6301\u6279\u91CF\u64CD\u4F5C\uFF1A\u6BCF\u6B21\u53EA\u80FD\u6307\u5B9A\u4E00\u4E2A\u7EC4\uFF0C\u591A\u7EC4\u9700\u5206\u6B21\u8C03\u7528\u3002',inputSchema:{type:"object",properties:{group:{type:"string",description:'\u7EC4 key\uFF08\u5982 pencil / task / mcp:my-server\uFF09\u3002\u5FC5\u987B\u6307\u5B9A\u5177\u4F53\u7EC4\uFF0C\u4E0D\u652F\u6301 "all" \u4E4B\u7C7B\u7684\u6279\u91CF\u53D6\u503C\u3002'},action:{type:"string",enum:["expand","collapse"],default:"expand",description:"expand=\u5C55\u5F00\uFF0Ccollapse=\u6536\u8D77"}},required:["group"],additionalProperties:!1},async execute(r){const t=String(r.group??"").trim(),a=String(r.action??"expand").trim();if(!t)return{ok:!1,error:"\u7F3A\u5C11 group \u53C2\u6570",hint:c()};if(a==="collapse"){const g=e.collapse(t);if(g<0)return{ok:!1,error:`\u672A\u77E5\u5DE5\u5177\u7EC4: ${t}`};if(s?.handlesGroup(t))try{await s.collapse(t)}catch{}return g===0?{ok:!0,status:"already-collapsed",group:t}:{ok:!0,status:"collapsed",group:t,hint:"\u5982\u9700\u91CD\u65B0\u4F7F\u7528\uFF0C\u8BF7\u518D\u6B21\u8C03\u7528 expand_tools\u3002"}}const d=e.getRegistration(t);if(!d){const g=c();return{ok:!1,error:`\u672A\u77E5\u5DE5\u5177\u7EC4: ${t}`,hint:g}}if(e.getConfigState(t)==="disabled")return{ok:!1,error:`\u80FD\u529B\u300C${d.label}\u300D\u672A\u5F00\u542F\uFF0C\u8BF7\u5728\u300C\u80FD\u529B\u914D\u7F6E\u300D\u4E2D\u5F00\u542F\u540E\u518D\u5C55\u5F00`};if(s?.handlesGroup(t)){let g;try{g=await s.expand(t)}catch(u){return{ok:!1,error:`\u5C55\u5F00\u300C${d.label}\u300D\u5931\u8D25: ${u instanceof Error?u.message:String(u)}`}}const n=e.expand(t);return{ok:!0,status:n===0?"already-expanded":"expanded",group:t,toolCount:g.length,tools:g,hint:n===0?"\u8BE5\u7EC4\u5DF2\u5728\u5C55\u5F00\u72B6\u6001\uFF0C\u53EF\u76F4\u63A5\u7ECF call_tool \u8C03\u7528\u3002":"\u5DE5\u5177\u5DF2\u5C55\u5F00\uFF0C\u4E0B\u4E00\u6761\u6D88\u606F\u5373\u53EF\u7ECF call_tool \u8C03\u7528\u3002"}}const i=e.expand(t);if(i<0)return{ok:!1,error:`\u672A\u77E5\u5DE5\u5177\u7EC4: ${t}`};const p=e.listToolManifests(t,o());return i===0?{ok:!0,status:"already-expanded",group:t,toolCount:p.length,tools:p,hint:"\u8BE5\u7EC4\u5DF2\u5728\u5C55\u5F00\u72B6\u6001\uFF0C\u53EF\u76F4\u63A5\u7ECF call_tool \u8C03\u7528\u3002"}:{ok:!0,status:"expanded",group:t,toolCount:p.length,tools:p,hint:"\u5DE5\u5177\u5DF2\u5C55\u5F00\uFF0C\u4E0B\u4E00\u6761\u6D88\u606F\u5373\u53EF\u7ECF call_tool \u8C03\u7528\u3002"}}}}function G(h){const{toolGroupManager:e,pluginBridge:o,findTool:s,dispatchTool:c,capabilityToolRelay:r}=h,t=(a,d)=>{if(r?.handlesTool(a))return!1;const f=d??e.getGroupForExposedName(a);return f&&!e.getRegistration(f)?!1:!f||!e.getRegistration(f).collapsible?!0:e.getConfigState(f)==="expanded"};return{kind:"builtin",toolName:"call_tool",exposedName:"call_tool",description:`\u4E2D\u8F6C\u8C03\u7528\u300C\u4E0D\u5728\u4F60\u7684\u5DE5\u5177\u5217\u8868\u4E2D\u300D\u7684\u5DE5\u5177\u3002\u4EC5\u6709\u4E24\u7C7B\u5DE5\u5177\u9700\u8981\u7ECF\u672C\u62A5\u6587\u53D1\u9001\uFF1A
|
|
7
|
+
1) \u5DF2\u6536\u7EB3\u7684\u5DE5\u5177\u7EC4\uFF1A\u5148 expand_tools({ group }) \u5C55\u5F00\uFF0C\u518D\u7528 call_tool({ name: "<\u5DE5\u5177\u540D>", arguments: {...} }) \u8C03\u7528\uFF1B
|
|
8
|
+
2) \u63D2\u4EF6\u5DE5\u5177\uFF1Aname \u4E3A"\u63D2\u4EF6\u540D.\u5DE5\u5177\u540D"\u9650\u5B9A\u540D\uFF08\u5982 "wechat-cli.send_msg"\uFF09\u3002
|
|
9
|
+
|
|
10
|
+
\u7981\u6B62\u7528\u9014\uFF08\u4F1A\u88AB\u62D2\u7EDD\uFF09\uFF1A\u5BF9\u5DE5\u5177\u5217\u8868\u4E2D**\u5DF2\u7ECF\u80FD\u76F4\u63A5\u8C03\u7528**\u7684\u5DE5\u5177\uFF08poll_message\u3001read_file\u3001browser_*\uFF08\u5C55\u5F00\u6001\u9664\u5916\uFF09\u7B49\uFF09\u8D70 call_tool\u3002\u76F4\u63A5\u8C03\u7528\u66F4\u7701\u4E00\u8F6E\u53C2\u6570\u6821\u9A8C\uFF0C\u4E14\u80FD\u4FDD\u6301\u5E76\u53D1/\u53EA\u8BFB\u8C03\u5EA6\u4E0E\u5DE5\u5177\u8C03\u7528\u7EDF\u8BA1\u7684\u51C6\u786E\u6027\u2014\u2014call_tool \u4E00\u5B9A\u662F\u72EC\u5360\u7684\uFF0C\u4F1A\u628A\u53EA\u8BFB\u5DE5\u5177\u964D\u7EA7\u4E3A\u4E32\u884C\u3002
|
|
11
|
+
|
|
12
|
+
\u63D2\u4EF6\u5DE5\u5177\u6A21\u5F0F\uFF08\u53EF\u9009\u63D2\u4EF6\uFF09\uFF1A
|
|
13
|
+
- action="catalog"\uFF1A\u8FD4\u56DE\u5F53\u524D\u5168\u90E8\u63D2\u4EF6\u76EE\u5F55\uFF08\u7D27\u51D1\uFF09
|
|
14
|
+
- action="schema" + tool="\u63D2\u4EF6\u540D.\u5DE5\u5177\u540D"\uFF1A\u8FD4\u56DE\u8BE5\u5DE5\u5177\u7684\u5B8C\u6574 inputSchema
|
|
15
|
+
- action="call"\uFF08\u9ED8\u8BA4\uFF09+ name="\u63D2\u4EF6\u540D.\u5DE5\u5177\u540D" + arguments={...}\uFF1A\u8C03\u7528\u63D2\u4EF6\u5DE5\u5177
|
|
16
|
+
|
|
17
|
+
\u8BF4\u660E\uFF1A\u53EA\u8C03\u5EA6\u5DF2\u5C55\u5F00\u7684\u6536\u7EB3\u7EC4\u5DE5\u5177\u4E0E\u63D2\u4EF6\u5DE5\u5177\uFF1B\u672A\u5C55\u5F00\u7684\u6536\u7EB3\u7EC4\u88AB\u62D2\u7EDD\u5E76\u5F15\u5BFC\u8C03\u7528 expand_tools\uFF1B\u5DF2\u76F4\u63A5\u53EF\u89C1\u7684\u5DE5\u5177\u88AB\u62D2\u7EDD\u5E76\u5F15\u5BFC\u76F4\u63A5\u8C03\u7528\u3002`,inputSchema:{type:"object",properties:{name:{type:"string",description:"\u5DE5\u5177\u540D\uFF08\u4EC5\u9650\u5DF2\u6536\u7EB3/\u5DF2\u5C55\u5F00\u7684\u5DE5\u5177\u7EC4\u5185\u5DE5\u5177\uFF0C\u5982 pencil_create_document\uFF09\uFF0C\u6216\u63D2\u4EF6\u9650\u5B9A\u540D\uFF08\u5982 wechat-cli.send_msg\uFF09"},arguments:{type:"object",description:"\u5DE5\u5177\u53C2\u6570\uFF08\u5BF9\u8C61\uFF0C\u53EF\u7701\u7565\uFF09"},action:{type:"string",enum:["call","catalog","schema"],default:"call",description:"call=\u8C03\u7528\u5DE5\u5177\uFF1Bcatalog=\u53D6\u63D2\u4EF6\u76EE\u5F55\uFF1Bschema=\u53D6\u63D2\u4EF6\u5DE5\u5177\u5B8C\u6574\u5B9A\u4E49"},tool:{type:"string",description:'action=schema \u65F6\u6307\u5B9A\u63D2\u4EF6\u5DE5\u5177\u9650\u5B9A\u540D\uFF08\u5982 "wechat-cli.send_msg"\uFF09\uFF1B\u4E5F\u652F\u6301 "\u63D2\u4EF6\u540D.*"'}},additionalProperties:!1},async execute(a,d){const f=String(a.action??"call").trim();if(f==="catalog"){if(!o)return{error:"\u63D2\u4EF6\u7CFB\u7EDF\u672A\u542F\u7528"};try{return await o.getCatalog()}catch(n){return{error:`\u63D2\u4EF6\u76EE\u5F55\u67E5\u8BE2\u5931\u8D25: ${n instanceof Error?n.message:String(n)}`}}}if(f==="schema"){if(!o)return{error:"\u63D2\u4EF6\u7CFB\u7EDF\u672A\u542F\u7528"};const n=String(a.tool??"").trim();if(!n)return{error:'\u7F3A\u5C11 tool \u53C2\u6570\uFF08\u9650\u5B9A\u540D "\u63D2\u4EF6\u540D.\u5DE5\u5177\u540D"\uFF09'};try{if(n.endsWith(".*")){const m=n.slice(0,-2),x=await o.getCatalog(),l=x.plugins.find(_=>_.plugin===m);if(!l)return{error:`\u63D2\u4EF6 ${m} \u672A\u5B89\u88C5\u6216\u5DF2\u505C\u7528`,catalog:x.plugins};const y=await Promise.all(l.tools.map(_=>o.getToolSchema(`${m}.${_.name}`)));return{plugin:m,schemas:y.filter(Boolean)}}const u=await o.getToolSchema(n);return u||{error:`\u672A\u77E5\u63D2\u4EF6\u5DE5\u5177: ${n}\uFF08\u53EF\u5148 action=catalog \u67E5\u770B\u76EE\u5F55\uFF09`}}catch(u){return{error:`\u63D2\u4EF6 schema \u67E5\u8BE2\u5931\u8D25: ${u instanceof Error?u.message:String(u)}`}}}const i=String(a.name??"").trim();if(!i)return{error:"\u7F3A\u5C11 name \u53C2\u6570\uFF08\u5DE5\u5177\u540D\u6216\u63D2\u4EF6\u9650\u5B9A\u540D\uFF09"};if(i.includes(".")){if(!o)return{error:"\u63D2\u4EF6\u7CFB\u7EDF\u672A\u542F\u7528"};const n=i.indexOf(".");if(n<=0||n>=i.length-1)return{error:`\u63D2\u4EF6\u9650\u5B9A\u540D\u4E0D\u5408\u6CD5: ${i}\uFF08\u5E94\u4E3A "\u63D2\u4EF6\u540D.\u5DE5\u5177\u540D"\uFF09`};const u=i.slice(0,n),m=i.slice(n+1);if(!m.trim())return{error:`\u63D2\u4EF6\u9650\u5B9A\u540D\u4E0D\u5408\u6CD5: ${i}\uFF08\u7F3A\u5C11\u5DE5\u5177\u540D\uFF09`};const x=a.arguments&&typeof a.arguments=="object"&&!Array.isArray(a.arguments)?a.arguments:{};try{const l=await o.invokeTool(u,m.trim(),x,{toolCallId:d?.toolCallId});if(l.ok)return l.result??{ok:!0};const y={error:l.error??"\u63D2\u4EF6\u5DE5\u5177\u8C03\u7528\u5931\u8D25"};return l.inputSchema!==void 0&&(y.inputSchema=l.inputSchema),typeof l.durationMs=="number"&&(y.durationMs=l.durationMs),y}catch(l){return{error:`\u63D2\u4EF6\u8C03\u7528\u5931\u8D25: ${l instanceof Error?l.message:String(l)}`}}}const p=s(i);if(!p){if(r?.handlesTool(i)){const n=e.getGroupForExposedName(i),u=n?e.getRegistration(n):void 0,m=n?e.getConfigState(n):"disabled";if(!n||!u||m==="disabled")return{error:`\u5DE5\u5177 ${i} \u6240\u5C5E\u7684\u80FD\u529B\u672A\u5F00\u542F\uFF0C\u8BF7\u544A\u77E5\u7528\u6237\u53BB\u300C\u80FD\u529B\u914D\u7F6E\u300D\u4E2D\u5F00\u542F`};if(!e.isExpanded(n))return{error:`\u5DE5\u5177\u96C6\u300C${u.label}\u300D\u5C1A\u672A\u5C55\u5F00\uFF0C\u8BF7\u5148\u8C03\u7528 expand_tools({ group: "${n}" }) \u5C55\u5F00\u540E\u518D\u8C03\u7528`,group:n};const x=a.arguments&&typeof a.arguments=="object"&&!Array.isArray(a.arguments)?a.arguments:{};try{const l=await r.call(i,x);return l.ok?l.result??{ok:!0}:{error:l.error??`\u8C03\u7528\u5DE5\u5177 ${i} \u5931\u8D25`}}catch(l){return{error:`\u8C03\u7528\u5DE5\u5177 ${i} \u5931\u8D25: ${l instanceof Error?l.message:String(l)}`}}}return{error:`\u672A\u77E5\u5DE5\u5177: ${i}\uFF08\u5DE5\u5177\u4E0D\u5728\u5F53\u524D\u4F1A\u8BDD\u7684\u5DE5\u5177\u5217\u8868\u4E2D\uFF09\u3002\u82E5\u5C5E\u4E8E\u5DF2\u5C55\u5F00\u7684\u6536\u7EB3\u7EC4\uFF0C\u68C0\u67E5\u5DE5\u5177\u540D\u662F\u5426\u6B63\u786E\u3002`}}if(t(i,p.group))return{error:`\u5DE5\u5177 ${i} \u672C\u5C31\u5728\u4F60\u7684\u5DE5\u5177\u5217\u8868\u4E2D\uFF0C\u53EF\u76F4\u63A5\u8C03\u7528\uFF0C\u65E0\u9700\u7ECF call_tool \u4E2D\u8F6C\u3002call_tool \u4EC5\u7528\u4E8E\uFF1A\u2460 expand_tools \u5C55\u5F00\u540E\u7684\u6536\u7EB3\u7EC4\u5DE5\u5177\uFF1B\u2461 \u63D2\u4EF6\u5DE5\u5177\uFF08"\u63D2\u4EF6\u540D.\u5DE5\u5177\u540D"\uFF09\u3002`};if(p.group){const n=e.getRegistration(p.group);if(n&&n.collapsible){const u=e.getConfigState(p.group);if(u==="disabled")return{error:`\u5DE5\u5177 ${i} \u6240\u5C5E\u7684\u80FD\u529B\u300C${n.label}\u300D\u672A\u5F00\u542F\uFF0C\u8BF7\u544A\u77E5\u7528\u6237\u53BB\u300C\u80FD\u529B\u914D\u7F6E\u300D\u4E2D\u5F00\u542F`};if(u==="collapsed"&&!e.isExpanded(p.group))return{error:`\u5DE5\u5177\u96C6\u300C${n.label}\u300D\u5C1A\u672A\u5C55\u5F00\uFF0C\u8BF7\u5148\u8C03\u7528 expand_tools({ group: "${p.group}" }) \u5C55\u5F00\u540E\u518D\u8C03\u7528`,group:p.group}}}const g=a.arguments&&typeof a.arguments=="object"&&!Array.isArray(a.arguments)?a.arguments:{};try{return await c(i,g,{toolCallId:d?.toolCallId})}catch(n){return{error:`\u8C03\u7528\u5DE5\u5177 ${i} \u5931\u8D25: ${n instanceof Error?n.message:String(n)}`}}}}}export{b as MCP_GROUP_KEY_PREFIX,N as ToolGroupManager,G as createCallToolTool,k as createExpandToolsTool,S as isMcpGroupKey,$ as mcpGroupKeyOf};
|
|
18
|
+
|
|
@@ -2,7 +2,7 @@ import type { SubAgentManager } from "./sub-agent-manager.js";
|
|
|
2
2
|
import type { ACodeMcpConnection } from "./runtime.js";
|
|
3
3
|
import type { TerminalManager } from "./terminal-types.js";
|
|
4
4
|
import type { ACodePluginBridge } from "./plugin-types.js";
|
|
5
|
-
import type { CapabilityState } from "./
|
|
5
|
+
import type { CapabilityState } from "./tool-group-manager.js";
|
|
6
6
|
export interface ACodeMcpServerSpec {
|
|
7
7
|
type?: "stdio" | "sse" | "http";
|
|
8
8
|
command?: string;
|
|
@@ -11,6 +11,10 @@ export interface ACodeMcpServerSpec {
|
|
|
11
11
|
cwd?: string;
|
|
12
12
|
url?: string;
|
|
13
13
|
headers?: Record<string, string>;
|
|
14
|
+
|
|
15
|
+
collapsed?: boolean;
|
|
16
|
+
|
|
17
|
+
description?: string;
|
|
14
18
|
[key: string]: unknown;
|
|
15
19
|
}
|
|
16
20
|
export interface ACodeConfigFile {
|
|
@@ -59,7 +63,7 @@ export interface ACodeSkillGroup {
|
|
|
59
63
|
exists: boolean;
|
|
60
64
|
skills: ACodeSkillMetadata[];
|
|
61
65
|
}
|
|
62
|
-
export type ACodeEventType = "session_started" | "startup_phase" | "ai_request" | "thinking_delta" | "assistant_delta" | "command_output" | "command_status" | "mcp_status" | "skill_status" | "warning" | "turn_complete" | "session_complete" | "context_compaction" | "question_request" | "tool_permission_request" | "error" | "background_command_completed";
|
|
66
|
+
export type ACodeEventType = "session_started" | "startup_phase" | "ai_request" | "iteration_usage" | "thinking_delta" | "assistant_delta" | "command_output" | "command_status" | "mcp_status" | "skill_status" | "warning" | "turn_complete" | "session_complete" | "context_compaction" | "question_request" | "tool_permission_request" | "error" | "background_command_completed";
|
|
63
67
|
export interface ACodeEvent {
|
|
64
68
|
type: ACodeEventType;
|
|
65
69
|
sessionId: string;
|
|
@@ -119,6 +123,8 @@ export interface ACodeRuntimeConfig {
|
|
|
119
123
|
rolePrompt?: string;
|
|
120
124
|
|
|
121
125
|
memory?: string;
|
|
126
|
+
|
|
127
|
+
resumeContext?: string;
|
|
122
128
|
env?: Record<string, string>;
|
|
123
129
|
commandDirs?: string[];
|
|
124
130
|
hooks?: ACodeHookHandler[];
|
|
@@ -142,6 +148,14 @@ export interface ACodeRuntimeConfig {
|
|
|
142
148
|
|
|
143
149
|
toolPermissionPolicy?: import("./built-in-file-tools.js").ToolPermissionPolicy;
|
|
144
150
|
|
|
151
|
+
enableStaleFileGuard?: boolean;
|
|
152
|
+
|
|
153
|
+
toolConcurrency?: {
|
|
154
|
+
enabled?: boolean;
|
|
155
|
+
maxReadOnly?: number;
|
|
156
|
+
maxBash?: number;
|
|
157
|
+
};
|
|
158
|
+
|
|
145
159
|
extraBuiltInTools?: import("./built-in-file-tools.js").ACodeBuiltInTool[];
|
|
146
160
|
|
|
147
161
|
subAgentSuiteTools?: import("./built-in-file-tools.js").ACodeBuiltInTool[];
|
|
@@ -149,6 +163,10 @@ export interface ACodeRuntimeConfig {
|
|
|
149
163
|
subAgentSuiteToolProvider?: (patterns: string[]) => Promise<import("./built-in-file-tools.js").ACodeBuiltInTool[]>;
|
|
150
164
|
|
|
151
165
|
capabilityState?: (featureKey: string) => CapabilityState;
|
|
166
|
+
|
|
167
|
+
capabilityToolRelay?: import("./tool-group-manager.js").CapabilityToolRelay;
|
|
168
|
+
|
|
169
|
+
runtimeResourcesProvider?: () => Promise<string | null | undefined>;
|
|
152
170
|
}
|
|
153
171
|
export interface ACodeResolvedProviderConfig {
|
|
154
172
|
model: string;
|
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
"acode": "dist/cli.js"
|
|
16
16
|
},
|
|
17
17
|
"scripts": {
|
|
18
|
-
"build": "tsc -p tsconfig.json && cpy grammars/** dist/grammars --parents
|
|
19
|
-
"build:
|
|
18
|
+
"build": "tsc -p tsconfig.json && cpy grammars/** dist/grammars --parents && node ../../scripts/minify-dist.mjs",
|
|
19
|
+
"build:incremental": "tsc -p tsconfig.json && cpy grammars/** dist/grammars --parents --skip-exist && node ../../scripts/minify-dist.mjs",
|
|
20
20
|
"test": "vitest run",
|
|
21
21
|
"test:watch": "vitest",
|
|
22
|
-
"test:legacy": "tsx --test src/runtime.test.ts src/mcpToolNames.test.ts src/compaction.test.ts src/compaction-tree.test.ts",
|
|
22
|
+
"test:legacy": "tsx --test --test-force-exit src/runtime.test.ts src/mcpToolNames.test.ts src/compaction.test.ts src/compaction-tree.test.ts",
|
|
23
23
|
"test:all": "npm run test:legacy && npm run test",
|
|
24
24
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
25
25
|
},
|
|
@@ -52,6 +52,7 @@ aws-client-agent-mcp
|
|
|
52
52
|
| `AWS_HEARTBEAT_INTERVAL` | 心跳间隔(毫秒) | `3000` |
|
|
53
53
|
| `AWS_HEARTBEAT_TIMEOUT` | 心跳超时时间(毫秒) | `9000` |
|
|
54
54
|
| `AWS_MCP_HTTP_URL` | 调度中心 MCP HTTP 调用地址 | 根据 `AWS_SERVER_URL` 推导为 `/mcp/call` |
|
|
55
|
+
| `AWS_ATTACHMENT_MAX_SIZE_MB` | 附件单文件大小上限(MB)。服务端还会按流程线模板的按项上限(`maxSizeMb`,默认 200MB)二次校验 | `200` |
|
|
55
56
|
|
|
56
57
|
> 注意:当前实现不再读取 `AWS_CONFIG_PATH`。作为 stdio MCP Server 运行时,stdout 必须只输出 JSON-RPC 消息,普通日志会输出到 stderr,避免污染 MCP 握手协议。
|
|
57
58
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
import type { MemoryStats } from "./memory-store.js";
|
|
3
3
|
import { StatusReporter } from "./status-reporter.js";
|
|
4
|
-
import type { AgentConfig,
|
|
4
|
+
import type { AgentConfig, BrowserListenerEvent, Card, DirectMessage, DmHistoryResponse, FetchUnreadMessagesOptions, FinishTaskRollbackArgs, GroupHistoryResponse, GroupRoomsResponse, HireBatchResult, HireColleagueArgs, MessageHandler, OnlineListResponse, PluginCatalogSnapshot, ProfileInfo, ProjectMembersResponse, RegisterResult, ReplyToRef, ServerConfig, SendDmResult, SendMessageResult, StartTaskRollbackArgs, TaskInstanceCommentArgs, UnreadMessagesResult } from "./types.js";
|
|
5
5
|
export type ProfileHandler = (profile: ProfileInfo) => void;
|
|
6
6
|
export type AgentConfigHandler = (data: Record<string, unknown>) => void;
|
|
7
7
|
export type SystemNotifyHandler = (data: Record<string, unknown>) => void;
|
|
@@ -52,30 +52,30 @@ export declare class AgentClient {
|
|
|
52
52
|
|
|
53
53
|
discoverGroupRooms(): Promise<GroupRoomsResponse>;
|
|
54
54
|
|
|
55
|
+
listProjectMembers(): Promise<ProjectMembersResponse>;
|
|
56
|
+
|
|
55
57
|
hireColleague(args: HireColleagueArgs): Promise<HireBatchResult>;
|
|
56
58
|
|
|
57
59
|
callAgentScopedTool<T = unknown>(toolName: string, args: Record<string, unknown>): Promise<T>;
|
|
58
60
|
|
|
59
61
|
reportMemoryStats(memoryStats: MemoryStats): Promise<void>;
|
|
60
62
|
|
|
61
|
-
sendGroupMessage(content: string, projectId?: string, roomId?: string, card?:
|
|
62
|
-
type: "pencil" | "draw";
|
|
63
|
-
docId: string;
|
|
64
|
-
title?: string;
|
|
65
|
-
description?: string;
|
|
66
|
-
}): Promise<SendMessageResult>;
|
|
63
|
+
sendGroupMessage(content: string, projectId?: string, roomId?: string, card?: Card, replyTo?: ReplyToRef[]): Promise<SendMessageResult>;
|
|
67
64
|
|
|
68
|
-
sendDirectMessage(targetId: string, content: string, waitReply?: boolean, replyToCallId?: string, timeoutMs?: number, card?:
|
|
69
|
-
type: "pencil" | "draw";
|
|
70
|
-
docId: string;
|
|
71
|
-
title?: string;
|
|
72
|
-
description?: string;
|
|
73
|
-
}): Promise<SendDmResult>;
|
|
65
|
+
sendDirectMessage(targetId: string, content: string, waitReply?: boolean, replyToCallId?: string, timeoutMs?: number, card?: Card, replyTo?: ReplyToRef[]): Promise<SendDmResult>;
|
|
74
66
|
|
|
75
67
|
sendCallAndWaitReply(targetId: string, content: string, timeoutMs?: number): Promise<DirectMessage>;
|
|
76
68
|
|
|
77
69
|
replyToCall(callId: string, targetId: string, content: string): Promise<SendDmResult>;
|
|
78
70
|
|
|
71
|
+
sendEmail(args: Record<string, unknown>): Promise<unknown>;
|
|
72
|
+
|
|
73
|
+
listEmails(args: Record<string, unknown>): Promise<unknown>;
|
|
74
|
+
|
|
75
|
+
readEmail(mailId: string): Promise<unknown>;
|
|
76
|
+
|
|
77
|
+
replyEmail(args: Record<string, unknown>): Promise<unknown>;
|
|
78
|
+
|
|
79
79
|
getDmHistory(targetUserId?: string, limit?: number, since?: string): Promise<DmHistoryResponse>;
|
|
80
80
|
|
|
81
81
|
getGroupHistory(limit?: number, roomId?: string, since?: string): Promise<GroupHistoryResponse>;
|
|
@@ -102,20 +102,6 @@ export declare class AgentClient {
|
|
|
102
102
|
|
|
103
103
|
notifyBridgeForceMessage(): Promise<void>;
|
|
104
104
|
|
|
105
|
-
setBridgeCapabilityTools(capability: string, action: "expand" | "collapse"): Promise<{
|
|
106
|
-
ok: boolean;
|
|
107
|
-
sessions?: number;
|
|
108
|
-
tools?: number;
|
|
109
|
-
manifests?: BridgeToolManifest[];
|
|
110
|
-
error?: string;
|
|
111
|
-
}>;
|
|
112
|
-
|
|
113
|
-
callBridgeCapabilityTool(capability: string, toolName: string, args: unknown): Promise<{
|
|
114
|
-
ok: boolean;
|
|
115
|
-
result?: unknown;
|
|
116
|
-
error?: string;
|
|
117
|
-
}>;
|
|
118
|
-
|
|
119
105
|
private fetchDirectMessagesWithRecovery;
|
|
120
106
|
|
|
121
107
|
private isRecoverableLongPollError;
|
|
@@ -129,18 +115,20 @@ export declare class AgentClient {
|
|
|
129
115
|
|
|
130
116
|
getMyTasks(): Promise<unknown[]>;
|
|
131
117
|
|
|
118
|
+
listTaskNodeIterations(args?: {
|
|
119
|
+
offset?: number;
|
|
120
|
+
limit?: number;
|
|
121
|
+
nodeTemplateId?: string;
|
|
122
|
+
}): Promise<unknown>;
|
|
123
|
+
|
|
132
124
|
createTaskInstanceComment(args: TaskInstanceCommentArgs): Promise<unknown>;
|
|
133
125
|
|
|
134
|
-
submitTaskResult(nodeId: string, outputPayload: string, changeLog?: unknown[]): Promise<unknown>;
|
|
126
|
+
submitTaskResult(nodeId: string, outputPayload: string, changeLog?: unknown[] | string, handoverNote?: string, deliverables?: unknown[]): Promise<unknown>;
|
|
135
127
|
|
|
136
128
|
startTaskRollback(args: StartTaskRollbackArgs): Promise<unknown>;
|
|
137
129
|
|
|
138
130
|
finishTaskRollback(args: FinishTaskRollbackArgs): Promise<unknown>;
|
|
139
131
|
|
|
140
|
-
rejectTask(nodeId: string, reason: string): Promise<unknown>;
|
|
141
|
-
|
|
142
|
-
terminateTask(taskInstanceId: string, reason: string): Promise<unknown>;
|
|
143
|
-
|
|
144
132
|
getDebugLogConfig(): Promise<unknown>;
|
|
145
133
|
|
|
146
134
|
queryDebugLogs(args: Record<string, unknown>): Promise<unknown>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{configManager as h}from"./config.js";import{MESSAGE_POLL_INTERVAL_MS as I}from"./constants.js";import{HttpClient as f}from"./http-client.js";import{logger as s,setMcpNodeLogSink as w,updateStartupLogIdentity as u}from"./logger.js";import{claimRuntimeLaunchBindingDetailed as m}from"./runtime-launch-binding.js";import{StatusReporter as A}from"./status-reporter.js";import{WebSocketClient as p}from"./websocket-client.js";class T extends Error{constructor(e){super(e),this.name="PollLongPollTimeoutError"}}const C=27e4;class N{wsClient;httpClient;agentConfig;serverConfig;agentId=null;displayName=null;projectId=null;isRunning=!1;isDegradedMode=!1;messageHandler=null;profileHandler=null;configHandler=null;systemNotifyHandler=null;pollTimer=null;statusReporter=null;newCharacterHandler=null;runtimeTokenRefreshTimer=null;pendingLaunchBindingClaim=!1;cachedProfile=null;constructor(){h.loadConfig(),this.agentConfig=h.getAgentConfig(),this.serverConfig=h.getServerConfig(),this.wsClient=new p(this.serverConfig),this.httpClient=new f(this.serverConfig),this.setupWebSocketListeners()}async initialize(){const e=await m(this.agentConfig,this.serverConfig);if(e.status==="claimed"){this.applyLaunchBinding(e.binding);return}if(e.status==="unreachable"){this.pendingLaunchBindingClaim=!0,s.warn("[AgentClient] runtime-bridge \u672A\u5C31\u7EEA\uFF0C\u542F\u52A8\u7ED1\u5B9A\u8BA4\u9886\u5DF2\u6302\u8D77\uFF0C\u5C06\u5728\u6CE8\u518C\u91CD\u8BD5\u4E2D\u91CD\u65B0\u8BA4\u9886: %s",e.message);return}this.serverConfig.runtimeBridgeBaseUrl=void 0}applyLaunchBinding(e){h.applyRuntimeLaunchBinding(e),this.agentConfig=h.getAgentConfig(),this.serverConfig=h.getServerConfig(),this.wsClient=new p(this.serverConfig),this.httpClient=new f(this.serverConfig),this.setupWebSocketListeners()}async retryPendingLaunchBindingClaim(){if(!this.pendingLaunchBindingClaim)return!0;const e=await m(this.agentConfig,this.serverConfig);if(e.status==="claimed")return this.pendingLaunchBindingClaim=!1,s.info("[AgentClient] \u542F\u52A8\u7ED1\u5B9A\u8865\u8BA4\u9886\u6210\u529F\uFF0C\u7EE7\u7EED\u6CE8\u518C\u6D41\u7A0B"),this.applyLaunchBinding(e.binding),!0;if(e.status==="missing")return this.pendingLaunchBindingClaim=!1,this.serverConfig.runtimeBridgeBaseUrl=void 0,s.warn("[AgentClient] \u542F\u52A8\u7ED1\u5B9A\u8865\u8BA4\u9886\u672A\u627E\u5230\u5F85\u8BA4\u9886\u8BB0\u5F55\uFF0C\u6309\u65E0\u7ED1\u5B9A\u6A21\u5F0F\u7EE7\u7EED\u6CE8\u518C"),!1;const t=e.status==="unreachable"?e.message:e.reason;return s.warn("[AgentClient] \u542F\u52A8\u7ED1\u5B9A\u8865\u8BA4\u9886\u5931\u8D25\uFF0C\u4FDD\u7559\u6302\u8D77\u72B6\u6001\u7B49\u5F85\u4E0B\u6B21\u6CE8\u518C\u91CD\u8BD5: %s",t),!1}setupWebSocketListeners(){this.wsClient.on("directMessage",e=>{this.handleIncomingDm(e)}),this.wsClient.on("groupMessage",e=>{this.handleIncomingGroup(e)}),this.wsClient.on("meetingMessage",e=>{this.handleIncomingMeeting(e)}),this.wsClient.on("systemNotify",e=>{this.systemNotifyHandler?.(e)}),this.wsClient.on("profileInfo",e=>{s.info(`[AgentClient] WebSocket profileInfo \u4E8B\u4EF6\u89E6\u53D1\uFF0CdisplayName: ${e.displayName}`),this.handleProfileInfo(e)}),this.wsClient.on("agentConfig",e=>{s.info("[AgentClient] WebSocket agentConfig \u4E8B\u4EF6\u89E6\u53D1"),this.configHandler&&this.configHandler(e??{})}),this.wsClient.on("agentStatus",e=>{s.info(`[AgentClient] WebSocket agentStatus \u4E8B\u4EF6\u89E6\u53D1: ${e.status}`)}),this.wsClient.on("disconnected",(e,t)=>{const n=t?.toString()||"";s.warn("[AgentClient] WebSocket \u65AD\u5F00\u8FDE\u63A5: code=%s, reason=%s, agentId=%s, \u6B63\u5728\u81EA\u52A8\u91CD\u8FDE",e,n,this.agentId)}),this.wsClient.on("error",e=>{s.error("[AgentClient] WebSocket \u9519\u8BEF: %s, stack=%s",e.message,e.stack)}),this.wsClient.on("reconnectFailed",()=>{s.error("[AgentClient] \u91CD\u8FDE\u5931\u8D25\uFF08\u5DF2\u8FBE\u91CD\u8BD5\u4E0A\u9650\uFF09\uFF0C\u505C\u6B62\u6D88\u606F\u5FAA\u73AF, agentId=%s",this.agentId),this.stop()}),this.wsClient.on("tokenRejected",()=>{s.error("[AgentClient] runtime token \u88AB 1008 \u62D2\u7EDD\u4E14\u5237\u65B0\u65E0\u53D8\u5316\uFF0C\u8FDB\u5165\u6162\u901F\u91CD\u8BD5\u7B49\u5F85\u65B0 token \u7B7E\u53D1: agentId=%s",this.agentId)}),this.wsClient.on("tokenRefreshFailed",e=>{s.error("[AgentClient] runtime token \u5237\u65B0\u8FDE\u7EED\u5931\u8D25 %s \u6B21\uFF0C\u8FDB\u5165\u6162\u901F\u91CD\u8BD5\u7B49\u5F85 bridge \u6062\u590D: agentId=%s",e,this.agentId)})}async register(){return s.info("[AgentClient] \u6B63\u5728\u6CE8\u518C Agent..."),await this.retryPendingLaunchBindingClaim(),this.hasPresetAgentId()?await this.registerWithExistingAgentId():await this.registerAsNewAgent()}hasPresetAgentId(){return!!(this.agentConfig.agentId&&this.agentConfig.agentId.trim().length>0)}async registerWithExistingAgentId(){const e=this.agentConfig.agentId;if(!e)throw new Error("Preset agentId is missing");this.agentId=e.trim();let t;try{t=await this.getProfileByAgentId(this.agentId)}catch(r){throw s.error("[AgentClient] getProfileByAgentId \u5931\u8D25 (presetAgentId=%s): %s",this.agentId,r instanceof Error?r.message:String(r)),r}this.displayName=t.displayName,this.projectId=t.projectId||null,s.info(`[AgentClient] \u4F7F\u7528\u9884\u8BBE AgentID \u7ED1\u5B9A\u5B9E\u4F8B: ${this.displayName} (${this.agentId})`),s.info(`[AgentClient] \u6240\u5C5E\u9879\u76EE: ${this.projectId||"(\u672A\u8BBE\u7F6E)"}`);try{await this.wsClient.connect(this.agentId)}catch(r){throw s.error("[AgentClient] WebSocket \u8FDE\u63A5\u5931\u8D25 (agentId=%s): %s",this.agentId,r instanceof Error?r.message:String(r)),r}s.info("[AgentClient] WebSocket \u8FDE\u63A5\u5DF2\u5EFA\u7ACB\uFF0CAgent \u73B0\u5728\u5DF2\u4E0A\u7EBF"),this.initializeStatusReporter();const n=await this.getProfileByAgentId(this.agentId);return this.displayName=n.displayName,this.projectId=n.projectId||null,u(n.roleName||"unknown-role",n.instanceName||this.agentId),{agentId:this.agentId,displayName:this.displayName,status:n.isOnline?"online":"offline",projectId:n.projectId,workspacePath:n.workspacePath,runtimeStatus:n.runtimeStatus,runtimeSessionId:n.runtimeSessionId}}async registerAsNewAgent(){const e=await this.httpClient.callTool("register",{roleName:this.agentConfig.roleName,projectId:this.agentConfig.projectId,workspacePath:this.agentConfig.workspacePath,prompt:this.agentConfig.prompt,runtimeBridgeBaseUrl:this.serverConfig.runtimeBridgeBaseUrl}),t=e.agentId;if(!t)throw new Error("Registration failed: agentId was not returned");return this.agentId=t,this.displayName=e.displayName,this.projectId=e.projectId||null,u(this.agentConfig.roleName||"unknown-role",e.instanceName||t),s.info(`[AgentClient] \u6CE8\u518C\u6210\u529F: ${this.displayName} (${this.agentId})`),s.info(`[AgentClient] \u72B6\u6001: ${e.status}`),s.info(`[AgentClient] \u6240\u5C5E\u9879\u76EE: ${this.projectId||"(\u672A\u8BBE\u7F6E)"}`),await this.wsClient.connect(this.agentId),s.info("[AgentClient] WebSocket \u8FDE\u63A5\u5DF2\u5EFA\u7ACB\uFF0CAgent \u73B0\u5728\u5DF2\u4E0A\u7EBF"),this.initializeStatusReporter(),e.isExisting===!1&&this.newCharacterHandler&&this.newCharacterHandler(),e}async unregister(){s.info("[AgentClient] \u6B63\u5728\u6CE8\u9500 Agent..."),this.agentId&&await this.httpClient.callTool("unregister",{agentId:this.agentId}),this.stopRuntimeTokenRefresh(),this.wsClient.disconnect(),this.agentId=null,this.displayName=null,this.projectId=null,this.isRunning=!1,s.info("[AgentClient] \u5DF2\u6CE8\u9500")}async discoverColleagues(){return await this.httpClient.callTool("discover_colleague",{agentId:this.agentId})}async discoverGroupRooms(){return this.ensureRegistered(),await this.httpClient.callTool("discover_group_rooms",{agentId:this.agentId})}async hireColleague(e){return this.ensureRegistered(),await this.httpClient.callTool("hire_colleague",{...e,agentId:this.agentId})}async callAgentScopedTool(e,t){this.ensureRegistered();const n={...t,agentId:this.agentId};if(e==="create_meeting"){const r=typeof t.waitTimeoutMs=="number"?t.waitTimeoutMs:Number.NaN,i=Number.isFinite(r)&&r>0?Math.min(r,C):C;return await this.httpClient.callToolOnce(e,{...n,waitTimeoutMs:i},0)}return await this.httpClient.callTool(e,n)}async reportMemoryStats(e){await this.callAgentScopedTool("report_memory_stats",{memoryStats:e})}async sendGroupMessage(e,t,n,r){this.ensureRegistered();const i=t||this.projectId||this.agentConfig.projectId;return await this.httpClient.callTool("send_group_message",{agentId:this.agentId,projectId:i,roomId:n,content:e,card:r})}async sendDirectMessage(e,t,n=!1,r,i,a){this.ensureRegistered();const o={agentId:this.agentId,targetId:e,content:t,requireReply:n,waitReply:n,replyToCallId:r,card:a};if(typeof i=="number"&&i>0&&(o.timeoutMs=i),n){const g=typeof i=="number"&&i>0?i+3e4:0;return await this.httpClient.callToolOnce("send_dm",o,g)}return await this.httpClient.callTool("send_dm",o)}async sendCallAndWaitReply(e,t,n=6e4){const r=await this.sendDirectMessage(e,t,!0,void 0,n);if(r.reply)return r.reply;throw new Error("No reply received for call-style direct message before timeout")}async replyToCall(e,t,n){return await this.sendDirectMessage(t,n,!1,e)}async getDmHistory(e,t=50,n){this.ensureRegistered();const r={agentId:this.agentId,targetUserId:e,limit:t};return n&&(r.since=n),await this.httpClient.callTool("get_dm_history",r)}async getGroupHistory(e=50,t,n){if(this.ensureRegistered(),t){const l={projectId:this.projectId||this.agentConfig.projectId,roomId:t,limit:e};return n&&(l.since=n),await this.httpClient.callTool("get_group_history",l)}const r=await this.discoverGroupRooms(),i=this.projectId||this.agentConfig.projectId,a=this.collectRoomIds(r,i);if(a.length===0)return{messages:[],count:0};const g=(await Promise.all(a.map(async l=>{const c={projectId:i,roomId:l,limit:e};return n&&(c.since=n),await this.httpClient.callTool("get_group_history",c)}))).flatMap(l=>l.messages).sort((l,c)=>new Date(l.timestamp).getTime()-new Date(c.timestamp).getTime());return{messages:g,count:g.length}}async fetchUnreadMessages(e={}){this.ensureRegistered();const t=this.projectId||this.agentConfig.projectId,n={agentId:this.agentId,blockIfEmpty:e.blockIfEmpty??!1};e.since&&(n.since=e.since),e.blockTimeoutMs&&e.blockTimeoutMs>0&&(n.blockTimeoutMs=e.blockTimeoutMs),e.preemptiveJoinWaitMs!==void 0&&e.preemptiveJoinWaitMs!==null&&e.preemptiveJoinWaitMs>=0&&(n.preemptiveJoinWaitMs=e.preemptiveJoinWaitMs);const r=e.includePipelineTasks?"poll_message":"get_dm_messages";s.info("[AgentClient] fetchUnreadMessages \u5165\u53E3: tool=%s, blockIfEmpty=%s, blockTimeoutMs=%s, pollMessageTimeoutMs=%s, skipGroupMessages=%s, preemptiveJoinWaitMs=%s, agentId=%s",r,String(e.blockIfEmpty??!1),String(e.blockTimeoutMs??"-"),String(e.pollMessageTimeoutMs??"-"),String(e.skipGroupMessages??!1),String(e.preemptiveJoinWaitMs??"-"),this.agentId);const i=await this.fetchDirectMessagesWithRecovery(r,n,e.pollMessageTimeoutMs,e.propagatePollTimeout===!0);if(s.info("[AgentClient] fetchUnreadMessages \u79C1\u4FE1\u9636\u6BB5\u8FD4\u56DE: %s \u6761",Array.isArray(i.messages)?i.messages.length:0),e.skipGroupMessages)return s.info("[AgentClient] \u4F1A\u8BAE\u5FEB\u901F hydrate \u5DF2\u53D6\u5F97\u79C1\u4FE1\u54CD\u5E94\uFF0C\u8DF3\u8FC7\u7FA4\u804A\u53D1\u73B0\u5E76\u7ACB\u5373\u8FD4\u56DE: directMessages=%s",Array.isArray(i.messages)?i.messages.length:0),{directMessages:Array.isArray(i.messages)?i.messages:[],groupMessages:[]};let a;try{a=await this.discoverGroupRooms()}catch(l){s.warn("[AgentClient] \u53D1\u73B0\u7FA4\u623F\u95F4\u5931\u8D25\uFF0C\u672C\u6B21\u6309\u65E0\u7FA4\u6D88\u606F\u5904\u7406\uFF08\u5DF2\u53D6\u5230\u7684\u79C1\u4FE1\u4E0D\u53D7\u5F71\u54CD\uFF09: %s",l instanceof Error?l.message:String(l)),a={groups:[]}}const o=this.collectRoomIds(a,t),g=await Promise.all(o.map(async l=>{const c={agentId:this.agentId,projectId:t,roomId:l};e.since&&(c.since=e.since);try{return await this.httpClient.callTool("get_group_messages",c)}catch(d){return s.warn("[AgentClient] \u8DF3\u8FC7\u7FA4\u623F\u95F4\u672A\u8BFB\u8865\u62C9\u5931\u8D25: roomId=%s, error=%s",l,d instanceof Error?d.message:String(d)),{messages:[],currentReadPos:0,hasMore:!1}}}));return{directMessages:Array.isArray(i.messages)?i.messages:[],groupMessages:g.flatMap(l=>this.normalizeGroupMessages(l)).sort((l,c)=>new Date(l.timestamp).getTime()-new Date(c.timestamp).getTime())}}async markDmRead(e){if(e.length===0)return new Set;this.ensureRegistered();try{const t=await this.httpClient.callTool("mark_dm_read",{agentId:this.agentId,msgIds:e}),n=new Set(Array.isArray(t?.deliverableMsgIds)?t.deliverableMsgIds:[]),r=e.filter(i=>!n.has(i));return r.length>0?s.warn("[AgentClient] mark_dm_read \u786E\u8BA4\u540E\u5C06\u6709 %d \u6761\u6D88\u606F\u88AB\u4E22\u5F03\u4E0D\u4EA4\u4ED8: \u8BF7\u6C42=%s, \u53EF\u4EA4\u4ED8=%s, \u88AB\u4E22\u5F03=%s",r.length,JSON.stringify(e),JSON.stringify([...n]),JSON.stringify(r)):s.info("[AgentClient] mark_dm_read \u786E\u8BA4\u5B8C\u6210: %d \u6761\u5168\u90E8\u53EF\u4EA4\u4ED8",e.length),n}catch(t){throw s.warn("[AgentClient] mark_dm_read \u8BF7\u6C42\u5931\u8D25\uFF08\u5C06\u964D\u7EA7\u4E3A\u76F4\u63A5\u4EA4\u4ED8\uFF09: %s",t instanceof Error?t.message:String(t)),t}}async markGroupRead(e,t){if(t.length===0)return new Set;this.ensureRegistered();const n=await this.httpClient.callTool("mark_group_read",{agentId:this.agentId,roomId:e,msgIds:t});return new Set(Array.isArray(n?.deliverableMsgIds)?n.deliverableMsgIds:[])}async markNotificationRead(e){if(e.length!==0){this.ensureRegistered();try{await this.httpClient.callTool("mark_notification_read",{agentId:this.agentId,msgIds:e})}catch{}}}async markMeetingRead(e){if(e.length!==0){this.ensureRegistered();try{await this.httpClient.callTool("mark_meeting_read",{agentId:this.agentId,msgIds:e})}catch{}}}async fetchBrowserListenerEvents(){const e=this.serverConfig.runtimeBridgeBaseUrl,t=this.agentId;if(!e||!t)return s.info("[AgentClient] fetchBrowserListenerEvents \u8DF3\u8FC7: bridgeBaseUrl=%s, agentId=%s",e||"(\u7A7A)",t||"(\u7A7A)"),[];try{const n=`${e}/runtime/browser-listeners/${encodeURIComponent(t)}/events`,r=this.serverConfig.runtimeAccessToken||"";s.debug("[AgentClient] \u62C9\u53D6\u76D1\u542C\u5668\u4E8B\u4EF6: url=%s, tokenLen=%d",n,r.length);const i=await fetch(n,{method:"GET",headers:{"X-Runtime-Token":r},signal:AbortSignal.timeout(3e3)});if(!i.ok)return s.warn("[AgentClient] \u62C9\u53D6\u76D1\u542C\u5668\u4E8B\u4EF6\u5931\u8D25: HTTP %s, url=%s",i.status,n),[];const a=await i.json();return!a.ok||!Array.isArray(a.events)?(s.warn("[AgentClient] \u62C9\u53D6\u76D1\u542C\u5668\u4E8B\u4EF6\u54CD\u5E94\u5F02\u5E38: ok=%s, eventsType=%s",a.ok,Array.isArray(a.events)?"array":typeof a.events),[]):(s.debug("[AgentClient] \u62C9\u53D6\u76D1\u542C\u5668\u4E8B\u4EF6\u6210\u529F: %d \u6761\u4E8B\u4EF6",a.events.length),a.events)}catch(n){return s.warn("[AgentClient] \u62C9\u53D6\u76D1\u542C\u5668\u4E8B\u4EF6\u5F02\u5E38: %s",n instanceof Error?n.message:String(n)),[]}}async fetchPluginEvents(){const e=this.serverConfig.runtimeBridgeBaseUrl,t=this.agentId;if(!e||!t)return{revision:0,events:[],catalog:null,compactionSeq:0};try{const n=`${e}/runtime/plugin-events/${encodeURIComponent(t)}/events`,r=this.serverConfig.runtimeAccessToken||"",i=await fetch(n,{method:"GET",headers:{"X-Runtime-Token":r},signal:AbortSignal.timeout(3e3)});if(!i.ok)return s.warn("[AgentClient] \u62C9\u53D6\u63D2\u4EF6\u4E8B\u4EF6\u5931\u8D25: HTTP %s, url=%s",i.status,n),{revision:0,events:[],catalog:null,compactionSeq:0};const a=await i.json();return!a.ok||!Array.isArray(a.events)?(s.warn("[AgentClient] \u62C9\u53D6\u63D2\u4EF6\u4E8B\u4EF6\u54CD\u5E94\u5F02\u5E38: ok=%s",String(a.ok)),{revision:0,events:[],catalog:null,compactionSeq:0}):(s.debug("[AgentClient] \u62C9\u53D6\u63D2\u4EF6\u4E8B\u4EF6\u6210\u529F: %d \u6761\u4E8B\u4EF6, revision=%s, catalog=%s, compactionSeq=%s",a.events.length,String(a.revision??0),a.catalog?`${a.catalog.plugins.length} \u4E2A\u63D2\u4EF6`:"null",String(a.compactionSeq??0)),{revision:a.revision??0,events:a.events,catalog:a.catalog??null,compactionSeq:typeof a.compactionSeq=="number"&&Number.isFinite(a.compactionSeq)?a.compactionSeq:0})}catch(n){return s.warn("[AgentClient] \u62C9\u53D6\u63D2\u4EF6\u4E8B\u4EF6\u5F02\u5E38: %s",n instanceof Error?n.message:String(n)),{revision:0,events:[],catalog:null,compactionSeq:0}}}async notifyBridgeForceMessage(){const e=this.serverConfig.runtimeBridgeBaseUrl,t=this.agentId;if(!(!e||!t))try{const n=`${e}/runtime/sessions/${encodeURIComponent(t)}/notify-force-message`,r=this.serverConfig.runtimeAccessToken||"",i=await fetch(n,{method:"POST",headers:{"X-Runtime-Token":r},signal:AbortSignal.timeout(3e3)});i.ok||s.warn("[AgentClient] \u901A\u77E5 bridge \u5F3A\u5236\u6D88\u606F\u5931\u8D25: HTTP %s, url=%s",i.status,n)}catch(n){s.warn("[AgentClient] \u901A\u77E5 bridge \u5F3A\u5236\u6D88\u606F\u5F02\u5E38: %s",n instanceof Error?n.message:String(n))}}async setBridgeCapabilityTools(e,t){const n=this.serverConfig.runtimeBridgeBaseUrl,r=this.agentId;if(!n||!r)return{ok:!1,error:"\u7F3A\u5C11 bridge \u5730\u5740\u6216 agentId"};try{const i=`${n}/runtime/sessions/${encodeURIComponent(r)}/capability-tools`,a=await fetch(i,{method:"POST",headers:{"Content-Type":"application/json","X-Runtime-Token":this.serverConfig.runtimeAccessToken||""},body:JSON.stringify({capability:e,action:t}),signal:AbortSignal.timeout(5e3)}),o=await a.json().catch(()=>null);return!a.ok||o?.ok===!1?(s.warn("[AgentClient] \u56DE\u4F20\u80FD\u529B\u5DE5\u5177\u5207\u6362\u5931\u8D25: HTTP %s, url=%s",a.status,i),{ok:!1,error:o?.error||`HTTP ${a.status}`}):{ok:!0,sessions:o?.changed?.sessions??0,tools:o?.changed?.tools??0,manifests:Array.isArray(o?.manifests)?o.manifests:void 0}}catch(i){return s.warn("[AgentClient] \u56DE\u4F20\u80FD\u529B\u5DE5\u5177\u5207\u6362\u5F02\u5E38: %s",i instanceof Error?i.message:String(i)),{ok:!1,error:i instanceof Error?i.message:String(i)}}}async callBridgeCapabilityTool(e,t,n){const r=this.serverConfig.runtimeBridgeBaseUrl,i=this.agentId;if(!r||!i)return{ok:!1,error:"\u7F3A\u5C11 bridge \u5730\u5740\u6216 agentId"};try{const a=`${r}/runtime/sessions/${encodeURIComponent(i)}/capability-tools/call`,o=await fetch(a,{method:"POST",headers:{"Content-Type":"application/json","X-Runtime-Token":this.serverConfig.runtimeAccessToken||""},body:JSON.stringify({capability:e,tool:t,arguments:n??{}}),signal:AbortSignal.timeout(55e3)}),g=await o.json().catch(()=>null);return!o.ok||g?.ok===!1?(s.warn("[AgentClient] \u6865\u63A5\u80FD\u529B\u5DE5\u5177\u6267\u884C\u5931\u8D25: HTTP %s, url=%s, tool=%s",o.status,a,t),{ok:!1,error:g?.error||`HTTP ${o.status}`}):{ok:!0,result:g?.result}}catch(a){return s.warn("[AgentClient] \u6865\u63A5\u80FD\u529B\u5DE5\u5177\u6267\u884C\u5F02\u5E38: %s",a instanceof Error?a.message:String(a)),{ok:!1,error:a instanceof Error?a.message:String(a)}}}async fetchDirectMessagesWithRecovery(e,t,n,r=!1){if(e==="poll_message"){s.info("[AgentClient] fetchDirectMessagesWithRecovery \u5165\u53E3: tool=poll_message, pollMessageTimeoutMs=%s, agentId=%s",String(n??"(\u9ED8\u8BA4)"),String(t?.agentId??""));try{const i=await this.httpClient.callToolOnce(e,t,n);return s.info("[AgentClient] fetchDirectMessagesWithRecovery poll_message \u6210\u529F\u8FD4\u56DE: %s \u6761",Array.isArray(i?.messages)?i.messages.length:0),i}catch(i){if(this.isRecoverableLongPollError(i)){if(r)throw new T(i instanceof Error?i.message:String(i));return s.warn("[AgentClient] poll_message \u5355\u6B21\u957F\u8F6E\u8BE2\u8D85\u65F6\uFF0C\u6309\u7A7A\u7ED3\u679C\u9000\u907F\u540E\u7EE7\u7EED\u7B49\u5F85:",i),{messages:[]}}throw i}}return await this.httpClient.callTool(e,t)}isRecoverableLongPollError(e){return e instanceof Error?/MCP tool poll_message call failed: 503(?:\s|$)/.test(e.message)||/MCP tool poll_message timed out after \d+ms/.test(e.message):!1}normalizeGroupMessages(e){return Array.isArray(e.messages)?e.messages.filter(t=>!!(t&&typeof t=="object"&&typeof t.msgId=="number"&&typeof t.senderId=="string"&&typeof t.content=="string"&&typeof t.timestamp=="string")):[]}collectRoomIds(e,t){const n=e.groups.filter(r=>r.projectId===t).map(r=>r.id);return Array.from(new Set(n))}async getProfile(){this.ensureRegistered();const e=this.agentId;if(!e)throw new Error("Agent is not registered");return{...await this.getProfileByAgentId(e),describe:this.agentConfig.describe}}async getProfileByAgentId(e){return await this.httpClient.callTool("get_profile",{agentId:e})}async getMyTasks(){return this.ensureRegistered(),await this.httpClient.callTool("my_task",{agentId:this.agentId})}async createTaskInstanceComment(e){this.ensureRegistered();const t={agentId:this.agentId,...e};return await this.httpClient.callTool("create_task_instance_comment",t)}async submitTaskResult(e,t,n){this.ensureRegistered();const r={agentId:this.agentId,nodeId:e,outputPayload:t};return n&&Array.isArray(n)&&n.length>0&&(r.changeLog=n),await this.httpClient.callTool("submit_task_result",r)}async startTaskRollback(e){return this.ensureRegistered(),await this.httpClient.callTool("start_task_rollback",{agentId:this.agentId,...e})}async finishTaskRollback(e){return this.ensureRegistered(),await this.httpClient.callTool("finish_task_rollback",{agentId:this.agentId,...e})}async rejectTask(e,t){return this.ensureRegistered(),await this.httpClient.callTool("reject_task",{agentId:this.agentId,nodeId:e,reason:t})}async terminateTask(e,t){return this.ensureRegistered(),await this.httpClient.callTool("terminate_task",{agentId:this.agentId,taskInstanceId:e,reason:t})}async getDebugLogConfig(){return await this.httpClient.callTool("get_debug_log_config",{agentId:this.agentId})}async queryDebugLogs(e){return this.ensureRegistered(),await this.httpClient.callTool("query_debug_logs",{...e})}async queryFileChangesHistory(e){return this.ensureRegistered(),await this.httpClient.callTool("query_file_changes_history",{...e})}async getRuntimeFeatures(){return await this.httpClient.fetchRuntimeFeatures()}async listLaunchConfigs(){return this.ensureRegistered(),await this.httpClient.callTool("launch_config_list",{})}async createLaunchConfig(e){return this.ensureRegistered(),await this.httpClient.callTool("launch_config_create",{...e})}async updateLaunchConfig(e){return this.ensureRegistered(),await this.httpClient.callTool("launch_config_update",{...e})}async deleteLaunchConfig(e){return this.ensureRegistered(),await this.httpClient.callTool("launch_config_delete",{configId:e})}async startLaunchConfig(e){this.ensureRegistered();const t=Math.max(0,Math.min(3e5,Number(e.wait_timeout_ms)||0));return t>0?await this.httpClient.callToolOnce("launch_config_start",e,t+6e4):await this.httpClient.callTool("launch_config_start",{...e})}async restartLaunchConfig(e){this.ensureRegistered();const t=Math.max(0,Math.min(3e5,Number(e.wait_timeout_ms)||0));return t>0?await this.httpClient.callToolOnce("launch_config_restart",e,t+6e4):await this.httpClient.callTool("launch_config_restart",{...e})}async stopLaunchConfig(e){return this.ensureRegistered(),await this.httpClient.callTool("launch_config_stop",{configId:e})}async getLaunchLogs(e){return this.ensureRegistered(),await this.httpClient.callTool("launch_config_logs",{...e})}async listLaunchRuns(){return this.ensureRegistered(),await this.httpClient.callTool("launch_config_status",{})}start(e,t){if(this.isRunning){s.warn("[AgentClient] \u6D88\u606F\u5FAA\u73AF\u5DF2\u5728\u8FD0\u884C\u4E2D");return}this.isDegradedMode||this.ensureRegistered(),this.messageHandler=e,this.profileHandler=t?.profileHandler||null,this.configHandler=t?.configHandler||null,this.systemNotifyHandler=t?.systemNotifyHandler||null,this.isRunning=!0,s.info(`[AgentClient] start() \u88AB\u8C03\u7528\uFF0CcachedProfile: ${this.cachedProfile?"\u5B58\u5728":"\u4E0D\u5B58\u5728"}, profileHandler: ${this.profileHandler?"\u5DF2\u8BBE\u7F6E":"\u672A\u8BBE\u7F6E"}, \u964D\u7EA7\u6A21\u5F0F: ${this.isDegradedMode?"\u662F":"\u5426"}`),this.cachedProfile&&this.profileHandler&&(s.info(`[AgentClient] \u5904\u7406\u7F13\u5B58\u7684 Profile \u4FE1\u606F: ${this.cachedProfile.displayName}`),this.profileHandler(this.cachedProfile),this.cachedProfile=null),t?.pollMode??!1?(s.warn("[AgentClient] \u542F\u52A8\u6D88\u606F\u4E3B\u5FAA\u73AF\uFF08HTTP\u8F6E\u8BE2\u6A21\u5F0F - \u4E0D\u63A8\u8350\uFF09"),this.messageLoop()):s.info("[AgentClient] \u542F\u52A8\u6D88\u606F\u4E3B\u5FAA\u73AF\uFF08WebSocket\u63A8\u9001\u6A21\u5F0F - \u63A8\u8350\uFF09")}stop(){this.isRunning=!1,this.pollTimer&&(clearTimeout(this.pollTimer),this.pollTimer=null),this.stopRuntimeTokenRefresh(),s.info("[AgentClient] \u6D88\u606F\u4E3B\u5FAA\u73AF\u5DF2\u505C\u6B62")}async messageLoop(){for(;this.isRunning;)try{await this.delay(I)}catch(e){s.error("[AgentClient] \u6D88\u606F\u5FAA\u73AF\u9519\u8BEF:",e),await this.delay(5e3)}}handleIncomingDm(e){e.senderId!==this.agentId&&this.processMessage(e)}handleIncomingGroup(e){e.senderId!==this.agentId&&this.processMessage(e)}handleIncomingMeeting(e){!e||e.senderId===this.agentId||this.processMessage(e)}handleProfileInfo(e){s.info(`[AgentClient] \u6536\u5230 Profile \u4FE1\u606F: ${e.displayName} (${e.roleName})`),e.projectId&&(this.projectId=e.projectId,s.info(`[AgentClient] \u66F4\u65B0\u6240\u5C5E\u9879\u76EE: ${this.projectId}`)),e.roleName&&e.roleName!==this.agentConfig.roleName&&(s.info(`[AgentClient] \u540C\u6B65\u89D2\u8272\u540D: "${this.agentConfig.roleName||"(\u7A7A)"}" -> "${e.roleName}"`),this.agentConfig.roleName=e.roleName),e.roleName&&u(e.roleName,e.instanceName||this.agentId||""),this.profileHandler?this.profileHandler(e):(s.info("[AgentClient] profileHandler \u672A\u8BBE\u7F6E\uFF0C\u7F13\u5B58 Profile \u4FE1\u606F"),this.cachedProfile=e)}async processMessage(e){if(!this.messageHandler)return;const t=typeof e.msgId=="string";s.info(`[AgentClient] \u6536\u5230${t?"\u79C1\u4FE1":"\u7FA4\u6D88\u606F"}\u6765\u81EA ${e.senderName}: ${e.content.substring(0,50)}...`);try{const n=await this.messageHandler(e);if(t){const r=e;r.requireReply&&r.callId&&await this.replyToCall(r.callId,r.senderId,n||"\u5DF2\u6536\u5230\u6D88\u606F\uFF0C\u6B63\u5728\u5904\u7406\u4E2D...")}}catch(n){const r=typeof e.msgId=="string";if(s.error("[AgentClient] \u5904\u7406\u6D88\u606F\u5931\u8D25: type=%s, senderId=%s, senderName=%s, msgId=%s, error=%s",r?"\u79C1\u4FE1":"\u7FA4\u6D88\u606F",e.senderId,e.senderName,e.msgId,n instanceof Error?n.message:String(n)),r){const i=e;i.requireReply&&i.callId&&await this.replyToCall(i.callId,i.senderId,`\u5904\u7406\u5931\u8D25: ${n}`)}}}ensureRegistered(){if(!this.agentId)throw new Error("Agent is not registered")}delay(e){return new Promise(t=>{this.pollTimer=setTimeout(t,e)})}onNewCharacter(e){this.newCharacterHandler=e}getState(){return{agentId:this.agentId,displayName:this.displayName,projectId:this.projectId,isConnected:this.wsClient.isConnected(),isRunning:this.isRunning}}getAgentConfig(){return this.agentConfig}getServerConfig(){return this.serverConfig}reloadConfig(){h.loadConfig(),this.agentConfig=h.getAgentConfig(),s.info(`[AgentClient] \u914D\u7F6E\u5DF2\u91CD\u65B0\u52A0\u8F7D\uFF0C\u89D2\u8272: ${this.agentConfig.roleName}`)}enterDegradedMode(){this.isDegradedMode=!0,s.warn("[AgentClient] \u8FDB\u5165\u964D\u7EA7\u6A21\u5F0F\uFF0C\u5C06\u5728\u540E\u53F0\u6301\u7EED\u5C1D\u8BD5\u91CD\u8FDE")}exitDegradedMode(){this.isDegradedMode=!1,s.info("[AgentClient] \u9000\u51FA\u964D\u7EA7\u6A21\u5F0F")}isInDegradedMode(){return this.isDegradedMode}async retryRegistrationInBackground(e,t){let n=0;(async()=>{for(;this.isDegradedMode;)try{s.info(`[AgentClient] \u964D\u7EA7\u6A21\u5F0F\uFF1A\u5C1D\u8BD5\u91CD\u65B0\u6CE8\u518C (${n+1}/${t===-1?"\u65E0\u9650":t})`);const i=await this.register();s.info(`[AgentClient] \u964D\u7EA7\u6A21\u5F0F\uFF1A\u6CE8\u518C\u6210\u529F - ${i.displayName} (${i.agentId})`),this.exitDegradedMode(),this.messageHandler&&this.start(this.messageHandler);return}catch(i){n++;const a=i instanceof Error?i.message:String(i);if(s.warn(`[AgentClient] \u964D\u7EA7\u6A21\u5F0F\uFF1A\u6CE8\u518C\u5931\u8D25 (${n}/${t===-1?"\u65E0\u9650":t}): ${a}`),t>0&&n>=t){s.error("[AgentClient] \u964D\u7EA7\u6A21\u5F0F\uFF1A\u8FBE\u5230\u6700\u5927\u91CD\u8BD5\u6B21\u6570\uFF0C\u505C\u6B62\u91CD\u8FDE"),this.isDegradedMode=!1;return}await new Promise(o=>setTimeout(o,e))}})().catch(i=>{s.error("[AgentClient] \u964D\u7EA7\u6A21\u5F0F\u540E\u53F0\u91CD\u8BD5\u5FAA\u73AF\u5F02\u5E38\u9000\u51FA: error=%s, stack=%s",i instanceof Error?i.message:String(i),i instanceof Error?i.stack:"(no stack)")})}initializeStatusReporter(){if(!this.agentId){s.warn("[AgentClient] \u65E0\u6CD5\u521D\u59CB\u5316\u72B6\u6001\u62A5\u544A\u5668\uFF1AagentId \u4E3A\u7A7A");return}this.statusReporter=new A({agentId:this.agentId,sendStatusUpdate:e=>{this.wsClient.send({type:"AGENT_STATUS",data:e,timestamp:new Date().toISOString()})}}),w(e=>this.reportMcpNodeLog(e)),this.startRuntimeTokenRefresh(),s.info("[AgentClient] \u72B6\u6001\u62A5\u544A\u5668\u5DF2\u521D\u59CB\u5316")}startRuntimeTokenRefresh(){this.stopRuntimeTokenRefresh();const e=this.serverConfig.runtimeTokenRefreshIntervalMs;if(!e||e<=0){s.warn("[AgentClient] runtimeTokenRefreshIntervalMs \u672A\u914D\u7F6E\u6216\u65E0\u6548\uFF0C\u8DF3\u8FC7\u4E3B\u52A8\u7EED\u671F");return}const t=this.agentId;if(!t){s.warn("[AgentClient] agentId \u4E3A\u7A7A\uFF0C\u8DF3\u8FC7\u4E3B\u52A8\u7EED\u671F");return}this.runtimeTokenRefreshTimer=setInterval(async()=>{try{await this.httpClient.refreshRuntimeAccessToken(t)&&s.info("[AgentClient] runtimeAccessToken \u5DF2\u4E3B\u52A8\u7EED\u671F")}catch(n){s.warn("[AgentClient] \u4E3B\u52A8\u7EED\u671F runtimeAccessToken \u5931\u8D25: %s",n instanceof Error?n.message:String(n)),n instanceof Error&&n.stack&&s.warn("[AgentClient] \u4E3B\u52A8\u7EED\u671F\u5F02\u5E38\u5806\u6808:",n.stack)}},e),this.runtimeTokenRefreshTimer.unref?.(),s.info(`[AgentClient] runtime token \u4E3B\u52A8\u7EED\u671F\u5DF2\u542F\u52A8\uFF0C\u95F4\u9694 ${e}ms`)}stopRuntimeTokenRefresh(){this.runtimeTokenRefreshTimer&&(clearInterval(this.runtimeTokenRefreshTimer),this.runtimeTokenRefreshTimer=null)}reportMcpNodeLog(e){const t=this.wsClient;!this.agentId||!this.wsClient.isConnected()||typeof t.sendMcpNodeLog!="function"||t.sendMcpNodeLog(e)}getStatusReporter(){return this.statusReporter}}export{N as AgentClient,T as PollLongPollTimeoutError};
|
|
1
|
+
import{configManager as c}from"./config.js";import{MESSAGE_POLL_INTERVAL_MS as I}from"./constants.js";import{HttpClient as f}from"./http-client.js";import{logger as i,setMcpNodeLogSink as w,updateStartupLogIdentity as u}from"./logger.js";import{claimRuntimeLaunchBindingDetailed as m}from"./runtime-launch-binding.js";import{StatusReporter as A}from"./status-reporter.js";import{WebSocketClient as p}from"./websocket-client.js";class T extends Error{constructor(e){super(e),this.name="PollLongPollTimeoutError"}}const C=27e4;class N{wsClient;httpClient;agentConfig;serverConfig;agentId=null;displayName=null;projectId=null;isRunning=!1;isDegradedMode=!1;messageHandler=null;profileHandler=null;configHandler=null;systemNotifyHandler=null;pollTimer=null;statusReporter=null;newCharacterHandler=null;runtimeTokenRefreshTimer=null;pendingLaunchBindingClaim=!1;cachedProfile=null;constructor(){c.loadConfig(),this.agentConfig=c.getAgentConfig(),this.serverConfig=c.getServerConfig(),this.wsClient=new p(this.serverConfig),this.httpClient=new f(this.serverConfig),this.setupWebSocketListeners()}async initialize(){const e=await m(this.agentConfig,this.serverConfig);if(e.status==="claimed"){this.applyLaunchBinding(e.binding);return}if(e.status==="unreachable"){this.pendingLaunchBindingClaim=!0,i.warn("[AgentClient] runtime-bridge \u672A\u5C31\u7EEA\uFF0C\u542F\u52A8\u7ED1\u5B9A\u8BA4\u9886\u5DF2\u6302\u8D77\uFF0C\u5C06\u5728\u6CE8\u518C\u91CD\u8BD5\u4E2D\u91CD\u65B0\u8BA4\u9886: %s",e.message);return}this.serverConfig.runtimeBridgeBaseUrl=void 0}applyLaunchBinding(e){c.applyRuntimeLaunchBinding(e),this.agentConfig=c.getAgentConfig(),this.serverConfig=c.getServerConfig(),this.wsClient=new p(this.serverConfig),this.httpClient=new f(this.serverConfig),this.setupWebSocketListeners()}async retryPendingLaunchBindingClaim(){if(!this.pendingLaunchBindingClaim)return!0;const e=await m(this.agentConfig,this.serverConfig);if(e.status==="claimed")return this.pendingLaunchBindingClaim=!1,i.info("[AgentClient] \u542F\u52A8\u7ED1\u5B9A\u8865\u8BA4\u9886\u6210\u529F\uFF0C\u7EE7\u7EED\u6CE8\u518C\u6D41\u7A0B"),this.applyLaunchBinding(e.binding),!0;if(e.status==="missing")return this.pendingLaunchBindingClaim=!1,this.serverConfig.runtimeBridgeBaseUrl=void 0,i.warn("[AgentClient] \u542F\u52A8\u7ED1\u5B9A\u8865\u8BA4\u9886\u672A\u627E\u5230\u5F85\u8BA4\u9886\u8BB0\u5F55\uFF0C\u6309\u65E0\u7ED1\u5B9A\u6A21\u5F0F\u7EE7\u7EED\u6CE8\u518C"),!1;const t=e.status==="unreachable"?e.message:e.reason;return i.warn("[AgentClient] \u542F\u52A8\u7ED1\u5B9A\u8865\u8BA4\u9886\u5931\u8D25\uFF0C\u4FDD\u7559\u6302\u8D77\u72B6\u6001\u7B49\u5F85\u4E0B\u6B21\u6CE8\u518C\u91CD\u8BD5: %s",t),!1}setupWebSocketListeners(){this.wsClient.on("directMessage",e=>{this.handleIncomingDm(e)}),this.wsClient.on("groupMessage",e=>{this.handleIncomingGroup(e)}),this.wsClient.on("meetingMessage",e=>{this.handleIncomingMeeting(e)}),this.wsClient.on("systemNotify",e=>{this.systemNotifyHandler?.(e)}),this.wsClient.on("profileInfo",e=>{i.info(`[AgentClient] WebSocket profileInfo \u4E8B\u4EF6\u89E6\u53D1\uFF0CdisplayName: ${e.displayName}`),this.handleProfileInfo(e)}),this.wsClient.on("agentConfig",e=>{i.info("[AgentClient] WebSocket agentConfig \u4E8B\u4EF6\u89E6\u53D1"),this.configHandler&&this.configHandler(e??{})}),this.wsClient.on("agentStatus",e=>{i.info(`[AgentClient] WebSocket agentStatus \u4E8B\u4EF6\u89E6\u53D1: ${e.status}`)}),this.wsClient.on("disconnected",(e,t)=>{const n=t?.toString()||"";i.warn("[AgentClient] WebSocket \u65AD\u5F00\u8FDE\u63A5: code=%s, reason=%s, agentId=%s, \u6B63\u5728\u81EA\u52A8\u91CD\u8FDE",e,n,this.agentId)}),this.wsClient.on("error",e=>{i.error("[AgentClient] WebSocket \u9519\u8BEF: %s, stack=%s",e.message,e.stack)}),this.wsClient.on("reconnectFailed",()=>{i.error("[AgentClient] \u91CD\u8FDE\u5931\u8D25\uFF08\u5DF2\u8FBE\u91CD\u8BD5\u4E0A\u9650\uFF09\uFF0C\u505C\u6B62\u6D88\u606F\u5FAA\u73AF, agentId=%s",this.agentId),this.stop()}),this.wsClient.on("tokenRejected",()=>{i.error("[AgentClient] runtime token \u88AB 1008 \u62D2\u7EDD\u4E14\u5237\u65B0\u65E0\u53D8\u5316\uFF0C\u8FDB\u5165\u6162\u901F\u91CD\u8BD5\u7B49\u5F85\u65B0 token \u7B7E\u53D1: agentId=%s",this.agentId)}),this.wsClient.on("tokenRefreshFailed",e=>{i.error("[AgentClient] runtime token \u5237\u65B0\u8FDE\u7EED\u5931\u8D25 %s \u6B21\uFF0C\u8FDB\u5165\u6162\u901F\u91CD\u8BD5\u7B49\u5F85 bridge \u6062\u590D: agentId=%s",e,this.agentId)})}async register(){return i.info("[AgentClient] \u6B63\u5728\u6CE8\u518C Agent..."),await this.retryPendingLaunchBindingClaim(),this.hasPresetAgentId()?await this.registerWithExistingAgentId():await this.registerAsNewAgent()}hasPresetAgentId(){return!!(this.agentConfig.agentId&&this.agentConfig.agentId.trim().length>0)}async registerWithExistingAgentId(){const e=this.agentConfig.agentId;if(!e)throw new Error("Preset agentId is missing");this.agentId=e.trim();let t;try{t=await this.getProfileByAgentId(this.agentId)}catch(r){throw i.error("[AgentClient] getProfileByAgentId \u5931\u8D25 (presetAgentId=%s): %s",this.agentId,r instanceof Error?r.message:String(r)),r}this.displayName=t.displayName,this.projectId=t.projectId||null,i.info(`[AgentClient] \u4F7F\u7528\u9884\u8BBE AgentID \u7ED1\u5B9A\u5B9E\u4F8B: ${this.displayName} (${this.agentId})`),i.info(`[AgentClient] \u6240\u5C5E\u9879\u76EE: ${this.projectId||"(\u672A\u8BBE\u7F6E)"}`);try{await this.wsClient.connect(this.agentId)}catch(r){throw i.error("[AgentClient] WebSocket \u8FDE\u63A5\u5931\u8D25 (agentId=%s): %s",this.agentId,r instanceof Error?r.message:String(r)),r}i.info("[AgentClient] WebSocket \u8FDE\u63A5\u5DF2\u5EFA\u7ACB\uFF0CAgent \u73B0\u5728\u5DF2\u4E0A\u7EBF"),this.initializeStatusReporter();const n=await this.getProfileByAgentId(this.agentId);return this.displayName=n.displayName,this.projectId=n.projectId||null,u(n.roleName||"unknown-role",n.instanceName||this.agentId),{agentId:this.agentId,displayName:this.displayName,status:n.isOnline?"online":"offline",projectId:n.projectId,workspacePath:n.workspacePath,runtimeStatus:n.runtimeStatus,runtimeSessionId:n.runtimeSessionId}}async registerAsNewAgent(){const e=await this.httpClient.callTool("register",{roleName:this.agentConfig.roleName,projectId:this.agentConfig.projectId,workspacePath:this.agentConfig.workspacePath,prompt:this.agentConfig.prompt,runtimeBridgeBaseUrl:this.serverConfig.runtimeBridgeBaseUrl}),t=e.agentId;if(!t)throw new Error("Registration failed: agentId was not returned");return this.agentId=t,this.displayName=e.displayName,this.projectId=e.projectId||null,u(this.agentConfig.roleName||"unknown-role",e.instanceName||t),i.info(`[AgentClient] \u6CE8\u518C\u6210\u529F: ${this.displayName} (${this.agentId})`),i.info(`[AgentClient] \u72B6\u6001: ${e.status}`),i.info(`[AgentClient] \u6240\u5C5E\u9879\u76EE: ${this.projectId||"(\u672A\u8BBE\u7F6E)"}`),await this.wsClient.connect(this.agentId),i.info("[AgentClient] WebSocket \u8FDE\u63A5\u5DF2\u5EFA\u7ACB\uFF0CAgent \u73B0\u5728\u5DF2\u4E0A\u7EBF"),this.initializeStatusReporter(),e.isExisting===!1&&this.newCharacterHandler&&this.newCharacterHandler(),e}async unregister(){i.info("[AgentClient] \u6B63\u5728\u6CE8\u9500 Agent..."),this.agentId&&await this.httpClient.callTool("unregister",{agentId:this.agentId}),this.stopRuntimeTokenRefresh(),this.wsClient.disconnect(),this.agentId=null,this.displayName=null,this.projectId=null,this.isRunning=!1,i.info("[AgentClient] \u5DF2\u6CE8\u9500")}async discoverColleagues(){return await this.httpClient.callTool("discover_colleague",{agentId:this.agentId})}async discoverGroupRooms(){return this.ensureRegistered(),await this.httpClient.callTool("discover_group_rooms",{agentId:this.agentId})}async listProjectMembers(){return this.ensureRegistered(),await this.httpClient.callTool("list_project_members",{agentId:this.agentId})}async hireColleague(e){return this.ensureRegistered(),await this.httpClient.callTool("hire_colleague",{...e,agentId:this.agentId})}async callAgentScopedTool(e,t){this.ensureRegistered();const n={...t,agentId:this.agentId};if(e==="create_meeting"){const r=typeof t.waitTimeoutMs=="number"?t.waitTimeoutMs:Number.NaN,s=Number.isFinite(r)&&r>0?Math.min(r,C):C;return await this.httpClient.callToolOnce(e,{...n,waitTimeoutMs:s},0)}return await this.httpClient.callTool(e,n)}async reportMemoryStats(e){await this.callAgentScopedTool("report_memory_stats",{memoryStats:e})}async sendGroupMessage(e,t,n,r,s){this.ensureRegistered();const a=t||this.projectId||this.agentConfig.projectId;return await this.httpClient.callTool("send_group_message",{agentId:this.agentId,projectId:a,roomId:n,content:e,card:r,replyTo:s})}async sendDirectMessage(e,t,n=!1,r,s,a,h){this.ensureRegistered();const g={agentId:this.agentId,targetId:e,content:t,requireReply:n,waitReply:n,replyToCallId:r,card:a,replyTo:h};if(typeof s=="number"&&s>0&&(g.timeoutMs=s),n){const o=typeof s=="number"&&s>0?s+3e4:0;return await this.httpClient.callToolOnce("send_dm",g,o)}return await this.httpClient.callTool("send_dm",g)}async sendCallAndWaitReply(e,t,n=6e4){const r=await this.sendDirectMessage(e,t,!0,void 0,n);if(r.reply)return r.reply;throw new Error("No reply received for call-style direct message before timeout")}async replyToCall(e,t,n){return await this.sendDirectMessage(t,n,!1,e)}async sendEmail(e){return await this.callAgentScopedTool("send_email",e)}async listEmails(e){return await this.callAgentScopedTool("list_emails",e)}async readEmail(e){return await this.callAgentScopedTool("read_email",{mailId:e})}async replyEmail(e){return await this.callAgentScopedTool("reply_email",e)}async getDmHistory(e,t=50,n){this.ensureRegistered();const r={agentId:this.agentId,targetUserId:e,limit:t};return n&&(r.since=n),await this.httpClient.callTool("get_dm_history",r)}async getGroupHistory(e=50,t,n){if(this.ensureRegistered(),t){const o={projectId:this.projectId||this.agentConfig.projectId,roomId:t,limit:e};return n&&(o.since=n),await this.httpClient.callTool("get_group_history",o)}const r=await this.discoverGroupRooms(),s=this.projectId||this.agentConfig.projectId,a=this.collectRoomIds(r,s);if(a.length===0)return{messages:[],count:0};const g=(await Promise.all(a.map(async o=>{const l={projectId:s,roomId:o,limit:e};return n&&(l.since=n),await this.httpClient.callTool("get_group_history",l)}))).flatMap(o=>o.messages).sort((o,l)=>new Date(o.timestamp).getTime()-new Date(l.timestamp).getTime());return{messages:g,count:g.length}}async fetchUnreadMessages(e={}){this.ensureRegistered();const t=this.projectId||this.agentConfig.projectId,n={agentId:this.agentId,blockIfEmpty:e.blockIfEmpty??!1};e.since&&(n.since=e.since),e.blockTimeoutMs&&e.blockTimeoutMs>0&&(n.blockTimeoutMs=e.blockTimeoutMs),e.preemptiveJoinWaitMs!==void 0&&e.preemptiveJoinWaitMs!==null&&e.preemptiveJoinWaitMs>=0&&(n.preemptiveJoinWaitMs=e.preemptiveJoinWaitMs);const r=e.includePipelineTasks?"poll_message":"get_dm_messages";i.info("[AgentClient] fetchUnreadMessages \u5165\u53E3: tool=%s, blockIfEmpty=%s, blockTimeoutMs=%s, pollMessageTimeoutMs=%s, skipGroupMessages=%s, preemptiveJoinWaitMs=%s, agentId=%s",r,String(e.blockIfEmpty??!1),String(e.blockTimeoutMs??"-"),String(e.pollMessageTimeoutMs??"-"),String(e.skipGroupMessages??!1),String(e.preemptiveJoinWaitMs??"-"),this.agentId);const s=await this.fetchDirectMessagesWithRecovery(r,n,e.pollMessageTimeoutMs,e.propagatePollTimeout===!0);if(i.info("[AgentClient] fetchUnreadMessages \u79C1\u4FE1\u9636\u6BB5\u8FD4\u56DE: %s \u6761",Array.isArray(s.messages)?s.messages.length:0),e.skipGroupMessages)return i.info("[AgentClient] \u4F1A\u8BAE\u5FEB\u901F hydrate \u5DF2\u53D6\u5F97\u79C1\u4FE1\u54CD\u5E94\uFF0C\u8DF3\u8FC7\u7FA4\u804A\u53D1\u73B0\u5E76\u7ACB\u5373\u8FD4\u56DE: directMessages=%s",Array.isArray(s.messages)?s.messages.length:0),{directMessages:Array.isArray(s.messages)?s.messages:[],groupMessages:[]};let a;try{a=await this.discoverGroupRooms()}catch(o){i.warn("[AgentClient] \u53D1\u73B0\u7FA4\u623F\u95F4\u5931\u8D25\uFF0C\u672C\u6B21\u6309\u65E0\u7FA4\u6D88\u606F\u5904\u7406\uFF08\u5DF2\u53D6\u5230\u7684\u79C1\u4FE1\u4E0D\u53D7\u5F71\u54CD\uFF09: %s",o instanceof Error?o.message:String(o)),a={groups:[]}}const h=this.collectRoomIds(a,t),g=await Promise.all(h.map(async o=>{const l={agentId:this.agentId,projectId:t,roomId:o};e.since&&(l.since=e.since);try{return await this.httpClient.callTool("get_group_messages",l)}catch(d){return i.warn("[AgentClient] \u8DF3\u8FC7\u7FA4\u623F\u95F4\u672A\u8BFB\u8865\u62C9\u5931\u8D25: roomId=%s, error=%s",o,d instanceof Error?d.message:String(d)),{messages:[],currentReadPos:0,hasMore:!1}}}));return{directMessages:Array.isArray(s.messages)?s.messages:[],groupMessages:g.flatMap(o=>this.normalizeGroupMessages(o)).sort((o,l)=>new Date(o.timestamp).getTime()-new Date(l.timestamp).getTime())}}async markDmRead(e){if(e.length===0)return new Set;this.ensureRegistered();try{const t=await this.httpClient.callTool("mark_dm_read",{agentId:this.agentId,msgIds:e}),n=new Set(Array.isArray(t?.deliverableMsgIds)?t.deliverableMsgIds:[]),r=e.filter(s=>!n.has(s));return r.length>0?i.warn("[AgentClient] mark_dm_read \u786E\u8BA4\u540E\u5C06\u6709 %d \u6761\u6D88\u606F\u88AB\u4E22\u5F03\u4E0D\u4EA4\u4ED8: \u8BF7\u6C42=%s, \u53EF\u4EA4\u4ED8=%s, \u88AB\u4E22\u5F03=%s",r.length,JSON.stringify(e),JSON.stringify([...n]),JSON.stringify(r)):i.info("[AgentClient] mark_dm_read \u786E\u8BA4\u5B8C\u6210: %d \u6761\u5168\u90E8\u53EF\u4EA4\u4ED8",e.length),n}catch(t){throw i.warn("[AgentClient] mark_dm_read \u8BF7\u6C42\u5931\u8D25\uFF08\u5C06\u964D\u7EA7\u4E3A\u76F4\u63A5\u4EA4\u4ED8\uFF09: %s",t instanceof Error?t.message:String(t)),t}}async markGroupRead(e,t){if(t.length===0)return new Set;this.ensureRegistered();const n=await this.httpClient.callTool("mark_group_read",{agentId:this.agentId,roomId:e,msgIds:t});return new Set(Array.isArray(n?.deliverableMsgIds)?n.deliverableMsgIds:[])}async markNotificationRead(e){if(e.length!==0){this.ensureRegistered();try{await this.httpClient.callTool("mark_notification_read",{agentId:this.agentId,msgIds:e})}catch{}}}async markMeetingRead(e){if(e.length!==0){this.ensureRegistered();try{await this.httpClient.callTool("mark_meeting_read",{agentId:this.agentId,msgIds:e})}catch{}}}async fetchBrowserListenerEvents(){const e=this.serverConfig.runtimeBridgeBaseUrl,t=this.agentId;if(!e||!t)return i.info("[AgentClient] fetchBrowserListenerEvents \u8DF3\u8FC7: bridgeBaseUrl=%s, agentId=%s",e||"(\u7A7A)",t||"(\u7A7A)"),[];try{const n=`${e}/runtime/browser-listeners/${encodeURIComponent(t)}/events`,r=this.serverConfig.runtimeAccessToken||"";i.debug("[AgentClient] \u62C9\u53D6\u76D1\u542C\u5668\u4E8B\u4EF6: url=%s, tokenLen=%d",n,r.length);const s=await fetch(n,{method:"GET",headers:{"X-Runtime-Token":r},signal:AbortSignal.timeout(3e3)});if(!s.ok)return i.warn("[AgentClient] \u62C9\u53D6\u76D1\u542C\u5668\u4E8B\u4EF6\u5931\u8D25: HTTP %s, url=%s",s.status,n),[];const a=await s.json();return!a.ok||!Array.isArray(a.events)?(i.warn("[AgentClient] \u62C9\u53D6\u76D1\u542C\u5668\u4E8B\u4EF6\u54CD\u5E94\u5F02\u5E38: ok=%s, eventsType=%s",a.ok,Array.isArray(a.events)?"array":typeof a.events),[]):(i.debug("[AgentClient] \u62C9\u53D6\u76D1\u542C\u5668\u4E8B\u4EF6\u6210\u529F: %d \u6761\u4E8B\u4EF6",a.events.length),a.events)}catch(n){return i.warn("[AgentClient] \u62C9\u53D6\u76D1\u542C\u5668\u4E8B\u4EF6\u5F02\u5E38: %s",n instanceof Error?n.message:String(n)),[]}}async fetchPluginEvents(){const e=this.serverConfig.runtimeBridgeBaseUrl,t=this.agentId;if(!e||!t)return{revision:0,events:[],catalog:null,compactionSeq:0};try{const n=`${e}/runtime/plugin-events/${encodeURIComponent(t)}/events`,r=this.serverConfig.runtimeAccessToken||"",s=await fetch(n,{method:"GET",headers:{"X-Runtime-Token":r},signal:AbortSignal.timeout(3e3)});if(!s.ok)return i.warn("[AgentClient] \u62C9\u53D6\u63D2\u4EF6\u4E8B\u4EF6\u5931\u8D25: HTTP %s, url=%s",s.status,n),{revision:0,events:[],catalog:null,compactionSeq:0};const a=await s.json();return!a.ok||!Array.isArray(a.events)?(i.warn("[AgentClient] \u62C9\u53D6\u63D2\u4EF6\u4E8B\u4EF6\u54CD\u5E94\u5F02\u5E38: ok=%s",String(a.ok)),{revision:0,events:[],catalog:null,compactionSeq:0}):(i.debug("[AgentClient] \u62C9\u53D6\u63D2\u4EF6\u4E8B\u4EF6\u6210\u529F: %d \u6761\u4E8B\u4EF6, revision=%s, catalog=%s, compactionSeq=%s",a.events.length,String(a.revision??0),a.catalog?`${a.catalog.plugins.length} \u4E2A\u63D2\u4EF6`:"null",String(a.compactionSeq??0)),{revision:a.revision??0,events:a.events,catalog:a.catalog??null,compactionSeq:typeof a.compactionSeq=="number"&&Number.isFinite(a.compactionSeq)?a.compactionSeq:0})}catch(n){return i.warn("[AgentClient] \u62C9\u53D6\u63D2\u4EF6\u4E8B\u4EF6\u5F02\u5E38: %s",n instanceof Error?n.message:String(n)),{revision:0,events:[],catalog:null,compactionSeq:0}}}async notifyBridgeForceMessage(){const e=this.serverConfig.runtimeBridgeBaseUrl,t=this.agentId;if(!(!e||!t))try{const n=`${e}/runtime/sessions/${encodeURIComponent(t)}/notify-force-message`,r=this.serverConfig.runtimeAccessToken||"",s=await fetch(n,{method:"POST",headers:{"X-Runtime-Token":r},signal:AbortSignal.timeout(3e3)});s.ok||i.warn("[AgentClient] \u901A\u77E5 bridge \u5F3A\u5236\u6D88\u606F\u5931\u8D25: HTTP %s, url=%s",s.status,n)}catch(n){i.warn("[AgentClient] \u901A\u77E5 bridge \u5F3A\u5236\u6D88\u606F\u5F02\u5E38: %s",n instanceof Error?n.message:String(n))}}async fetchDirectMessagesWithRecovery(e,t,n,r=!1){if(e==="poll_message"){i.info("[AgentClient] fetchDirectMessagesWithRecovery \u5165\u53E3: tool=poll_message, pollMessageTimeoutMs=%s, agentId=%s",String(n??"(\u9ED8\u8BA4)"),String(t?.agentId??""));try{const s=await this.httpClient.callToolOnce(e,t,n);return i.info("[AgentClient] fetchDirectMessagesWithRecovery poll_message \u6210\u529F\u8FD4\u56DE: %s \u6761",Array.isArray(s?.messages)?s.messages.length:0),s}catch(s){if(this.isRecoverableLongPollError(s)){if(r)throw new T(s instanceof Error?s.message:String(s));return i.warn("[AgentClient] poll_message \u5355\u6B21\u957F\u8F6E\u8BE2\u8D85\u65F6\uFF0C\u6309\u7A7A\u7ED3\u679C\u9000\u907F\u540E\u7EE7\u7EED\u7B49\u5F85:",s),{messages:[]}}throw s}}return await this.httpClient.callTool(e,t)}isRecoverableLongPollError(e){return e instanceof Error?/MCP tool poll_message call failed: 503(?:\s|$)/.test(e.message)||/MCP tool poll_message timed out after \d+ms/.test(e.message):!1}normalizeGroupMessages(e){return Array.isArray(e.messages)?e.messages.filter(t=>!!(t&&typeof t=="object"&&typeof t.msgId=="number"&&typeof t.senderId=="string"&&typeof t.content=="string"&&typeof t.timestamp=="string")):[]}collectRoomIds(e,t){const n=e.groups.filter(r=>r.projectId===t).map(r=>r.id);return Array.from(new Set(n))}async getProfile(){this.ensureRegistered();const e=this.agentId;if(!e)throw new Error("Agent is not registered");return{...await this.getProfileByAgentId(e),describe:this.agentConfig.describe}}async getProfileByAgentId(e){return await this.httpClient.callTool("get_profile",{agentId:e})}async getMyTasks(){return this.ensureRegistered(),await this.httpClient.callTool("my_task",{agentId:this.agentId})}async listTaskNodeIterations(e={}){return this.ensureRegistered(),await this.httpClient.callTool("list_task_node_iterations",{agentId:this.agentId,...e})}async createTaskInstanceComment(e){this.ensureRegistered();const t={agentId:this.agentId,...e};return await this.httpClient.callTool("create_task_instance_comment",t)}async submitTaskResult(e,t,n,r,s){this.ensureRegistered();const a={agentId:this.agentId,nodeId:e,outputPayload:t};return(Array.isArray(n)&&n.length>0||typeof n=="string"&&n.trim().length>0)&&(a.changeLog=n),typeof r=="string"&&r.trim().length>0&&(a.handoverNote=r),s&&Array.isArray(s)&&s.length>0&&(a.deliverables=s),await this.httpClient.callTool("submit_task_result",a)}async startTaskRollback(e){return this.ensureRegistered(),await this.httpClient.callTool("start_task_rollback",{agentId:this.agentId,...e})}async finishTaskRollback(e){return this.ensureRegistered(),await this.httpClient.callTool("finish_task_rollback",{agentId:this.agentId,...e})}async getDebugLogConfig(){return await this.httpClient.callTool("get_debug_log_config",{agentId:this.agentId})}async queryDebugLogs(e){return this.ensureRegistered(),await this.httpClient.callTool("query_debug_logs",{...e})}async queryFileChangesHistory(e){return this.ensureRegistered(),await this.httpClient.callTool("query_file_changes_history",{...e})}async getRuntimeFeatures(){return await this.httpClient.fetchRuntimeFeatures()}async listLaunchConfigs(){return this.ensureRegistered(),await this.httpClient.callTool("launch_config_list",{})}async createLaunchConfig(e){return this.ensureRegistered(),await this.httpClient.callTool("launch_config_create",{...e})}async updateLaunchConfig(e){return this.ensureRegistered(),await this.httpClient.callTool("launch_config_update",{...e})}async deleteLaunchConfig(e){return this.ensureRegistered(),await this.httpClient.callTool("launch_config_delete",{configId:e})}async startLaunchConfig(e){this.ensureRegistered();const t=Math.max(0,Math.min(3e5,Number(e.wait_timeout_ms)||0));return t>0?await this.httpClient.callToolOnce("launch_config_start",e,t+6e4):await this.httpClient.callTool("launch_config_start",{...e})}async restartLaunchConfig(e){this.ensureRegistered();const t=Math.max(0,Math.min(3e5,Number(e.wait_timeout_ms)||0));return t>0?await this.httpClient.callToolOnce("launch_config_restart",e,t+6e4):await this.httpClient.callTool("launch_config_restart",{...e})}async stopLaunchConfig(e){return this.ensureRegistered(),await this.httpClient.callTool("launch_config_stop",{configId:e})}async getLaunchLogs(e){return this.ensureRegistered(),await this.httpClient.callTool("launch_config_logs",{...e})}async listLaunchRuns(){return this.ensureRegistered(),await this.httpClient.callTool("launch_config_status",{})}start(e,t){if(this.isRunning){i.warn("[AgentClient] \u6D88\u606F\u5FAA\u73AF\u5DF2\u5728\u8FD0\u884C\u4E2D");return}this.isDegradedMode||this.ensureRegistered(),this.messageHandler=e,this.profileHandler=t?.profileHandler||null,this.configHandler=t?.configHandler||null,this.systemNotifyHandler=t?.systemNotifyHandler||null,this.isRunning=!0,i.info(`[AgentClient] start() \u88AB\u8C03\u7528\uFF0CcachedProfile: ${this.cachedProfile?"\u5B58\u5728":"\u4E0D\u5B58\u5728"}, profileHandler: ${this.profileHandler?"\u5DF2\u8BBE\u7F6E":"\u672A\u8BBE\u7F6E"}, \u964D\u7EA7\u6A21\u5F0F: ${this.isDegradedMode?"\u662F":"\u5426"}`),this.cachedProfile&&this.profileHandler&&(i.info(`[AgentClient] \u5904\u7406\u7F13\u5B58\u7684 Profile \u4FE1\u606F: ${this.cachedProfile.displayName}`),this.profileHandler(this.cachedProfile),this.cachedProfile=null),t?.pollMode??!1?(i.warn("[AgentClient] \u542F\u52A8\u6D88\u606F\u4E3B\u5FAA\u73AF\uFF08HTTP\u8F6E\u8BE2\u6A21\u5F0F - \u4E0D\u63A8\u8350\uFF09"),this.messageLoop()):i.info("[AgentClient] \u542F\u52A8\u6D88\u606F\u4E3B\u5FAA\u73AF\uFF08WebSocket\u63A8\u9001\u6A21\u5F0F - \u63A8\u8350\uFF09")}stop(){this.isRunning=!1,this.pollTimer&&(clearTimeout(this.pollTimer),this.pollTimer=null),this.stopRuntimeTokenRefresh(),i.info("[AgentClient] \u6D88\u606F\u4E3B\u5FAA\u73AF\u5DF2\u505C\u6B62")}async messageLoop(){for(;this.isRunning;)try{await this.delay(I)}catch(e){i.error("[AgentClient] \u6D88\u606F\u5FAA\u73AF\u9519\u8BEF:",e),await this.delay(5e3)}}handleIncomingDm(e){e.senderId!==this.agentId&&this.processMessage(e)}handleIncomingGroup(e){e.senderId!==this.agentId&&this.processMessage(e)}handleIncomingMeeting(e){!e||e.senderId===this.agentId||this.processMessage(e)}handleProfileInfo(e){i.info(`[AgentClient] \u6536\u5230 Profile \u4FE1\u606F: ${e.displayName} (${e.roleName})`),e.projectId&&(this.projectId=e.projectId,i.info(`[AgentClient] \u66F4\u65B0\u6240\u5C5E\u9879\u76EE: ${this.projectId}`)),e.roleName&&e.roleName!==this.agentConfig.roleName&&(i.info(`[AgentClient] \u540C\u6B65\u89D2\u8272\u540D: "${this.agentConfig.roleName||"(\u7A7A)"}" -> "${e.roleName}"`),this.agentConfig.roleName=e.roleName),e.roleName&&u(e.roleName,e.instanceName||this.agentId||""),this.profileHandler?this.profileHandler(e):(i.info("[AgentClient] profileHandler \u672A\u8BBE\u7F6E\uFF0C\u7F13\u5B58 Profile \u4FE1\u606F"),this.cachedProfile=e)}async processMessage(e){if(!this.messageHandler)return;const t=typeof e.msgId=="string";i.info(`[AgentClient] \u6536\u5230${t?"\u79C1\u4FE1":"\u7FA4\u6D88\u606F"}\u6765\u81EA ${e.senderName}: ${e.content.substring(0,50)}...`);try{const n=await this.messageHandler(e);if(t){const r=e;r.requireReply&&r.callId&&await this.replyToCall(r.callId,r.senderId,n||"\u5DF2\u6536\u5230\u6D88\u606F\uFF0C\u6B63\u5728\u5904\u7406\u4E2D...")}}catch(n){const r=typeof e.msgId=="string";if(i.error("[AgentClient] \u5904\u7406\u6D88\u606F\u5931\u8D25: type=%s, senderId=%s, senderName=%s, msgId=%s, error=%s",r?"\u79C1\u4FE1":"\u7FA4\u6D88\u606F",e.senderId,e.senderName,e.msgId,n instanceof Error?n.message:String(n)),r){const s=e;s.requireReply&&s.callId&&await this.replyToCall(s.callId,s.senderId,`\u5904\u7406\u5931\u8D25: ${n}`)}}}ensureRegistered(){if(!this.agentId)throw new Error("Agent is not registered")}delay(e){return new Promise(t=>{this.pollTimer=setTimeout(t,e)})}onNewCharacter(e){this.newCharacterHandler=e}getState(){return{agentId:this.agentId,displayName:this.displayName,projectId:this.projectId,isConnected:this.wsClient.isConnected(),isRunning:this.isRunning}}getAgentConfig(){return this.agentConfig}getServerConfig(){return this.serverConfig}reloadConfig(){c.loadConfig(),this.agentConfig=c.getAgentConfig(),i.info(`[AgentClient] \u914D\u7F6E\u5DF2\u91CD\u65B0\u52A0\u8F7D\uFF0C\u89D2\u8272: ${this.agentConfig.roleName}`)}enterDegradedMode(){this.isDegradedMode=!0,i.warn("[AgentClient] \u8FDB\u5165\u964D\u7EA7\u6A21\u5F0F\uFF0C\u5C06\u5728\u540E\u53F0\u6301\u7EED\u5C1D\u8BD5\u91CD\u8FDE")}exitDegradedMode(){this.isDegradedMode=!1,i.info("[AgentClient] \u9000\u51FA\u964D\u7EA7\u6A21\u5F0F")}isInDegradedMode(){return this.isDegradedMode}async retryRegistrationInBackground(e,t){let n=0;(async()=>{for(;this.isDegradedMode;)try{i.info(`[AgentClient] \u964D\u7EA7\u6A21\u5F0F\uFF1A\u5C1D\u8BD5\u91CD\u65B0\u6CE8\u518C (${n+1}/${t===-1?"\u65E0\u9650":t})`);const s=await this.register();i.info(`[AgentClient] \u964D\u7EA7\u6A21\u5F0F\uFF1A\u6CE8\u518C\u6210\u529F - ${s.displayName} (${s.agentId})`),this.exitDegradedMode(),this.messageHandler&&this.start(this.messageHandler);return}catch(s){n++;const a=s instanceof Error?s.message:String(s);if(i.warn(`[AgentClient] \u964D\u7EA7\u6A21\u5F0F\uFF1A\u6CE8\u518C\u5931\u8D25 (${n}/${t===-1?"\u65E0\u9650":t}): ${a}`),t>0&&n>=t){i.error("[AgentClient] \u964D\u7EA7\u6A21\u5F0F\uFF1A\u8FBE\u5230\u6700\u5927\u91CD\u8BD5\u6B21\u6570\uFF0C\u505C\u6B62\u91CD\u8FDE"),this.isDegradedMode=!1;return}await new Promise(h=>setTimeout(h,e))}})().catch(s=>{i.error("[AgentClient] \u964D\u7EA7\u6A21\u5F0F\u540E\u53F0\u91CD\u8BD5\u5FAA\u73AF\u5F02\u5E38\u9000\u51FA: error=%s, stack=%s",s instanceof Error?s.message:String(s),s instanceof Error?s.stack:"(no stack)")})}initializeStatusReporter(){if(!this.agentId){i.warn("[AgentClient] \u65E0\u6CD5\u521D\u59CB\u5316\u72B6\u6001\u62A5\u544A\u5668\uFF1AagentId \u4E3A\u7A7A");return}this.statusReporter=new A({agentId:this.agentId,sendStatusUpdate:e=>{this.wsClient.send({type:"AGENT_STATUS",data:e,timestamp:new Date().toISOString()})}}),w(e=>this.reportMcpNodeLog(e)),this.startRuntimeTokenRefresh(),i.info("[AgentClient] \u72B6\u6001\u62A5\u544A\u5668\u5DF2\u521D\u59CB\u5316")}startRuntimeTokenRefresh(){this.stopRuntimeTokenRefresh();const e=this.serverConfig.runtimeTokenRefreshIntervalMs;if(!e||e<=0){i.warn("[AgentClient] runtimeTokenRefreshIntervalMs \u672A\u914D\u7F6E\u6216\u65E0\u6548\uFF0C\u8DF3\u8FC7\u4E3B\u52A8\u7EED\u671F");return}const t=this.agentId;if(!t){i.warn("[AgentClient] agentId \u4E3A\u7A7A\uFF0C\u8DF3\u8FC7\u4E3B\u52A8\u7EED\u671F");return}this.runtimeTokenRefreshTimer=setInterval(async()=>{try{await this.httpClient.refreshRuntimeAccessToken(t)&&i.info("[AgentClient] runtimeAccessToken \u5DF2\u4E3B\u52A8\u7EED\u671F")}catch(n){i.warn("[AgentClient] \u4E3B\u52A8\u7EED\u671F runtimeAccessToken \u5931\u8D25: %s",n instanceof Error?n.message:String(n)),n instanceof Error&&n.stack&&i.warn("[AgentClient] \u4E3B\u52A8\u7EED\u671F\u5F02\u5E38\u5806\u6808:",n.stack)}},e),this.runtimeTokenRefreshTimer.unref?.(),i.info(`[AgentClient] runtime token \u4E3B\u52A8\u7EED\u671F\u5DF2\u542F\u52A8\uFF0C\u95F4\u9694 ${e}ms`)}stopRuntimeTokenRefresh(){this.runtimeTokenRefreshTimer&&(clearInterval(this.runtimeTokenRefreshTimer),this.runtimeTokenRefreshTimer=null)}reportMcpNodeLog(e){const t=this.wsClient;!this.agentId||!this.wsClient.isConnected()||typeof t.sendMcpNodeLog!="function"||t.sendMcpNodeLog(e)}getStatusReporter(){return this.statusReporter}}export{N as AgentClient,T as PollLongPollTimeoutError};
|
|
2
2
|
|
|
@@ -2,9 +2,19 @@
|
|
|
2
2
|
import type { ServerConfig } from "./types.js";
|
|
3
3
|
export interface McpToolResponse {
|
|
4
4
|
error?: string;
|
|
5
|
+
|
|
6
|
+
errorCode?: string;
|
|
7
|
+
|
|
8
|
+
field?: string;
|
|
5
9
|
[key: string]: unknown;
|
|
6
10
|
}
|
|
7
11
|
|
|
12
|
+
export declare class McpToolError extends Error {
|
|
13
|
+
readonly errorCode?: string;
|
|
14
|
+
readonly field?: string;
|
|
15
|
+
constructor(message: string, errorCode?: string, field?: string);
|
|
16
|
+
}
|
|
17
|
+
|
|
8
18
|
export declare function normalizeServerHttpBase(value: unknown, options?: {
|
|
9
19
|
fromAgentWebSocketUrl?: boolean;
|
|
10
20
|
}): string | undefined;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{logger as o}from"./logger.js";import{meetingDebugLog as h}from"./meeting-debug-log.js";const w=12e4,g=5e3,T=3e4,p=1e3;function d(l){const e=l.trim();return e?e.length<=p?e:`${e.slice(0,p)}...(truncated)`:""}function y(l){return l.replace(/^((?:https?|wss?):\/\/(?:\[[^\]]+\]|[^/:?#]+):\d+):\d+(?=\/|$)/i,"$1")}function C(l){const e=l.toLowerCase();return e==="localhost"||e==="::1"||e==="[::1]"?"127.0.0.1":e}function m(l,e={}){const r=k(l,e);if(r)try{const s=new URL(r);return s.pathname=s.pathname.includes("/mcp/call")?s.pathname:`${s.pathname.replace(/\/$/,"")}/mcp/call`,s.search="",s.hash="",s.toString()}catch{return r.endsWith("/mcp/call")?r:`${r}/mcp/call`}}function k(l,e={}){const r=String(l||"").trim();if(!r)return;const s=y(r);try{const t=new URL(s);t.protocol==="ws:"?t.protocol="http:":t.protocol==="wss:"?t.protocol="https:":t.protocol=t.protocol.toLowerCase(),t.hostname=C(t.hostname);const n=e.fromAgentWebSocketUrl?t.pathname.replace(/\/ws\/agent\/?$/,""):t.pathname;return t.pathname=n,t.search="",t.hash="",t.toString().replace(/\/+$/,"")}catch{return(e.fromAgentWebSocketUrl?s.replace(/\/ws\/agent\/?$/i,""):s).replace(/\/+$/,"")||void 0}}const $=6e5;class b{serverConfig;mcpHttpUrl;tokenRefreshPromise=null;constructor(e){this.serverConfig=e,this.mcpHttpUrl=this.resolveMcpHttpUrl()}async callTool(e,r){await this.ensureRuntimeAccessToken();const s=Date.now()+this.resolveRetryMaxAccumulatedMs();let t=0;for(;;){t++;let n;try{n=await this.executeToolRequest(e,r)}catch(a){if(Date.now()<s&&this.isTransientError(a)){await this.delayForRetry(s,e,t);continue}throw o.warn("[HttpClient] MCP tool %s \u8BF7\u6C42\u4E0D\u53EF\u6062\u590D\u5F02\u5E38 (attempt=%s): %s",e,t,a instanceof Error?a.message:String(a)),a}if(n.status===401){if(o.warn(`[HttpClient] MCP Tool ${e} \u8FD4\u56DE 401\uFF0C\u5C1D\u8BD5\u5411 bridge \u5237\u65B0 token`),await this.tryRefreshToken(r)){let c;try{c=await this.executeToolRequest(e,r)}catch(f){if(Date.now()<s&&this.isTransientError(f)){await this.delayForRetry(s,e,t);continue}throw o.warn("[HttpClient] MCP tool %s 401\u91CD\u8BD5\u5F02\u5E38 (attempt=%s): %s",e,t,f instanceof Error?f.message:String(f)),f}if(!c.ok){if(Date.now()<s&&this.isRetryableHttpStatus(c.status)){c.body&&await c.body.cancel().catch(()=>{}),await this.delayForRetry(s,e,t);continue}const f=typeof c.text=="function"?d(await c.text().catch(()=>"")):"";throw new Error(`MCP tool ${e} call failed: ${c.status} ${c.statusText}${f?` - ${f}`:""}`)}const u=await c.json();if(typeof u.error=="string"&&u.error.trim().length>0)throw new Error(`MCP tool ${e} failed: ${u.error}`);return u}o.warn("[HttpClient] token \u5237\u65B0\u5931\u8D25\u6216\u65E0\u65B0 token\uFF0C\u8FD4\u56DE\u539F\u59CB 401 \u9519\u8BEF")}if(!n.ok){if(Date.now()<s&&this.isRetryableHttpStatus(n.status)){n.body&&await n.body.cancel().catch(()=>{}),await this.delayForRetry(s,e,t);continue}const a=typeof n.text=="function"?d(await n.text().catch(()=>"")):"";throw new Error(`MCP tool ${e} call failed: ${n.status} ${n.statusText}${a?` - ${a}`:""}`)}const i=await n.json();if(typeof i.error=="string"&&i.error.trim().length>0)throw new Error(`MCP tool ${e} failed: ${i.error}`);return i}}async fetchRuntimeFeatures(){if(!this.serverConfig.runtimeAccessToken)throw new Error("fetch runtime features skipped: runtimeAccessToken not ready");const e=this.mcpHttpUrl.replace(/\/mcp\/call(\/)?$/,"/mcp/features$1");let r;try{r=await fetch(e,{method:"POST",headers:this.buildRequestHeaders(),body:JSON.stringify({}),signal:AbortSignal.timeout(5e3)})}catch(t){throw o.warn("[HttpClient] \u67E5\u8BE2\u80FD\u529B\u5F00\u5173\u8BF7\u6C42\u5931\u8D25: %s",t instanceof Error?t.message:String(t)),new Error(`fetch runtime features failed: ${t instanceof Error?t.message:String(t)}`)}if(!r.ok)throw o.warn("[HttpClient] \u67E5\u8BE2\u80FD\u529B\u5F00\u5173\u5931\u8D25: status=%s, statusText=%s",r.status,r.statusText),new Error(`fetch runtime features failed: ${r.status} ${r.statusText}`);const s=await r.json();return!s||typeof s.features!="object"||s.features===null?{}:s.features}async callToolOnce(e,r,s=$){await this.ensureRuntimeAccessToken(),o.info("[HttpClient] callToolOnce \u5F00\u59CB: tool=%s, timeoutMs=%d, url=%s, agentId=%s",e,s,this.mcpHttpUrl,String(r?.agentId??"")),e==="poll_message"&&h("http.callToolOnce.start",`tool=${e} timeoutMs=${s} preemptiveJoinWaitMs=${String(r?.preemptiveJoinWaitMs??"-")}`);const t=c=>fetch(this.mcpHttpUrl,{method:"POST",headers:this.buildRequestHeaders(),body:JSON.stringify({tool:e,arguments:r}),signal:c}),n=Date.now();let i=await this.singleFetchWithTimeout(t,s,e);if(o.info("[HttpClient] callToolOnce \u6536\u5230\u54CD\u5E94: tool=%s, status=%d, \u8017\u65F6=%dms",e,i.status,Date.now()-n),e==="poll_message"&&h("http.callToolOnce.response",`status=${i.status} elapsedMs=${Date.now()-n}`),i.status===401&&(o.warn(`[HttpClient] MCP Tool ${e} \u8FD4\u56DE 401\uFF0C\u5C1D\u8BD5\u5411 bridge \u5237\u65B0 token`),await this.tryRefreshToken(r)&&(i=await this.singleFetchWithTimeout(t,s,e),o.info("[HttpClient] callToolOnce token \u5237\u65B0\u540E\u91CD\u8BD5\u6536\u5230\u54CD\u5E94: tool=%s, status=%d, \u7D2F\u8BA1\u8017\u65F6=%dms",e,i.status,Date.now()-n))),!i.ok){const c=typeof i.text=="function"?d(await this.readTextWithTimeout(i,s,e).catch(()=>"")):"";throw o.info("[HttpClient] callToolOnce \u975E 2xx \u54CD\u5E94: tool=%s, status=%d, body=%s",e,i.status,c||"(\u7A7A)"),new Error(`MCP tool ${e} call failed: ${i.status} ${i.statusText}${c?` - ${c}`:""}`)}const a=await this.parseJsonWithTimeout(i,s,e);if(o.info("[HttpClient] callToolOnce \u5B8C\u6210: tool=%s, \u603B\u8017\u65F6=%dms, error=%s",e,Date.now()-n,typeof a.error=="string"?a.error:"(\u65E0)"),e==="poll_message"){const c=Array.isArray(a.messages)?a.messages:[];h("http.callToolOnce.parsed",`totalElapsedMs=${Date.now()-n} serverMessages=${c.length} `+JSON.stringify(c.map(u=>({msgId:u.msgId,channel:u.channel,sender:u.senderId}))))}if(typeof a.error=="string"&&a.error.trim().length>0)throw new Error(`MCP tool ${e} failed: ${a.error}`);return a}async readTextWithTimeout(e,r,s){if(r<=0)return await e.text();let t;try{return await Promise.race([e.text(),new Promise((n,i)=>{t=setTimeout(()=>i(new Error(`MCP tool ${s} timed out after ${r}ms`)),r)})])}finally{t!==void 0&&clearTimeout(t)}}async parseJsonWithTimeout(e,r,s){if(r<=0)return await e.json();let t;try{return await Promise.race([e.json(),new Promise((n,i)=>{t=setTimeout(()=>i(new Error(`MCP tool ${s} timed out after ${r}ms`)),r)})])}finally{t!==void 0&&clearTimeout(t)}}async singleFetchWithTimeout(e,r,s){const t=new AbortController;let n;r>0&&(n=setTimeout(()=>t.abort(),r));try{return await e(t.signal)}catch(i){throw t.signal.aborted?(s==="poll_message"&&h("http.callToolOnce.timeout",`timeoutMs=${r} \u670D\u52A1\u7AEF\u53EF\u80FD\u4ECD\u5728\u6267\u884C\u540C\u4E00\u8BF7\u6C42\uFF08Callable \u5360\u7EBF\u81F3\u9884\u7B97\u7ED3\u675F\uFF09`),new Error(`MCP tool ${s} timed out after ${r}ms`)):i}finally{n!==void 0&&clearTimeout(n)}}async executeToolRequest(e,r){return await this.fetchWithTimeout(this.mcpHttpUrl,{method:"POST",headers:this.buildRequestHeaders(),body:JSON.stringify({tool:e,arguments:r})},`MCP tool ${e}`)}async fetchWithTimeout(e,r,s){const t=this.resolveRequestTimeoutMs(),n=new AbortController,i=setTimeout(()=>n.abort(),t);try{return await fetch(e,{...r,signal:n.signal})}catch(a){throw n.signal.aborted?new Error(`${s} timed out after ${t}ms`):a}finally{clearTimeout(i)}}resolveRequestTimeoutMs(){const e=this.serverConfig.mcpHttpRequestTimeoutMs;return typeof e=="number"&&Number.isFinite(e)&&e>0?e:w}resolveRetryIntervalMs(){const e=this.serverConfig.mcpRetryIntervalMs;return typeof e=="number"&&Number.isFinite(e)&&e>=0?e:g}resolveRetryMaxAccumulatedMs(){const e=this.serverConfig.mcpRetryMaxAccumulatedMs;return typeof e=="number"&&Number.isFinite(e)&&e>=0?e:T}isTransientError(e){if(!(e instanceof Error))return!1;const r=e.message;return!!(/timed out after \d+ms/.test(r)||/fetch failed/i.test(r)||/network/i.test(r)||/ECONNREFUSED/i.test(r)||/ECONNRESET/i.test(r))}isRetryableHttpStatus(e){return e>=500||e===429}async delayForRetry(e,r,s){const t=e-Date.now(),n=Math.min(this.resolveRetryIntervalMs(),Math.max(0,t));o.warn(`[HttpClient] MCP tool ${r} \u8BF7\u6C42\u5931\u8D25\uFF0C${n}ms \u540E\u91CD\u8BD5 (\u7B2C${s}\u6B21)`),n>0&&await new Promise(i=>setTimeout(i,n))}buildRequestHeaders(){const e={"Content-Type":"application/json"};return this.serverConfig.runtimeAccessToken&&(e["X-Runtime-Token"]=this.serverConfig.runtimeAccessToken,e.Authorization=`Bearer ${this.serverConfig.runtimeAccessToken}`),e}async ensureRuntimeAccessToken(){if(this.serverConfig.runtimeAccessToken||!this.serverConfig.runtimeBridgeBaseUrl){o.info("[HttpClient] ensureRuntimeAccessToken: tokenLen=%d, bridgeBaseUrl=%s",(this.serverConfig.runtimeAccessToken||"").length,this.serverConfig.runtimeBridgeBaseUrl||"(\u7A7A)");return}throw new Error("runtimeAccessToken is required; MCP nodes must claim a session token from launch binding")}async tryRefreshToken(e){if(this.tokenRefreshPromise)return this.tokenRefreshPromise;this.tokenRefreshPromise=this.doRefreshToken(e);try{return await this.tokenRefreshPromise}finally{this.tokenRefreshPromise=null}}async doRefreshToken(e){const r=this.serverConfig.runtimeBridgeBaseUrl;if(!r)return o.warn("[HttpClient] \u65E0 runtimeBridgeBaseUrl\uFF0C\u65E0\u6CD5\u5237\u65B0 token"),!1;const s=String(e?.agentId||"").trim();if(!s)return o.warn("[HttpClient] \u65E0 agentId\uFF0C\u65E0\u6CD5\u5237\u65B0 token"),!1;try{const t=await fetch(`${r}/runtime/binding/refresh-token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({agentId:s,currentToken:this.serverConfig.runtimeAccessToken||""})});if(!t.ok)return o.warn(`[HttpClient] bridge refresh-token \u8FD4\u56DE ${t.status}\uFF0C\u65E0\u6CD5\u5237\u65B0`),!1;const i=(await t.json()).runtimeAccessToken;return i?i===this.serverConfig.runtimeAccessToken?!1:(this.serverConfig.runtimeAccessToken=i,o.info("[HttpClient] runtimeAccessToken \u5DF2\u901A\u8FC7 bridge refresh \u66F4\u65B0"),!0):(o.warn("[HttpClient] bridge \u672A\u8FD4\u56DE\u65B0 token"),!1)}catch(t){return o.warn("[HttpClient] \u5237\u65B0 token \u5931\u8D25: %s",t instanceof Error?t.message:String(t)),t instanceof Error&&t.stack&&o.warn("[HttpClient] \u5237\u65B0 token \u5F02\u5E38\u5806\u6808:",t.stack),!1}}async refreshRuntimeAccessToken(e){return this.tryRefreshToken({agentId:e})}resolveMcpHttpUrl(){const e=this.serverConfig.mcpHttpUrl;if(e&&e.trim().length>0){const s=m(e);if(s)return s}const r=m(this.serverConfig.serverUrl,{fromAgentWebSocketUrl:!0});return r||this.serverConfig.serverUrl}getMcpHttpUrl(){return this.mcpHttpUrl}}export{b as HttpClient,k as normalizeServerHttpBase};
|
|
1
|
+
import{logger as c}from"./logger.js";import{meetingDebugLog as h}from"./meeting-debug-log.js";class g extends Error{errorCode;field;constructor(e,r,s){super(e),this.name="McpToolError",this.errorCode=r,this.field=s}}const w=12e4,T=5e3,y=3e4,p=1e3;function d(l){const e=l.trim();return e?e.length<=p?e:`${e.slice(0,p)}...(truncated)`:""}function C(l){return l.replace(/^((?:https?|wss?):\/\/(?:\[[^\]]+\]|[^/:?#]+):\d+):\d+(?=\/|$)/i,"$1")}function k(l){const e=l.toLowerCase();return e==="localhost"||e==="::1"||e==="[::1]"?"127.0.0.1":e}function m(l,e={}){const r=$(l,e);if(r)try{const s=new URL(r);return s.pathname=s.pathname.includes("/mcp/call")?s.pathname:`${s.pathname.replace(/\/$/,"")}/mcp/call`,s.search="",s.hash="",s.toString()}catch{return r.endsWith("/mcp/call")?r:`${r}/mcp/call`}}function $(l,e={}){const r=String(l||"").trim();if(!r)return;const s=C(r);try{const t=new URL(s);t.protocol==="ws:"?t.protocol="http:":t.protocol==="wss:"?t.protocol="https:":t.protocol=t.protocol.toLowerCase(),t.hostname=k(t.hostname);const n=e.fromAgentWebSocketUrl?t.pathname.replace(/\/ws\/agent\/?$/,""):t.pathname;return t.pathname=n,t.search="",t.hash="",t.toString().replace(/\/+$/,"")}catch{return(e.fromAgentWebSocketUrl?s.replace(/\/ws\/agent\/?$/i,""):s).replace(/\/+$/,"")||void 0}}const R=6e5;class M{serverConfig;mcpHttpUrl;tokenRefreshPromise=null;constructor(e){this.serverConfig=e,this.mcpHttpUrl=this.resolveMcpHttpUrl()}async callTool(e,r){await this.ensureRuntimeAccessToken();const s=Date.now()+this.resolveRetryMaxAccumulatedMs();let t=0;for(;;){t++;let n;try{n=await this.executeToolRequest(e,r)}catch(o){if(Date.now()<s&&this.isTransientError(o)){await this.delayForRetry(s,e,t);continue}throw c.warn("[HttpClient] MCP tool %s \u8BF7\u6C42\u4E0D\u53EF\u6062\u590D\u5F02\u5E38 (attempt=%s): %s",e,t,o instanceof Error?o.message:String(o)),o}if(n.status===401){if(c.warn(`[HttpClient] MCP Tool ${e} \u8FD4\u56DE 401\uFF0C\u5C1D\u8BD5\u5411 bridge \u5237\u65B0 token`),await this.tryRefreshToken(r)){let a;try{a=await this.executeToolRequest(e,r)}catch(f){if(Date.now()<s&&this.isTransientError(f)){await this.delayForRetry(s,e,t);continue}throw c.warn("[HttpClient] MCP tool %s 401\u91CD\u8BD5\u5F02\u5E38 (attempt=%s): %s",e,t,f instanceof Error?f.message:String(f)),f}if(!a.ok){if(Date.now()<s&&this.isRetryableHttpStatus(a.status)){a.body&&await a.body.cancel().catch(()=>{}),await this.delayForRetry(s,e,t);continue}const f=typeof a.text=="function"?d(await a.text().catch(()=>"")):"";throw new Error(`MCP tool ${e} call failed: ${a.status} ${a.statusText}${f?` - ${f}`:""}`)}const u=await a.json();if(typeof u.error=="string"&&u.error.trim().length>0)throw new Error(`MCP tool ${e} failed: ${u.error}`);return u}c.warn("[HttpClient] token \u5237\u65B0\u5931\u8D25\u6216\u65E0\u65B0 token\uFF0C\u8FD4\u56DE\u539F\u59CB 401 \u9519\u8BEF")}if(!n.ok){if(Date.now()<s&&this.isRetryableHttpStatus(n.status)){n.body&&await n.body.cancel().catch(()=>{}),await this.delayForRetry(s,e,t);continue}const o=typeof n.text=="function"?d(await n.text().catch(()=>"")):"";throw new Error(`MCP tool ${e} call failed: ${n.status} ${n.statusText}${o?` - ${o}`:""}`)}const i=await n.json();if(typeof i.error=="string"&&i.error.trim().length>0)throw new Error(`MCP tool ${e} failed: ${i.error}`);return i}}async fetchRuntimeFeatures(){if(!this.serverConfig.runtimeAccessToken)throw new Error("fetch runtime features skipped: runtimeAccessToken not ready");const e=this.mcpHttpUrl.replace(/\/mcp\/call(\/)?$/,"/mcp/features$1");let r;try{r=await fetch(e,{method:"POST",headers:this.buildRequestHeaders(),body:JSON.stringify({}),signal:AbortSignal.timeout(5e3)})}catch(t){throw c.warn("[HttpClient] \u67E5\u8BE2\u80FD\u529B\u5F00\u5173\u8BF7\u6C42\u5931\u8D25: %s",t instanceof Error?t.message:String(t)),new Error(`fetch runtime features failed: ${t instanceof Error?t.message:String(t)}`)}if(!r.ok)throw c.warn("[HttpClient] \u67E5\u8BE2\u80FD\u529B\u5F00\u5173\u5931\u8D25: status=%s, statusText=%s",r.status,r.statusText),new Error(`fetch runtime features failed: ${r.status} ${r.statusText}`);const s=await r.json();return!s||typeof s.features!="object"||s.features===null?{}:s.features}async callToolOnce(e,r,s=R){await this.ensureRuntimeAccessToken(),c.info("[HttpClient] callToolOnce \u5F00\u59CB: tool=%s, timeoutMs=%d, url=%s, agentId=%s",e,s,this.mcpHttpUrl,String(r?.agentId??"")),e==="poll_message"&&h("http.callToolOnce.start",`tool=${e} timeoutMs=${s} preemptiveJoinWaitMs=${String(r?.preemptiveJoinWaitMs??"-")}`);const t=a=>fetch(this.mcpHttpUrl,{method:"POST",headers:this.buildRequestHeaders(),body:JSON.stringify({tool:e,arguments:r}),signal:a}),n=Date.now();let i=await this.singleFetchWithTimeout(t,s,e);if(c.info("[HttpClient] callToolOnce \u6536\u5230\u54CD\u5E94: tool=%s, status=%d, \u8017\u65F6=%dms",e,i.status,Date.now()-n),e==="poll_message"&&h("http.callToolOnce.response",`status=${i.status} elapsedMs=${Date.now()-n}`),i.status===401&&(c.warn(`[HttpClient] MCP Tool ${e} \u8FD4\u56DE 401\uFF0C\u5C1D\u8BD5\u5411 bridge \u5237\u65B0 token`),await this.tryRefreshToken(r)&&(i=await this.singleFetchWithTimeout(t,s,e),c.info("[HttpClient] callToolOnce token \u5237\u65B0\u540E\u91CD\u8BD5\u6536\u5230\u54CD\u5E94: tool=%s, status=%d, \u7D2F\u8BA1\u8017\u65F6=%dms",e,i.status,Date.now()-n))),!i.ok){const a=typeof i.text=="function"?d(await this.readTextWithTimeout(i,s,e).catch(()=>"")):"";throw c.info("[HttpClient] callToolOnce \u975E 2xx \u54CD\u5E94: tool=%s, status=%d, body=%s",e,i.status,a||"(\u7A7A)"),new Error(`MCP tool ${e} call failed: ${i.status} ${i.statusText}${a?` - ${a}`:""}`)}const o=await this.parseJsonWithTimeout(i,s,e);if(c.info("[HttpClient] callToolOnce \u5B8C\u6210: tool=%s, \u603B\u8017\u65F6=%dms, error=%s",e,Date.now()-n,typeof o.error=="string"?o.error:"(\u65E0)"),e==="poll_message"){const a=Array.isArray(o.messages)?o.messages:[];h("http.callToolOnce.parsed",`totalElapsedMs=${Date.now()-n} serverMessages=${a.length} `+JSON.stringify(a.map(u=>({msgId:u.msgId,channel:u.channel,sender:u.senderId}))))}if(typeof o.error=="string"&&o.error.trim().length>0){const a=typeof o.errorCode=="string"?o.errorCode:void 0,u=typeof o.field=="string"?o.field:void 0;throw new g(`MCP tool ${e} failed: ${o.error}`,a,u)}return o}async readTextWithTimeout(e,r,s){if(r<=0)return await e.text();let t;try{return await Promise.race([e.text(),new Promise((n,i)=>{t=setTimeout(()=>i(new Error(`MCP tool ${s} timed out after ${r}ms`)),r)})])}finally{t!==void 0&&clearTimeout(t)}}async parseJsonWithTimeout(e,r,s){if(r<=0)return await e.json();let t;try{return await Promise.race([e.json(),new Promise((n,i)=>{t=setTimeout(()=>i(new Error(`MCP tool ${s} timed out after ${r}ms`)),r)})])}finally{t!==void 0&&clearTimeout(t)}}async singleFetchWithTimeout(e,r,s){const t=new AbortController;let n;r>0&&(n=setTimeout(()=>t.abort(),r));try{return await e(t.signal)}catch(i){throw t.signal.aborted?(s==="poll_message"&&h("http.callToolOnce.timeout",`timeoutMs=${r} \u670D\u52A1\u7AEF\u53EF\u80FD\u4ECD\u5728\u6267\u884C\u540C\u4E00\u8BF7\u6C42\uFF08Callable \u5360\u7EBF\u81F3\u9884\u7B97\u7ED3\u675F\uFF09`),new Error(`MCP tool ${s} timed out after ${r}ms`)):i}finally{n!==void 0&&clearTimeout(n)}}async executeToolRequest(e,r){return await this.fetchWithTimeout(this.mcpHttpUrl,{method:"POST",headers:this.buildRequestHeaders(),body:JSON.stringify({tool:e,arguments:r})},`MCP tool ${e}`)}async fetchWithTimeout(e,r,s){const t=this.resolveRequestTimeoutMs(),n=new AbortController,i=setTimeout(()=>n.abort(),t);try{return await fetch(e,{...r,signal:n.signal})}catch(o){throw n.signal.aborted?new Error(`${s} timed out after ${t}ms`):o}finally{clearTimeout(i)}}resolveRequestTimeoutMs(){const e=this.serverConfig.mcpHttpRequestTimeoutMs;return typeof e=="number"&&Number.isFinite(e)&&e>0?e:w}resolveRetryIntervalMs(){const e=this.serverConfig.mcpRetryIntervalMs;return typeof e=="number"&&Number.isFinite(e)&&e>=0?e:T}resolveRetryMaxAccumulatedMs(){const e=this.serverConfig.mcpRetryMaxAccumulatedMs;return typeof e=="number"&&Number.isFinite(e)&&e>=0?e:y}isTransientError(e){if(!(e instanceof Error))return!1;const r=e.message;return!!(/timed out after \d+ms/.test(r)||/fetch failed/i.test(r)||/network/i.test(r)||/ECONNREFUSED/i.test(r)||/ECONNRESET/i.test(r))}isRetryableHttpStatus(e){return e>=500||e===429}async delayForRetry(e,r,s){const t=e-Date.now(),n=Math.min(this.resolveRetryIntervalMs(),Math.max(0,t));c.warn(`[HttpClient] MCP tool ${r} \u8BF7\u6C42\u5931\u8D25\uFF0C${n}ms \u540E\u91CD\u8BD5 (\u7B2C${s}\u6B21)`),n>0&&await new Promise(i=>setTimeout(i,n))}buildRequestHeaders(){const e={"Content-Type":"application/json"};return this.serverConfig.runtimeAccessToken&&(e["X-Runtime-Token"]=this.serverConfig.runtimeAccessToken,e.Authorization=`Bearer ${this.serverConfig.runtimeAccessToken}`),e}async ensureRuntimeAccessToken(){if(this.serverConfig.runtimeAccessToken||!this.serverConfig.runtimeBridgeBaseUrl){c.info("[HttpClient] ensureRuntimeAccessToken: tokenLen=%d, bridgeBaseUrl=%s",(this.serverConfig.runtimeAccessToken||"").length,this.serverConfig.runtimeBridgeBaseUrl||"(\u7A7A)");return}throw new Error("runtimeAccessToken is required; MCP nodes must claim a session token from launch binding")}async tryRefreshToken(e){if(this.tokenRefreshPromise)return this.tokenRefreshPromise;this.tokenRefreshPromise=this.doRefreshToken(e);try{return await this.tokenRefreshPromise}finally{this.tokenRefreshPromise=null}}async doRefreshToken(e){const r=this.serverConfig.runtimeBridgeBaseUrl;if(!r)return c.warn("[HttpClient] \u65E0 runtimeBridgeBaseUrl\uFF0C\u65E0\u6CD5\u5237\u65B0 token"),!1;const s=String(e?.agentId||"").trim();if(!s)return c.warn("[HttpClient] \u65E0 agentId\uFF0C\u65E0\u6CD5\u5237\u65B0 token"),!1;try{const t=await fetch(`${r}/runtime/binding/refresh-token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({agentId:s,currentToken:this.serverConfig.runtimeAccessToken||""})});if(!t.ok)return c.warn(`[HttpClient] bridge refresh-token \u8FD4\u56DE ${t.status}\uFF0C\u65E0\u6CD5\u5237\u65B0`),!1;const i=(await t.json()).runtimeAccessToken;return i?i===this.serverConfig.runtimeAccessToken?!1:(this.serverConfig.runtimeAccessToken=i,c.info("[HttpClient] runtimeAccessToken \u5DF2\u901A\u8FC7 bridge refresh \u66F4\u65B0"),!0):(c.warn("[HttpClient] bridge \u672A\u8FD4\u56DE\u65B0 token"),!1)}catch(t){return c.warn("[HttpClient] \u5237\u65B0 token \u5931\u8D25: %s",t instanceof Error?t.message:String(t)),t instanceof Error&&t.stack&&c.warn("[HttpClient] \u5237\u65B0 token \u5F02\u5E38\u5806\u6808:",t.stack),!1}}async refreshRuntimeAccessToken(e){return this.tryRefreshToken({agentId:e})}resolveMcpHttpUrl(){const e=this.serverConfig.mcpHttpUrl;if(e&&e.trim().length>0){const s=m(e);if(s)return s}const r=m(this.serverConfig.serverUrl,{fromAgentWebSocketUrl:!0});return r||this.serverConfig.serverUrl}getMcpHttpUrl(){return this.mcpHttpUrl}}export{M as HttpClient,g as McpToolError,$ as normalizeServerHttpBase};
|
|
2
2
|
|
|
@@ -21,7 +21,6 @@ export declare function buildStartupLogFilePath(options?: {
|
|
|
21
21
|
export declare function initializeStartupLogFile(): string | null;
|
|
22
22
|
|
|
23
23
|
export declare function updateStartupLogIdentity(roleName: string, instanceName: string): void;
|
|
24
|
-
|
|
25
24
|
export declare function appendStartupLogLine(level: LogLevel, message: string): void;
|
|
26
25
|
|
|
27
26
|
export declare function getStartupLogFilePath(): string | null;
|
|
@@ -34,3 +33,5 @@ export declare const logger: {
|
|
|
34
33
|
warn: (...args: unknown[]) => void;
|
|
35
34
|
error: (...args: unknown[]) => void;
|
|
36
35
|
};
|
|
36
|
+
|
|
37
|
+
export declare function isDebugEnabled(): boolean;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import*as u from"node:fs";import*as f from"node:os";import*as
|
|
2
|
-
|
|
1
|
+
import*as u from"node:fs";import*as f from"node:os";import*as i from"node:path";import{format as m}from"node:util";const d=new Date,N=new Set(["0","false","off","no"]),L=200,S="aws-mcp-node";let n,s=null,g=null;const l=[];function c(e,r=2){return String(e).padStart(r,"0")}function P(e){return`${e.getFullYear()}-${c(e.getMonth()+1)}`}function A(e){return[c(e.getDate()),"-",c(e.getHours()),c(e.getMinutes()),c(e.getSeconds()),c(e.getMilliseconds(),3)].join("")}function h(e){const r=new RegExp("[\0-]","g");return e.replace(/[<>:"/\\|?*]/g,"_").replace(r,"_").replace(/\s+/g," ").trim().replace(/[. ]+$/g,"")||"workspace"}function _(e={}){const r=e.logDir||i.join(e.homeDir||f.homedir(),".aws-bridge","log"),t=h(e.roleName||process.env.AWS_ROLE_NAME||"unknown-role"),o=h(e.instanceName||process.env.AWS_AGENT_ID||"unknown-instance"),a=e.startupTime||d,E=P(a),M=`${A(a)}.log`;return i.join(r,"agent",S,`${t}-${o}`,E,M)}function x(){if(n!==void 0)return n;const e=String(process.env.AWS_MCP_FILE_LOG||"").trim().toLowerCase();if(N.has(e))return n=null,null;try{return s=process.env.AWS_MCP_LOG_DIR||void 0||i.join(f.homedir(),".aws-bridge","log"),n=_({logDir:s,roleName:process.env.AWS_ROLE_NAME||void 0,instanceName:process.env.AWS_AGENT_ID||void 0}),u.mkdirSync(i.dirname(n),{recursive:!0}),n}catch(r){return n=null,s=null,console.warn("[Logger] \u65E0\u6CD5\u521B\u5EFA MCP \u542F\u52A8\u65E5\u5FD7\u6587\u4EF6:",r),null}}function I(e,r){if(n==null||!s)return;const t=n,o=_({logDir:s,roleName:e,instanceName:r,startupTime:d});if(t!==o)try{u.mkdirSync(i.dirname(o),{recursive:!0}),u.renameSync(t,o),n=o,console.log(`[Logger] MCP \u542F\u52A8\u65E5\u5FD7\u8DEF\u5F84\u5DF2\u66F4\u65B0: ${t} -> ${o}`);const a=i.join(s,"agent",S);y(i.dirname(t),a)}catch(a){console.warn("[Logger] \u65E0\u6CD5\u66F4\u65B0 MCP \u542F\u52A8\u65E5\u5FD7\u8EAB\u4EFD\u6807\u8BC6:",a)}}function y(e,r){let t=i.normalize(e);const o=i.normalize(r),a=i.parse(t).root;for(;t!==o&&t!==a;){try{u.rmdirSync(t)}catch{break}t=i.dirname(t)}}let w=Promise.resolve(),D=!1;function C(e,r){if(n===void 0)return;const t=n;if(!t)return;const o=`${new Date().toISOString()} [${e.toUpperCase()}] ${r}
|
|
2
|
+
`;w=w.then(async()=>{if(n!==null)try{await u.promises.appendFile(t,o,"utf8")}catch{if(n=null,!D){D=!0;try{console.error("[Logger] MCP \u542F\u52A8\u65E5\u5FD7\u6587\u4EF6\u5199\u5165\u5931\u8D25\uFF0C\u5DF2\u5173\u95ED\u6587\u4EF6\u65E5\u5FD7:",t)}catch{}}}})}function O(){return n??null}function F(e,r){C(e,m(...r))}function p(e,r){const t={level:e,message:m(...r),timestamp:new Date().toISOString()};if(F(e,r),$(t),!!process.stderr.isTTY)try{switch(e){case"info":console.error(...r);break;case"warn":console.warn(...r);break;case"error":console.error(...r);break}}catch{}}function T(e){if(g=e,!!e)for(const r of l)e(r)}function $(e){l.push(e),l.length>L&&l.splice(0,l.length-L),g&&g(e)}const k={debug:(...e)=>{},info:(...e)=>p("info",e),warn:(...e)=>p("warn",e),error:(...e)=>p("error",e)};function v(){return!1}export{C as appendStartupLogLine,_ as buildStartupLogFilePath,A as formatLogFileTimestamp,P as formatLogYearMonth,O as getStartupLogFilePath,x as initializeStartupLogFile,v as isDebugEnabled,k as logger,h as sanitizeLogFileNameSegment,T as setMcpNodeLogSink,I as updateStartupLogIdentity};
|
|
3
3
|
|