aws-runtime-bridge 1.9.162 → 1.9.169

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/CHANGELOG.md +324 -0
  2. package/dist/adapter/AcodeSdkAdapter.d.ts +31 -3
  3. package/dist/adapter/AcodeSdkAdapter.js +4 -9
  4. package/dist/adapter/ClaudeSdkAdapter.d.ts +2 -0
  5. package/dist/adapter/ClaudeSdkAdapter.js +3 -3
  6. package/dist/adapter/CodexSdkAdapter.d.ts +2 -0
  7. package/dist/adapter/CodexSdkAdapter.js +3 -3
  8. package/dist/adapter/OpencodeSdkAdapter.d.ts +2 -0
  9. package/dist/adapter/OpencodeSdkAdapter.js +3 -3
  10. package/dist/adapter/prompts.d.ts +1 -1
  11. package/dist/adapter/prompts.js +1 -1
  12. package/dist/adapter/types.d.ts +41 -4
  13. package/dist/adapter/types.js +1 -1
  14. package/dist/browser/frame-encode.d.ts +25 -0
  15. package/dist/browser/frame-encode.js +2 -0
  16. package/dist/browser/screencast-differ.d.ts +2 -3
  17. package/dist/browser/screencast-differ.js +1 -1
  18. package/dist/browser/screencast-manager.js +1 -1
  19. package/dist/browser/types.d.ts +5 -1
  20. package/dist/browser/types.js +1 -1
  21. package/dist/desktop/desktop-mcp-client.js +2 -2
  22. package/dist/routes/background-tasks.js +3 -3
  23. package/dist/routes/capabilities.js +1 -1
  24. package/dist/routes/dashboard.d.ts +2 -0
  25. package/dist/routes/dashboard.js +4 -4
  26. package/dist/routes/git.js +22 -22
  27. package/dist/routes/instance.js +1 -1
  28. package/dist/routes/launch.js +10 -10
  29. package/dist/routes/mcp-extra.js +2 -2
  30. package/dist/routes/mcp.d.ts +4 -0
  31. package/dist/routes/mcp.js +1 -1
  32. package/dist/routes/plugins.js +1 -1
  33. package/dist/routes/pty.d.ts +11 -3
  34. package/dist/routes/pty.js +3 -3
  35. package/dist/routes/runtime-binding.js +1 -1
  36. package/dist/routes/sessions.js +1 -1
  37. package/dist/routes/skills.js +1 -1
  38. package/dist/routes/sub-agents.js +8 -8
  39. package/dist/routes/terminal.d.ts +16 -2
  40. package/dist/routes/terminal.js +34 -36
  41. package/dist/services/agent-process-manager.js +1 -1
  42. package/dist/services/agent-pty-manager.js +4 -4
  43. package/dist/services/aws-client-agent-mcp.js +2 -2
  44. package/dist/services/capability-config.d.ts +8 -0
  45. package/dist/services/capability-config.js +2 -2
  46. package/dist/services/desktop-mcp-manager.d.ts +3 -1
  47. package/dist/services/desktop-mcp-manager.js +1 -1
  48. package/dist/services/instance-ai-config-service.js +1 -1
  49. package/dist/services/instance-features.d.ts +10 -0
  50. package/dist/services/instance-features.js +1 -1
  51. package/dist/services/instance-init-service.js +1 -1
  52. package/dist/services/launch-manager.d.ts +9 -1
  53. package/dist/services/launch-manager.js +6 -6
  54. package/dist/services/launch-metrics.d.ts +1 -1
  55. package/dist/services/launch-metrics.js +4 -3
  56. package/dist/services/mcp-deploy.d.ts +4 -0
  57. package/dist/services/mcp-env-injector.d.ts +12 -0
  58. package/dist/services/mcp-env-injector.js +2 -0
  59. package/dist/services/mcp-launch-binding-queue.d.ts +8 -0
  60. package/dist/services/mcp-launch-binding-queue.js +1 -1
  61. package/dist/services/orphan-monitor.js +1 -1
  62. package/dist/services/panel-env.d.ts +6 -2
  63. package/dist/services/panel-env.js +1 -1
  64. package/dist/services/plugin-manager.js +9 -9
  65. package/dist/services/process-detector.d.ts +23 -3
  66. package/dist/services/process-detector.js +13 -13
  67. package/dist/services/runtime-resources-snapshot.d.ts +3 -0
  68. package/dist/services/runtime-resources-snapshot.js +3 -0
  69. package/dist/services/session-output.d.ts +13 -0
  70. package/dist/services/session-output.js +4 -4
  71. package/dist/services/tunnel-client.js +1 -1
  72. package/dist/services/workspace-files.js +1 -1
  73. package/dist/types.d.ts +4 -0
  74. package/dist/utils/env-safety.d.ts +15 -0
  75. package/dist/utils/env-safety.js +2 -0
  76. package/dist/utils/lifecycle-log.d.ts +2 -0
  77. package/dist/utils/lifecycle-log.js +3 -0
  78. package/dist/utils/mcp-utils.js +1 -1
  79. package/package/acode/dist/background-command-manager.js +4 -4
  80. package/package/acode/dist/built-in-file-tools.d.ts +13 -0
  81. package/package/acode/dist/built-in-file-tools.js +2 -2
  82. package/package/acode/dist/builtins/shellCommandPreparation.d.ts +2 -0
  83. package/package/acode/dist/builtins/shellCommandPreparation.js +2 -2
  84. package/package/acode/dist/compaction.d.ts +10 -0
  85. package/package/acode/dist/compaction.js +6 -6
  86. package/package/acode/dist/context-overflow.js +1 -1
  87. package/package/acode/dist/index.d.ts +1 -0
  88. package/package/acode/dist/index.js +1 -1
  89. package/package/acode/dist/mcpToolNames.d.ts +4 -0
  90. package/package/acode/dist/mcpToolNames.js +1 -1
  91. package/package/acode/dist/runtime-environment.d.ts +2 -0
  92. package/package/acode/dist/runtime-environment.js +3 -2
  93. package/package/acode/dist/runtime.d.ts +68 -8
  94. package/package/acode/dist/runtime.js +28 -27
  95. package/package/acode/dist/sub-agent-manager.js +1 -1
  96. package/package/acode/dist/tool-allocation.js +1 -1
  97. package/package/acode/dist/tool-group-manager.d.ts +12 -0
  98. package/package/acode/dist/tool-group-manager.js +8 -4
  99. package/package/acode/dist/types.d.ts +8 -0
  100. package/package/acode/package.json +1 -1
  101. package/package/aws-client-agent-mcp/README.md +1 -0
  102. package/package/aws-client-agent-mcp/dist/agent-client.d.ts +22 -8
  103. package/package/aws-client-agent-mcp/dist/agent-client.js +1 -1
  104. package/package/aws-client-agent-mcp/dist/http-client.d.ts +10 -0
  105. package/package/aws-client-agent-mcp/dist/http-client.js +1 -1
  106. package/package/aws-client-agent-mcp/dist/logger.d.ts +2 -1
  107. package/package/aws-client-agent-mcp/dist/logger.js +2 -2
  108. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +19 -2
  109. package/package/aws-client-agent-mcp/dist/mcp-server.js +18 -18
  110. package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +15 -4
  111. package/package/aws-client-agent-mcp/dist/mcp-tools.js +79 -29
  112. package/package/aws-client-agent-mcp/dist/memory-store.d.ts +2 -0
  113. package/package/aws-client-agent-mcp/dist/memory-store.js +3 -3
  114. package/package/aws-client-agent-mcp/dist/message-buffer.js +1 -1
  115. package/package/aws-client-agent-mcp/dist/office/office-workspace.d.ts +15 -0
  116. package/package/aws-client-agent-mcp/dist/office/office-workspace.js +1 -1
  117. package/package/aws-client-agent-mcp/dist/status-reporter.js +1 -1
  118. package/package/aws-client-agent-mcp/dist/tool-groups.d.ts +4 -0
  119. package/package/aws-client-agent-mcp/dist/tool-groups.js +2 -2
  120. package/package/aws-client-agent-mcp/dist/types.d.ts +52 -1
  121. package/package/aws-client-agent-mcp/dist/websocket-client.js +1 -1
  122. package/package/aws-client-agent-mcp/package.json +1 -1
  123. package/package.json +1 -1
@@ -1,2 +1,2 @@
1
- import{randomUUID as S}from"node:crypto";import{ACodeRuntime as w}from"./runtime.js";const T=30*60*1e3,m=2*60*1e3,f=12*60*1e3,b=5e3,c=[100,500,2e3,8e3],E=6e4,A=10*60*1e3;class k{constructor(t){this.subAgents=new Map,this.parentToSubs=new Map,this.subscribers=new Map,this.cleanupTimer=null,this.completionQueue=[],this.completionWaiterResolve=null,this.pendingPersists=new Set,this.store=t.store,this.maxConcurrent=t.maxConcurrent??5,this.cleanupTimer=setInterval(()=>{this.cleanupCompletedEntries(),this.recoverZombieEntries()},5*60*1e3),this.cleanupTimer.unref&&this.cleanupTimer.unref(),this.store.reconcileZombies().catch(()=>{})}async spawn(t){if(this.countByStatus(t.parentAgentId,"running","pending")>=this.maxConcurrent)throw new Error(`concurrent sub-agent limit reached (${this.maxConcurrent}) for agent ${t.parentAgentId}`);const s=`sub-${S()}`,n=Date.now(),i=new AbortController,o={...t.parentConfig,sessionId:s,workingDirectory:t.workingDirectory,agentId:`${t.parentAgentId}__sub__${s}`,initialPrompt:void 0,subAgentManager:void 0,subAgentAllowedTools:t.allowedTools&&t.allowedTools.length>0?t.allowedTools:void 0,...t.parentConfig.subAgentModel?{model:t.parentConfig.subAgentModel}:{},...t.parentConfig.subAgentEffort?{effort:t.parentConfig.subAgentEffort}:{},subAgentModel:void 0,subAgentEffort:void 0,pluginBridge:void 0},r=new w(o),a={subId:s,parentAgentId:t.parentAgentId,parentSessionId:t.parentSessionId,subagentType:t.subagentType,description:t.description,prompt:t.prompt,status:"pending",startedAt:n,runtime:r,abortController:i,silent:t.silent,contextSnapshot:{tokenUsage:{input:0,output:0},messageCount:0,updatedAt:new Date().toISOString()},availableTools:[],...t.allowedTools&&t.allowedTools.length>0?{allocatedTools:t.allowedTools}:{}};this.subAgents.set(s,a),this.addToParentMap(t.parentAgentId,s);const u=this.toRecord(a);return await this.store.upsert(t.parentAgentId,u),r.on("event",l=>{this.handleRuntimeEvent(s,l)}),this.emitEvent(s,"spawned",{}),s}async start(t){const e=this.subAgents.get(t);if(!e)throw new Error(`sub-agent not found: ${t}`);if(e.status!=="pending")throw new Error(`sub-agent ${t} cannot start from status: ${e.status}`);e.completionPromise=new Promise((s,n)=>{e.completionResolve=s,e.completionReject=n}),this.runEntryToCompletion(e).catch(()=>{})}async startWithRecheck(t,e,s=3){const n=this.subAgents.get(t);if(!n)throw new Error(`sub-agent not found: ${t}`);if(n.status!=="pending")throw new Error(`sub-agent ${t} cannot start from status: ${n.status}`);n.completionPromise=new Promise((i,o)=>{n.completionResolve=i,n.completionReject=o}),this.runEntryToCompletionWithRecheck(n,e,s).catch(()=>{})}async awaitCompletion(t,e=0){if(t.length===0)return[];const s=[],n=t.map(async o=>{const r=this.subAgents.get(o);if(!r){const u=await this.findRecordInStore(o);u?s.push({subId:o,output:u.result??"",error:u.errorMessage,status:u.status}):s.push({subId:o,output:"",error:`sub-agent not found: ${o}`,status:"failed"});return}r.awaited=!0,r.status==="pending"&&await this.start(o);const a=r.completionPromise??Promise.resolve({output:"",error:"not started"});try{const u=await a;s.push({subId:o,output:u.output,error:u.error,status:r.status})}catch(u){s.push({subId:o,output:"",error:u instanceof Error?u.message:String(u),status:r.status})}}),i=new Set(t);for(let o=this.completionQueue.length-1;o>=0;o--)i.has(this.completionQueue[o].subId)&&this.completionQueue.splice(o,1);return e>0?await Promise.race([Promise.allSettled(n),new Promise(o=>setTimeout(()=>o(),e))]):await Promise.allSettled(n),s}async runEntryToCompletion(t){const e=[];let s=!1,n;const i=o=>{if(o)switch(o.type){case"assistant_delta":typeof o.data?.text=="string"&&e.push(o.data.text);break;case"turn_complete":o.data?.failed&&(s=!0);break;case"error":typeof o.data?.message=="string"&&(n=o.data.message);break}};t.runtime.on("event",i),t.status="running",t.contextSnapshot.currentTool="[starting]",t.contextSnapshot.updatedAt=new Date().toISOString(),this.emitEvent(t.subId,"running",{snapshot:{...t.contextSnapshot}});try{await d(this.store.updateStatus(t.parentAgentId,t.subId,{status:"running"}),b,`sub-agent ${t.subId} store.updateStatus(running)`)}catch(o){console.error(`[SubAgentManager] store.updateStatus(running) failed for subId=${t.subId}: ${o instanceof Error?o.message:String(o)}`)}try{if(await t.runtime.start(),t.availableTools=t.runtime.getAvailableTools(),await t.runtime.submit(t.prompt),s)throw new Error(n??"sub-agent turn failed");const o=e.join("");t.status="completed",t.result=o,t.endedAt=Date.now(),t.durationMs=t.endedAt-t.startedAt,this.emitEvent(t.subId,"completed",{result:o}),t.completionResolve?.({output:o}),this.enqueueCompletion(t,o,void 0),this.persistFinalStatus(t,{status:"completed",result:o,endedAt:t.endedAt,durationMs:t.durationMs,availableTools:t.availableTools,contextSnapshot:void 0})}catch(o){const r=o instanceof Error?o.message:String(o);t.status="failed",t.errorMessage=r,t.endedAt=Date.now(),t.durationMs=t.endedAt-t.startedAt,this.emitEvent(t.subId,"failed",{error:r}),t.completionResolve?.({output:"",error:r}),this.enqueueCompletion(t,"",r),this.persistFinalStatus(t,{status:"failed",errorMessage:r,endedAt:t.endedAt,durationMs:t.durationMs,availableTools:t.availableTools,contextSnapshot:void 0})}finally{try{t.runtime.removeListener?.("event",i)}catch{}try{await t.runtime.stop()}catch{}}}async runEntryToCompletionWithRecheck(t,e,s){const n=[];let i=!1,o;const r=a=>{if(a)switch(a.type){case"assistant_delta":typeof a.data?.text=="string"&&n.push(a.data.text);break;case"turn_complete":a.data?.failed&&(i=!0);break;case"error":typeof a.data?.message=="string"&&(o=a.data.message);break}};t.runtime.on("event",r),t.status="running",t.contextSnapshot.currentTool="[starting]",t.contextSnapshot.updatedAt=new Date().toISOString(),this.emitEvent(t.subId,"running",{snapshot:{...t.contextSnapshot}});try{await d(this.store.updateStatus(t.parentAgentId,t.subId,{status:"running"}),b,`sub-agent ${t.subId} store.updateStatus(running)`)}catch(a){console.error(`[SubAgentManager] store.updateStatus(running) failed for subId=${t.subId}: ${a instanceof Error?a.message:String(a)}`)}try{if(await d(t.runtime.start(),E,`sub-agent ${t.subId} runtime.start()`),t.contextSnapshot.currentTool="[submitting]",t.contextSnapshot.updatedAt=new Date().toISOString(),t.availableTools=t.runtime.getAvailableTools(),this.emitEvent(t.subId,"progress",{snapshot:{...t.contextSnapshot}}),await d(t.runtime.submit(t.prompt),A,`sub-agent ${t.subId} runtime.submit() turn=1`),i)throw new Error(o??"sub-agent turn failed");let a=1;for(;a<=s;){let l;try{l=await e(n.join(""),a)}catch(g){console.error(`[SubAgentManager] recheck threw error for subId=${t.subId} turn=${a}, treating as done:`,g instanceof Error?g.message:String(g));break}if(l.done)break;const h=l.continueMessage??"\u7ECF\u68C0\u67E5\uFF0C\u672A\u5B8C\u6210\u5904\u7406\uFF0C\u8BF7\u7EE7\u7EED\u3002";if(i=!1,o=void 0,console.error(`[SubAgentManager] recheck not done for subId=${t.subId} turn=${a}/${s}, injecting continue message (${h.length} chars)`),await d(t.runtime.submit(h),A,`sub-agent ${t.subId} runtime.submit() recheck turn=${a+1}`),i)throw new Error(o??`sub-agent turn ${a+1} failed during recheck continuation`);a++}a>s&&console.error(`[SubAgentManager] recheck reached maxRetries=${s} for subId=${t.subId}, completing with potentially unfinished work`);const u=n.join("");t.status="completed",t.result=u,t.endedAt=Date.now(),t.durationMs=t.endedAt-t.startedAt,this.emitEvent(t.subId,"completed",{result:u}),t.completionResolve?.({output:u}),this.enqueueCompletion(t,u,void 0),this.persistFinalStatus(t,{status:"completed",result:u,endedAt:t.endedAt,durationMs:t.durationMs,availableTools:t.availableTools,contextSnapshot:void 0})}catch(a){const u=a instanceof Error?a.message:String(a);t.status="failed",t.errorMessage=u,t.endedAt=Date.now(),t.durationMs=t.endedAt-t.startedAt,this.emitEvent(t.subId,"failed",{error:u}),t.completionResolve?.({output:"",error:u}),this.enqueueCompletion(t,"",u),this.persistFinalStatus(t,{status:"failed",errorMessage:u,endedAt:t.endedAt,durationMs:t.durationMs,availableTools:t.availableTools,contextSnapshot:void 0})}finally{try{t.runtime.removeListener?.("event",r)}catch{}try{await t.runtime.stop()}catch{}}}async runToCompletion(t){const e=this.subAgents.get(t);if(!e)throw new Error(`sub-agent not found: ${t}`);if(e.status==="running")throw new Error(`sub-agent already running: ${t}`);return e.status!=="pending"&&(e.status="pending"),await this.start(t),await e.completionPromise??{output:"",error:"not started"}}async abort(t){const e=this.subAgents.get(t);if(e&&!(e.status==="completed"||e.status==="failed"||e.status==="cancelled")){e.abortController.abort();try{await e.runtime.abort()}catch{}e.status="cancelled",e.endedAt=Date.now(),e.durationMs=e.endedAt-e.startedAt,this.emitEvent(t,"cancelled",{}),e.completionResolve?.({output:"",error:"aborted"}),this.enqueueCompletion(e,"","aborted"),this.persistFinalStatus(e,{status:"cancelled",endedAt:e.endedAt,durationMs:e.durationMs,availableTools:e.availableTools,contextSnapshot:void 0})}}getSubAgent(t){return this.subAgents.get(t)}listByParent(t){const e=this.parentToSubs.get(t);return e?Array.from(e).map(s=>this.subAgents.get(s)).filter(s=>s!==void 0):[]}listActiveByParent(t){return this.listByParent(t).filter(e=>(e.status==="pending"||e.status==="running")&&!e.silent)}takeCompletedSubAgents(){return this.completionQueue.length===0?[]:this.completionQueue.splice(0)}waitForAnyCompletion(){if(this.completionQueue.length>0){const n=this.completionQueue.shift();return{promise:Promise.resolve(n),cancel:()=>{}}}let t=!1;return{promise:new Promise(n=>{this.completionWaiterResolve=i=>{t||n(i)}}),cancel:()=>{t=!0,this.completionWaiterResolve=null}}}subscribe(t,e){let s=this.subscribers.get(t);return s||(s=new Set,this.subscribers.set(t,s)),s.add(e),()=>{s?.delete(e),s&&s.size===0&&this.subscribers.delete(t)}}async dispose(){this.cleanupTimer&&(clearInterval(this.cleanupTimer),this.cleanupTimer=null);const t=Array.from(this.subAgents.values());await Promise.allSettled(t.map(e=>this.abort(e.subId))),await this.flushPendingPersists(),this.subAgents.clear(),this.parentToSubs.clear(),this.subscribers.clear()}persistFinalStatus(t,e){const s=(async()=>{let n;for(let i=0;i<=c.length;i++)try{await this.store.updateStatus(t.parentAgentId,t.subId,e);return}catch(o){n=o,i<c.length&&await new Promise(r=>setTimeout(r,c[i]))}console.error(`[SubAgentManager] persistFinalStatus(${e.status}) failed after ${c.length+1} attempts for subId=${t.subId}: ${n instanceof Error?n.message:String(n)}`)})();return this.pendingPersists.add(s),s.finally(()=>this.pendingPersists.delete(s)),s}async flushPendingPersists(){this.pendingPersists.size!==0&&await Promise.allSettled(Array.from(this.pendingPersists))}enqueueCompletion(t,e,s){if(t.silent||t.awaited)return;const n={subId:t.subId,subagentType:t.subagentType,description:t.description,status:t.status,output:e,error:s,durationMs:t.durationMs};if(this.completionQueue.push(n),this.completionWaiterResolve){const i=this.completionWaiterResolve;this.completionWaiterResolve=null;const o=this.completionQueue.pop();i(o??n)}}countByStatus(t,...e){return this.listByParent(t).filter(s=>e.includes(s.status)).length}addToParentMap(t,e){let s=this.parentToSubs.get(t);s||(s=new Set,this.parentToSubs.set(t,s)),s.add(e)}removeFromParentMap(t,e){const s=this.parentToSubs.get(t);s&&(s.delete(e),s.size===0&&this.parentToSubs.delete(t))}cleanupCompletedEntries(){const t=Date.now();for(const[e,s]of this.subAgents)(s.status==="completed"||s.status==="failed"||s.status==="cancelled")&&s.endedAt&&t-s.endedAt>T&&(this.subAgents.delete(e),this.removeFromParentMap(s.parentAgentId,e))}recoverZombieEntries(){const t=Date.now();for(const[e,s]of this.subAgents)s.status==="pending"&&t-s.startedAt>m?this.recoverZombie(s,`stuck in pending >${m}ms (never started)`):s.status==="running"&&t-s.startedAt>f&&this.recoverZombie(s,`stuck in running >${f}ms (no completion)`)}async recoverZombie(t,e){if(t.status!=="pending"&&t.status!=="running")return;const s=`zombie recovered: ${e}`;t.status="failed",t.errorMessage=s,t.endedAt=Date.now(),t.durationMs=t.endedAt-t.startedAt,this.emitEvent(t.subId,"failed",{error:s}),t.completionResolve?.({output:"",error:s}),this.enqueueCompletion(t,"",s),this.persistFinalStatus(t,{status:"failed",errorMessage:s,endedAt:t.endedAt,durationMs:t.durationMs,availableTools:t.availableTools,contextSnapshot:void 0});try{await t.runtime.stop()}catch{}}async findRecordInStore(t){for(const e of this.parentToSubs.keys()){const n=(await this.store.read(e)).subAgents.find(i=>i.subId===t);if(n)return n}}handleRuntimeEvent(t,e){const s=this.subAgents.get(t);if(!s)return;const n=s.contextSnapshot;switch(n.updatedAt=new Date().toISOString(),e?.type){case"session_started":n.currentTool="[starting]",this.emitEvent(t,"progress",{snapshot:{...n}});break;case"startup_phase":n.currentTool=`[startup:${e.data?.phase??"unknown"}]`,this.emitEvent(t,"progress",{snapshot:{...n}});break;case"mcp_status":e.data?.action==="call_tool"?(n.currentTool=e.data?.tool,this.emitEvent(t,"tool_start",{tool:n.currentTool,snapshot:{...n}})):e.data?.action==="tool_result"?(this.emitEvent(t,"tool_end",{tool:n.currentTool,snapshot:{...n}}),n.currentTool=void 0):(n.currentTool="[mcp_init]",this.emitEvent(t,"progress",{snapshot:{...n}}));break;case"skill_status":n.currentTool="[skill_loaded]",this.emitEvent(t,"progress",{snapshot:{...n}});break;case"ai_request":n.currentTool="[model_request]",this.emitEvent(t,"progress",{snapshot:{...n}});break;case"iteration_usage":(e.data?.inputTokens!=null||e.data?.outputTokens!=null)&&(n.tokenUsage.input=e.data.inputTokens??n.tokenUsage.input,n.tokenUsage.output=e.data.outputTokens??n.tokenUsage.output,this.emitEvent(t,"progress",{snapshot:{...n}}));break;case"context_compaction":e.data?.action==="start"?(n.currentTool="[context_compaction]",this.emitEvent(t,"progress",{snapshot:{...n}})):e.data?.action==="end"&&n.currentTool==="[context_compaction]"&&(n.currentTool=void 0,this.emitEvent(t,"progress",{snapshot:{...n}}));break;case"turn_complete":e.data?.usage?(n.tokenUsage.input=e.data.usage.inputTokens??n.tokenUsage.input,n.tokenUsage.output=e.data.usage.outputTokens??n.tokenUsage.output,this.emitEvent(t,"progress",{snapshot:{...n}})):(e.data?.failed||e.data?.aborted)&&(n.tokenUsage.output=0);break;case"assistant_delta":n.lastAssistantText=((n.lastAssistantText??"")+(e.data?.text??"")).slice(-500),n.messageCount+=1,this.emitEvent(t,"delta",{text:e.data?.text});break;case"session_complete":n.messageCount+=1;break}}emitEvent(t,e,s){const n={type:e,subId:t,timestamp:new Date().toISOString(),data:s},i=this.subscribers.get(t);if(i)for(const r of i)try{r(n)}catch{}const o=this.subscribers.get("*");if(o)for(const r of o)try{r(n)}catch{}if(e==="tool_start"||e==="tool_end"){const r=this.subAgents.get(t);r?(console.error(`[SubAgentManager] appendEvent: subId=${t} type=${e} tool=${s.tool??"?"} parentAgentId=${r.parentAgentId}`),this.store.appendEvent(r.parentAgentId,t,n).catch(a=>{console.error(`[SubAgentManager] appendEvent FAILED: subId=${t} error=${a instanceof Error?a.message:String(a)}`)})):console.error(`[SubAgentManager] appendEvent SKIPPED (entry not found): subId=${t} type=${e}`)}}toRecord(t){return{subId:t.subId,parentAgentId:t.parentAgentId,parentSessionId:t.parentSessionId,subagentType:t.subagentType,description:t.description,prompt:t.prompt,status:t.status,result:t.result,errorMessage:t.errorMessage,startedAt:t.startedAt,endedAt:t.endedAt,durationMs:t.durationMs,contextSnapshot:t.status==="running"?t.contextSnapshot:void 0,availableTools:t.availableTools,allocatedTools:t.allocatedTools}}getContextSnapshot(t){return this.subAgents.get(t)?.contextSnapshot}}async function d(p,t,e){if(t<=0)return await p;let s;try{return await new Promise((n,i)=>{s=setTimeout(()=>i(new Error(`${e} timed out after ${t}ms`)),t),p.then(n,i)})}finally{s&&clearTimeout(s)}}export{k as SubAgentManager};
1
+ import{randomUUID as S}from"node:crypto";import{ACodeRuntime as w}from"./runtime.js";const T=30*60*1e3,m=2*60*1e3,f=12*60*1e3,b=5e3,c=[100,500,2e3,8e3],E=6e4,A=10*60*1e3;class k{constructor(t){this.subAgents=new Map,this.parentToSubs=new Map,this.subscribers=new Map,this.cleanupTimer=null,this.completionQueue=[],this.completionWaiterResolve=null,this.pendingPersists=new Set,this.store=t.store,this.maxConcurrent=t.maxConcurrent??5,this.cleanupTimer=setInterval(()=>{this.cleanupCompletedEntries(),this.recoverZombieEntries()},5*60*1e3),this.cleanupTimer.unref&&this.cleanupTimer.unref()}async spawn(t){if(this.countByStatus(t.parentAgentId,"running","pending")>=this.maxConcurrent)throw new Error(`concurrent sub-agent limit reached (${this.maxConcurrent}) for agent ${t.parentAgentId}`);const s=`sub-${S()}`,n=Date.now(),i=new AbortController,o={...t.parentConfig,sessionId:s,workingDirectory:t.workingDirectory,agentId:`${t.parentAgentId}__sub__${s}`,initialPrompt:void 0,subAgentManager:void 0,subAgentAllowedTools:t.allowedTools&&t.allowedTools.length>0?t.allowedTools:void 0,...t.parentConfig.subAgentModel?{model:t.parentConfig.subAgentModel}:{},...t.parentConfig.subAgentEffort?{effort:t.parentConfig.subAgentEffort}:{},subAgentModel:void 0,subAgentEffort:void 0,pluginBridge:void 0,runtimeResourcesProvider:void 0},r=new w(o),a={subId:s,parentAgentId:t.parentAgentId,parentSessionId:t.parentSessionId,subagentType:t.subagentType,description:t.description,prompt:t.prompt,status:"pending",startedAt:n,runtime:r,abortController:i,silent:t.silent,contextSnapshot:{tokenUsage:{input:0,output:0},messageCount:0,updatedAt:new Date().toISOString()},availableTools:[],...t.allowedTools&&t.allowedTools.length>0?{allocatedTools:t.allowedTools}:{}};this.subAgents.set(s,a),this.addToParentMap(t.parentAgentId,s);const u=this.toRecord(a);return await this.store.upsert(t.parentAgentId,u),r.on("event",l=>{this.handleRuntimeEvent(s,l)}),this.emitEvent(s,"spawned",{}),s}async start(t){const e=this.subAgents.get(t);if(!e)throw new Error(`sub-agent not found: ${t}`);if(e.status!=="pending")throw new Error(`sub-agent ${t} cannot start from status: ${e.status}`);e.completionPromise=new Promise((s,n)=>{e.completionResolve=s,e.completionReject=n}),this.runEntryToCompletion(e).catch(()=>{})}async startWithRecheck(t,e,s=3){const n=this.subAgents.get(t);if(!n)throw new Error(`sub-agent not found: ${t}`);if(n.status!=="pending")throw new Error(`sub-agent ${t} cannot start from status: ${n.status}`);n.completionPromise=new Promise((i,o)=>{n.completionResolve=i,n.completionReject=o}),this.runEntryToCompletionWithRecheck(n,e,s).catch(()=>{})}async awaitCompletion(t,e=0){if(t.length===0)return[];const s=[],n=t.map(async o=>{const r=this.subAgents.get(o);if(!r){const u=await this.findRecordInStore(o);u?s.push({subId:o,output:u.result??"",error:u.errorMessage,status:u.status}):s.push({subId:o,output:"",error:`sub-agent not found: ${o}`,status:"failed"});return}r.awaited=!0,r.status==="pending"&&await this.start(o);const a=r.completionPromise??Promise.resolve({output:"",error:"not started"});try{const u=await a;s.push({subId:o,output:u.output,error:u.error,status:r.status})}catch(u){s.push({subId:o,output:"",error:u instanceof Error?u.message:String(u),status:r.status})}}),i=new Set(t);for(let o=this.completionQueue.length-1;o>=0;o--)i.has(this.completionQueue[o].subId)&&this.completionQueue.splice(o,1);return e>0?await Promise.race([Promise.allSettled(n),new Promise(o=>setTimeout(()=>o(),e))]):await Promise.allSettled(n),s}async runEntryToCompletion(t){const e=[];let s=!1,n;const i=o=>{if(o)switch(o.type){case"assistant_delta":typeof o.data?.text=="string"&&e.push(o.data.text);break;case"turn_complete":o.data?.failed&&(s=!0);break;case"error":typeof o.data?.message=="string"&&(n=o.data.message);break}};t.runtime.on("event",i),t.status="running",t.contextSnapshot.currentTool="[starting]",t.contextSnapshot.updatedAt=new Date().toISOString(),this.emitEvent(t.subId,"running",{snapshot:{...t.contextSnapshot}});try{await d(this.store.updateStatus(t.parentAgentId,t.subId,{status:"running"}),b,`sub-agent ${t.subId} store.updateStatus(running)`)}catch(o){console.error(`[SubAgentManager] store.updateStatus(running) failed for subId=${t.subId}: ${o instanceof Error?o.message:String(o)}`)}try{if(await t.runtime.start(),t.availableTools=t.runtime.getAvailableTools(),await t.runtime.submit(t.prompt),s)throw new Error(n??"sub-agent turn failed");const o=e.join("");t.status="completed",t.result=o,t.endedAt=Date.now(),t.durationMs=t.endedAt-t.startedAt,this.emitEvent(t.subId,"completed",{result:o}),t.completionResolve?.({output:o}),this.enqueueCompletion(t,o,void 0),this.persistFinalStatus(t,{status:"completed",result:o,endedAt:t.endedAt,durationMs:t.durationMs,availableTools:t.availableTools,contextSnapshot:void 0})}catch(o){const r=o instanceof Error?o.message:String(o);t.status="failed",t.errorMessage=r,t.endedAt=Date.now(),t.durationMs=t.endedAt-t.startedAt,this.emitEvent(t.subId,"failed",{error:r}),t.completionResolve?.({output:"",error:r}),this.enqueueCompletion(t,"",r),this.persistFinalStatus(t,{status:"failed",errorMessage:r,endedAt:t.endedAt,durationMs:t.durationMs,availableTools:t.availableTools,contextSnapshot:void 0})}finally{try{t.runtime.removeListener?.("event",i)}catch{}try{await t.runtime.stop()}catch{}}}async runEntryToCompletionWithRecheck(t,e,s){const n=[];let i=!1,o;const r=a=>{if(a)switch(a.type){case"assistant_delta":typeof a.data?.text=="string"&&n.push(a.data.text);break;case"turn_complete":a.data?.failed&&(i=!0);break;case"error":typeof a.data?.message=="string"&&(o=a.data.message);break}};t.runtime.on("event",r),t.status="running",t.contextSnapshot.currentTool="[starting]",t.contextSnapshot.updatedAt=new Date().toISOString(),this.emitEvent(t.subId,"running",{snapshot:{...t.contextSnapshot}});try{await d(this.store.updateStatus(t.parentAgentId,t.subId,{status:"running"}),b,`sub-agent ${t.subId} store.updateStatus(running)`)}catch(a){console.error(`[SubAgentManager] store.updateStatus(running) failed for subId=${t.subId}: ${a instanceof Error?a.message:String(a)}`)}try{if(await d(t.runtime.start(),E,`sub-agent ${t.subId} runtime.start()`),t.contextSnapshot.currentTool="[submitting]",t.contextSnapshot.updatedAt=new Date().toISOString(),t.availableTools=t.runtime.getAvailableTools(),this.emitEvent(t.subId,"progress",{snapshot:{...t.contextSnapshot}}),await d(t.runtime.submit(t.prompt),A,`sub-agent ${t.subId} runtime.submit() turn=1`),i)throw new Error(o??"sub-agent turn failed");let a=1;for(;a<=s;){let l;try{l=await e(n.join(""),a)}catch(g){console.error(`[SubAgentManager] recheck threw error for subId=${t.subId} turn=${a}, treating as done:`,g instanceof Error?g.message:String(g));break}if(l.done)break;const h=l.continueMessage??"\u7ECF\u68C0\u67E5\uFF0C\u672A\u5B8C\u6210\u5904\u7406\uFF0C\u8BF7\u7EE7\u7EED\u3002";if(i=!1,o=void 0,console.error(`[SubAgentManager] recheck not done for subId=${t.subId} turn=${a}/${s}, injecting continue message (${h.length} chars)`),await d(t.runtime.submit(h),A,`sub-agent ${t.subId} runtime.submit() recheck turn=${a+1}`),i)throw new Error(o??`sub-agent turn ${a+1} failed during recheck continuation`);a++}a>s&&console.error(`[SubAgentManager] recheck reached maxRetries=${s} for subId=${t.subId}, completing with potentially unfinished work`);const u=n.join("");t.status="completed",t.result=u,t.endedAt=Date.now(),t.durationMs=t.endedAt-t.startedAt,this.emitEvent(t.subId,"completed",{result:u}),t.completionResolve?.({output:u}),this.enqueueCompletion(t,u,void 0),this.persistFinalStatus(t,{status:"completed",result:u,endedAt:t.endedAt,durationMs:t.durationMs,availableTools:t.availableTools,contextSnapshot:void 0})}catch(a){const u=a instanceof Error?a.message:String(a);t.status="failed",t.errorMessage=u,t.endedAt=Date.now(),t.durationMs=t.endedAt-t.startedAt,this.emitEvent(t.subId,"failed",{error:u}),t.completionResolve?.({output:"",error:u}),this.enqueueCompletion(t,"",u),this.persistFinalStatus(t,{status:"failed",errorMessage:u,endedAt:t.endedAt,durationMs:t.durationMs,availableTools:t.availableTools,contextSnapshot:void 0})}finally{try{t.runtime.removeListener?.("event",r)}catch{}try{await t.runtime.stop()}catch{}}}async runToCompletion(t){const e=this.subAgents.get(t);if(!e)throw new Error(`sub-agent not found: ${t}`);if(e.status==="running")throw new Error(`sub-agent already running: ${t}`);return e.status!=="pending"&&(e.status="pending"),await this.start(t),await e.completionPromise??{output:"",error:"not started"}}async abort(t){const e=this.subAgents.get(t);if(e&&!(e.status==="completed"||e.status==="failed"||e.status==="cancelled")){e.abortController.abort();try{await e.runtime.abort()}catch{}e.status="cancelled",e.endedAt=Date.now(),e.durationMs=e.endedAt-e.startedAt,this.emitEvent(t,"cancelled",{}),e.completionResolve?.({output:"",error:"aborted"}),this.enqueueCompletion(e,"","aborted"),this.persistFinalStatus(e,{status:"cancelled",endedAt:e.endedAt,durationMs:e.durationMs,availableTools:e.availableTools,contextSnapshot:void 0})}}getSubAgent(t){return this.subAgents.get(t)}listByParent(t){const e=this.parentToSubs.get(t);return e?Array.from(e).map(s=>this.subAgents.get(s)).filter(s=>s!==void 0):[]}listActiveByParent(t){return this.listByParent(t).filter(e=>(e.status==="pending"||e.status==="running")&&!e.silent)}takeCompletedSubAgents(){return this.completionQueue.length===0?[]:this.completionQueue.splice(0)}waitForAnyCompletion(){if(this.completionQueue.length>0){const n=this.completionQueue.shift();return{promise:Promise.resolve(n),cancel:()=>{}}}let t=!1;return{promise:new Promise(n=>{this.completionWaiterResolve=i=>{t||n(i)}}),cancel:()=>{t=!0,this.completionWaiterResolve=null}}}subscribe(t,e){let s=this.subscribers.get(t);return s||(s=new Set,this.subscribers.set(t,s)),s.add(e),()=>{s?.delete(e),s&&s.size===0&&this.subscribers.delete(t)}}async dispose(){this.cleanupTimer&&(clearInterval(this.cleanupTimer),this.cleanupTimer=null);const t=Array.from(this.subAgents.values());await Promise.allSettled(t.map(e=>this.abort(e.subId))),await this.flushPendingPersists(),this.subAgents.clear(),this.parentToSubs.clear(),this.subscribers.clear()}persistFinalStatus(t,e){const s=(async()=>{let n;for(let i=0;i<=c.length;i++)try{await this.store.updateStatus(t.parentAgentId,t.subId,e);return}catch(o){n=o,i<c.length&&await new Promise(r=>setTimeout(r,c[i]))}console.error(`[SubAgentManager] persistFinalStatus(${e.status}) failed after ${c.length+1} attempts for subId=${t.subId}: ${n instanceof Error?n.message:String(n)}`)})();return this.pendingPersists.add(s),s.finally(()=>this.pendingPersists.delete(s)),s}async flushPendingPersists(){this.pendingPersists.size!==0&&await Promise.allSettled(Array.from(this.pendingPersists))}enqueueCompletion(t,e,s){if(t.silent||t.awaited)return;const n={subId:t.subId,subagentType:t.subagentType,description:t.description,status:t.status,output:e,error:s,durationMs:t.durationMs};if(this.completionQueue.push(n),this.completionWaiterResolve){const i=this.completionWaiterResolve;this.completionWaiterResolve=null;const o=this.completionQueue.pop();i(o??n)}}countByStatus(t,...e){return this.listByParent(t).filter(s=>e.includes(s.status)).length}addToParentMap(t,e){let s=this.parentToSubs.get(t);s||(s=new Set,this.parentToSubs.set(t,s)),s.add(e)}removeFromParentMap(t,e){const s=this.parentToSubs.get(t);s&&(s.delete(e),s.size===0&&this.parentToSubs.delete(t))}cleanupCompletedEntries(){const t=Date.now();for(const[e,s]of this.subAgents)(s.status==="completed"||s.status==="failed"||s.status==="cancelled")&&s.endedAt&&t-s.endedAt>T&&(this.subAgents.delete(e),this.removeFromParentMap(s.parentAgentId,e))}recoverZombieEntries(){const t=Date.now();for(const[e,s]of this.subAgents)s.status==="pending"&&t-s.startedAt>m?this.recoverZombie(s,`stuck in pending >${m}ms (never started)`):s.status==="running"&&t-s.startedAt>f&&this.recoverZombie(s,`stuck in running >${f}ms (no completion)`)}async recoverZombie(t,e){if(t.status!=="pending"&&t.status!=="running")return;const s=`zombie recovered: ${e}`;t.status="failed",t.errorMessage=s,t.endedAt=Date.now(),t.durationMs=t.endedAt-t.startedAt,this.emitEvent(t.subId,"failed",{error:s}),t.completionResolve?.({output:"",error:s}),this.enqueueCompletion(t,"",s),this.persistFinalStatus(t,{status:"failed",errorMessage:s,endedAt:t.endedAt,durationMs:t.durationMs,availableTools:t.availableTools,contextSnapshot:void 0});try{await t.runtime.stop()}catch{}}async findRecordInStore(t){for(const e of this.parentToSubs.keys()){const n=(await this.store.read(e)).subAgents.find(i=>i.subId===t);if(n)return n}}handleRuntimeEvent(t,e){const s=this.subAgents.get(t);if(!s)return;const n=s.contextSnapshot;switch(n.updatedAt=new Date().toISOString(),e?.type){case"session_started":n.currentTool="[starting]",this.emitEvent(t,"progress",{snapshot:{...n}});break;case"startup_phase":n.currentTool=`[startup:${e.data?.phase??"unknown"}]`,this.emitEvent(t,"progress",{snapshot:{...n}});break;case"mcp_status":e.data?.action==="call_tool"?(n.currentTool=e.data?.tool,this.emitEvent(t,"tool_start",{tool:n.currentTool,snapshot:{...n}})):e.data?.action==="tool_result"?(this.emitEvent(t,"tool_end",{tool:n.currentTool,snapshot:{...n}}),n.currentTool=void 0):(n.currentTool="[mcp_init]",this.emitEvent(t,"progress",{snapshot:{...n}}));break;case"skill_status":n.currentTool="[skill_loaded]",this.emitEvent(t,"progress",{snapshot:{...n}});break;case"ai_request":n.currentTool="[model_request]",this.emitEvent(t,"progress",{snapshot:{...n}});break;case"iteration_usage":(e.data?.inputTokens!=null||e.data?.outputTokens!=null)&&(n.tokenUsage.input=e.data.inputTokens??n.tokenUsage.input,n.tokenUsage.output=e.data.outputTokens??n.tokenUsage.output,this.emitEvent(t,"progress",{snapshot:{...n}}));break;case"context_compaction":e.data?.action==="start"?(n.currentTool="[context_compaction]",this.emitEvent(t,"progress",{snapshot:{...n}})):e.data?.action==="end"&&n.currentTool==="[context_compaction]"&&(n.currentTool=void 0,this.emitEvent(t,"progress",{snapshot:{...n}}));break;case"turn_complete":e.data?.usage?(n.tokenUsage.input=e.data.usage.inputTokens??n.tokenUsage.input,n.tokenUsage.output=e.data.usage.outputTokens??n.tokenUsage.output,this.emitEvent(t,"progress",{snapshot:{...n}})):(e.data?.failed||e.data?.aborted)&&(n.tokenUsage.output=0);break;case"assistant_delta":n.lastAssistantText=((n.lastAssistantText??"")+(e.data?.text??"")).slice(-500),n.messageCount+=1,this.emitEvent(t,"delta",{text:e.data?.text});break;case"session_complete":n.messageCount+=1;break}}emitEvent(t,e,s){const n={type:e,subId:t,timestamp:new Date().toISOString(),data:s},i=this.subscribers.get(t);if(i)for(const r of i)try{r(n)}catch{}const o=this.subscribers.get("*");if(o)for(const r of o)try{r(n)}catch{}if(e==="tool_start"||e==="tool_end"){const r=this.subAgents.get(t);r?(console.error(`[SubAgentManager] appendEvent: subId=${t} type=${e} tool=${s.tool??"?"} parentAgentId=${r.parentAgentId}`),this.store.appendEvent(r.parentAgentId,t,n).catch(a=>{console.error(`[SubAgentManager] appendEvent FAILED: subId=${t} error=${a instanceof Error?a.message:String(a)}`)})):console.error(`[SubAgentManager] appendEvent SKIPPED (entry not found): subId=${t} type=${e}`)}}toRecord(t){return{subId:t.subId,parentAgentId:t.parentAgentId,parentSessionId:t.parentSessionId,subagentType:t.subagentType,description:t.description,prompt:t.prompt,status:t.status,result:t.result,errorMessage:t.errorMessage,startedAt:t.startedAt,endedAt:t.endedAt,durationMs:t.durationMs,contextSnapshot:t.status==="running"?t.contextSnapshot:void 0,availableTools:t.availableTools,allocatedTools:t.allocatedTools}}getContextSnapshot(t){return this.subAgents.get(t)?.contextSnapshot}}async function d(p,t,e){if(t<=0)return await p;let s;try{return await new Promise((n,i)=>{s=setTimeout(()=>i(new Error(`${e} timed out after ${t}ms`)),t),p.then(n,i)})}finally{s&&clearTimeout(s)}}export{k as SubAgentManager};
2
2
 
@@ -1,2 +1,2 @@
1
- const i="default",p=new Set(["sub_agent","list_sub_agents","get_sub_agent_status","abort_sub_agent","list_sub_agent_tools"]),_=new Set(["poll_message","get_message","send_group","send_private","create_task_instance_comment","submit_task_result","start_task_rollback","finish_task_rollback","reject_task","terminate_task","hire_colleague","abandon_memory_update"]);function m(e){return e.kind==="mcp"&&_.has(e.toolName)}function k(e,n){if(n.length===0)return[...e];const r=new Set(e.map(t=>t.exposedName)),o=[...e];for(const t of n)r.has(t.exposedName)||(r.add(t.exposedName),o.push(t));return o}function d(e){return e.kind==="mcp"?e.serverName||"mcp":e.category||i}function T(e,n){return!n||e.length===0?[...e]:e.map(r=>{if(r.kind!=="builtin")return r;const t=r.execute;return typeof t!="function"?r:{...r,execute:(s,c)=>{const a=s&&typeof s=="object"&&s.agentId==null?{...s,agentId:n}:s;return t(a,c)}}})}function h(e){if(e.kind==="mcp"){const t=e.serverName||"mcp",s=[`${t}.${e.toolName}`];return e.exposedName&&e.exposedName!==e.toolName&&s.push(`${t}.${e.exposedName}`),s}const n=e.category||i,r=[`${n}.${e.exposedName}`],o=`${n}_`;return n!==i&&e.exposedName.startsWith(o)&&r.push(`${n}.${e.exposedName.slice(o.length)}`),r}function f(e){let n=e.trim();for(;n.length>0&&(n.endsWith("*")||n.endsWith("."));)n=n.slice(0,-1).trimEnd();return n}function w(e,n){if(m(e))return!1;const r=n.map(t=>typeof t=="string"?f(t):"").filter(t=>t.length>0);if(r.length===0)return!1;const o=h(e);return r.some(t=>o.some(s=>s===t||s.startsWith(`${t}.`)))}function b(e){const n=[],r=new Map;for(const o of e){if(p.has(o.exposedName)||m(o))continue;const t=d(o);let s=r.get(t);s||(s={kind:o.kind,names:[],seen:new Set},r.set(t,s),n.push(t));const c=x(o);s.seen.has(c)||(s.seen.add(c),s.names.push(c))}return n.sort((o,t)=>o===i?-1:t===i?1:o<t?-1:o>t?1:0).map(o=>{const t=r.get(o);return{category:o,kind:t.kind,tools:t.names}})}function x(e){if(e.kind==="mcp")return e.toolName;const n=e.category||i,r=`${n}_`;return n!==i&&e.exposedName.startsWith(r)?e.exposedName.slice(r.length):e.exposedName}const g=new Set(["write_file","edit_file","delete_file"]),y=new Set(["create_memory","read_memory","update_memory","delete_memory","search_memory","list_memories","get_memory_stats","list_memories_by_file","memory_recurrence","memory_recurrence_complete"]),E="explore",N="core",O="custom";class l extends Error{}function A(e,n){if(e==="core")return[i];const r=[],o=n.find(t=>t.category===i);if(o)for(const t of o.tools)g.has(t)||r.push(`${i}.${t}`);for(const t of n)if(t.kind==="mcp")for(const s of t.tools)y.has(s)&&r.push(`${t.category}.${s}`);return r}function $(e,n,r){for(const o of r){if(o.category===n)return;for(const t of o.tools){const s=`${o.category}.${t}`;if(s===n||s.startsWith(`${n}.`))return}}throw e.startsWith("@")?new l(`Unknown tool preset '${e}'. Presets are now specified via the 'subagent_type' parameter ('${E}', '${N}', or 'custom'); '@explore'/'@core' are no longer valid in 'tools'.`):new l(`Unknown tool allocation '${e}'. Allocatable categories: ${r.map(o=>o.category).join(", ")}. Call list_sub_agent_tools to see all allocatable categories and tool paths.`)}function S(e,n,r){if(e==="custom"&&n.length===0)throw new l("'tools' parameter is required when subagent_type is 'custom'. Call list_sub_agent_tools to see all allocatable categories and tool paths.");if(e==="explore"||e==="core")return{patterns:A(e,r),label:e};const o=n.map(a=>typeof a=="string"?a.trim():"").filter(a=>a.length>0),t=[];for(const a of o){const u=f(a);$(a,u,r),t.push(u)}const s=new Set,c=[];for(const a of t)a.length===0||s.has(a)||(s.add(a),c.push(a));return{patterns:c,label:e}}export{_ as AGENT_IDENTITY_MCP_RESTRICTED_TOOLS,i as DEFAULT_TOOL_CATEGORY,g as EXPLORE_READONLY_DENIED_TOOLS,N as PRESET_CORE,E as PRESET_EXPLORE,y as SUB_AGENT_ALLOWED_MCP_TOOLS,p as SUB_AGENT_MANAGEMENT_TOOL_NAMES,O as TYPE_LABEL_CUSTOM,l as ToolAllocationError,b as buildToolCatalog,A as expandPreset,m as isAgentIdentityRestrictedTool,w as matchesToolAllocation,k as mergeAllocatableTools,f as normalizeAllocationPattern,T as rebindDefaultAgentId,S as resolveToolAllocation,h as toolAllocationAliases,d as toolAllocationCategory};
1
+ const i="default",p=new Set(["sub_agent","list_sub_agents","get_sub_agent_status","abort_sub_agent","list_sub_agent_tools"]),_=new Set(["poll_message","get_message","send_group","send_private","create_task_instance_comment","submit_task_result","start_task_rollback","finish_task_rollback","hire_colleague","abandon_memory_update"]);function m(e){return e.kind==="mcp"&&_.has(e.toolName)}function T(e,n){if(n.length===0)return[...e];const r=new Set(e.map(t=>t.exposedName)),o=[...e];for(const t of n)r.has(t.exposedName)||(r.add(t.exposedName),o.push(t));return o}function d(e){return e.kind==="mcp"?e.serverName||"mcp":e.category||i}function w(e,n){return!n||e.length===0?[...e]:e.map(r=>{if(r.kind!=="builtin")return r;const t=r.execute;return typeof t!="function"?r:{...r,execute:(s,c)=>{const a=s&&typeof s=="object"&&s.agentId==null?{...s,agentId:n}:s;return t(a,c)}}})}function h(e){if(e.kind==="mcp"){const t=e.serverName||"mcp",s=[`${t}.${e.toolName}`];return e.exposedName&&e.exposedName!==e.toolName&&s.push(`${t}.${e.exposedName}`),s}const n=e.category||i,r=[`${n}.${e.exposedName}`],o=`${n}_`;return n!==i&&e.exposedName.startsWith(o)&&r.push(`${n}.${e.exposedName.slice(o.length)}`),r}function f(e){let n=e.trim();for(;n.length>0&&(n.endsWith("*")||n.endsWith("."));)n=n.slice(0,-1).trimEnd();return n}function b(e,n){if(m(e))return!1;const r=n.map(t=>typeof t=="string"?f(t):"").filter(t=>t.length>0);if(r.length===0)return!1;const o=h(e);return r.some(t=>o.some(s=>s===t||s.startsWith(`${t}.`)))}function k(e){const n=[],r=new Map;for(const o of e){if(p.has(o.exposedName)||m(o))continue;const t=d(o);let s=r.get(t);s||(s={kind:o.kind,names:[],seen:new Set},r.set(t,s),n.push(t));const c=x(o);s.seen.has(c)||(s.seen.add(c),s.names.push(c))}return n.sort((o,t)=>o===i?-1:t===i?1:o<t?-1:o>t?1:0).map(o=>{const t=r.get(o);return{category:o,kind:t.kind,tools:t.names}})}function x(e){if(e.kind==="mcp")return e.toolName;const n=e.category||i,r=`${n}_`;return n!==i&&e.exposedName.startsWith(r)?e.exposedName.slice(r.length):e.exposedName}const g=new Set(["write_file","edit_file","delete_file"]),y=new Set(["create_memory","read_memory","update_memory","delete_memory","search_memory","list_memories","get_memory_stats","list_memories_by_file","memory_recurrence","memory_recurrence_complete"]),E="explore",N="core",O="custom";class l extends Error{}function A(e,n){if(e==="core")return[i];const r=[],o=n.find(t=>t.category===i);if(o)for(const t of o.tools)g.has(t)||r.push(`${i}.${t}`);for(const t of n)if(t.kind==="mcp")for(const s of t.tools)y.has(s)&&r.push(`${t.category}.${s}`);return r}function $(e,n,r){for(const o of r){if(o.category===n)return;for(const t of o.tools){const s=`${o.category}.${t}`;if(s===n||s.startsWith(`${n}.`))return}}throw e.startsWith("@")?new l(`Unknown tool preset '${e}'. Presets are now specified via the 'subagent_type' parameter ('${E}', '${N}', or 'custom'); '@explore'/'@core' are no longer valid in 'tools'.`):new l(`Unknown tool allocation '${e}'. Allocatable categories: ${r.map(o=>o.category).join(", ")}. Call list_sub_agent_tools to see all allocatable categories and tool paths.`)}function S(e,n,r){if(e==="custom"&&n.length===0)throw new l("'tools' parameter is required when subagent_type is 'custom'. Call list_sub_agent_tools to see all allocatable categories and tool paths.");if(e==="explore"||e==="core")return{patterns:A(e,r),label:e};const o=n.map(a=>typeof a=="string"?a.trim():"").filter(a=>a.length>0),t=[];for(const a of o){const u=f(a);$(a,u,r),t.push(u)}const s=new Set,c=[];for(const a of t)a.length===0||s.has(a)||(s.add(a),c.push(a));return{patterns:c,label:e}}export{_ as AGENT_IDENTITY_MCP_RESTRICTED_TOOLS,i as DEFAULT_TOOL_CATEGORY,g as EXPLORE_READONLY_DENIED_TOOLS,N as PRESET_CORE,E as PRESET_EXPLORE,y as SUB_AGENT_ALLOWED_MCP_TOOLS,p as SUB_AGENT_MANAGEMENT_TOOL_NAMES,O as TYPE_LABEL_CUSTOM,l as ToolAllocationError,k as buildToolCatalog,A as expandPreset,m as isAgentIdentityRestrictedTool,b as matchesToolAllocation,T as mergeAllocatableTools,f as normalizeAllocationPattern,w as rebindDefaultAgentId,S as resolveToolAllocation,h as toolAllocationAliases,d as toolAllocationCategory};
2
2
 
@@ -13,11 +13,19 @@ export interface ToolGroupRegistration {
13
13
  collapsible: boolean;
14
14
 
15
15
  toolNames?: readonly string[];
16
+
17
+ serverName?: string;
16
18
  }
17
19
  export interface ToolGroupManagerOptions {
18
20
 
19
21
  stateOf: (key: string) => CapabilityState | undefined;
20
22
  }
23
+
24
+ export declare const MCP_GROUP_KEY_PREFIX = "mcp:";
25
+
26
+ export declare function mcpGroupKeyOf(serverName: string): string;
27
+
28
+ export declare function isMcpGroupKey(key: string): boolean;
21
29
  export declare class ToolGroupManager {
22
30
  private groups;
23
31
  private expandedGroups;
@@ -44,8 +52,12 @@ export declare class ToolGroupManager {
44
52
 
45
53
  getGroupForExposedName(exposedName: string): string | undefined;
46
54
 
55
+ findGroupByServerName(serverName: string): string | undefined;
56
+
47
57
  shouldShowToLLMByName(exposedName: string): boolean;
48
58
 
59
+ claimedToolNamesBySubGroups(): Set<string>;
60
+
49
61
  listToolManifests(key: string, tools: ReadonlyArray<{
50
62
  exposedName: string;
51
63
  description?: string;
@@ -1,14 +1,18 @@
1
- class b{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){if(e==="all"){let s=0;for(const n of this.groups.keys())this.expandedGroups.has(n)||(this.expandedGroups.add(n),s++);return s}return this.groups.has(e)?this.expandedGroups.has(e)?0:(this.expandedGroups.add(e),1):-1}collapse(e){if(e==="all"){const s=this.expandedGroups.size;return this.expandedGroups.clear(),s}return this.expandedGroups.delete(e)?1:0}resetExpanded(){this.expandedGroups.clear()}shouldShowToLLM(e){if(!e)return!0;const s=this.groups.get(e);if(!s)return!0;const n=this.getConfigState(e);return!(n==="disabled"||n==="collapsed"&&s.collapsible)}getGroupForExposedName(e){for(const[n,a]of this.groups){if(a.toolNames&&a.toolNames.length>0){for(const r of a.toolNames)if(e===r)return n}if(e.startsWith(`${n}_`))return n}const s=e.indexOf("__");if(s>=0&&s<e.length-2){const n=e.slice(s+2);for(const[a,r]of this.groups)if(r.toolNames&&r.toolNames.includes(n)||n.startsWith(`${a}_`)||n===a)return a}}shouldShowToLLMByName(e){const s=this.getGroupForExposedName(e);return this.shouldShowToLLM(s)}listToolManifests(e,s){const n=this.groups.get(e);if(!n)return[];if(n.toolNames&&n.toolNames.length>0)return s.filter(r=>{const t=r.exposedName.includes("__")?r.exposedName.slice(r.exposedName.indexOf("__")+2):r.exposedName;return n.toolNames.includes(t)}).map(r=>({name:r.exposedName,description:r.description,inputSchema:r.inputSchema}));const a=`${e}_`;return s.filter(r=>{const t=r.exposedName.includes("__")?r.exposedName.slice(r.exposedName.indexOf("__")+2):r.exposedName;return t===e||t.startsWith(a)}).map(r=>({name:r.exposedName,description:r.description,inputSchema:r.inputSchema}))}buildCapabilityPrompt(){const e=[],s=[],n=[];for(const r of this.groups.values()){const t=this.getConfigState(r.key);t==="disabled"?n.push(r):t==="collapsed"&&r.collapsible?s.push(r):e.push(r)}const a=["## \u53EF\u7528\u80FD\u529B",""];if(e.length>0||s.length>0){a.push("\u5DF2\u5F00\u542F\uFF1A");for(const r of e)a.push(`- ${r.label}\uFF1A${r.summary}\uFF08\u5DE5\u5177\u5DF2\u53EF\u76F4\u63A5\u8C03\u7528\uFF09`);for(const r of s)a.push(`- ${r.label}\uFF1A${r.summary}\uFF08\u5DE5\u5177\u5DF2\u6536\u8D77\uFF09`);s.length>0&&(a.push(""),a.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 \u5C55\u5F00\uFF0C\u5DE5\u5177\u5B9A\u4E49\u968F\u7ED3\u679C\u8FD4\u56DE\u540E\u5373\u53EF\u7ECF call_tool \u8C03\u7528\u3002"))}else a.push("\u5F53\u524D\u6CA1\u6709\u5DF2\u5F00\u542F\u7684\u6269\u5C55\u80FD\u529B\u3002");if(n.length>0){a.push(""),a.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 r of n)a.push(`- ${r.label}\uFF1A${r.summary}`)}return a.join(`
2
- `)}registerFromMeta(e,s,n,a){this.groups.has(e)||this.register({key:e,label:s??e,summary:n??"",collapsible:!0})}addToolName(e,s){const n=this.groups.get(e);n&&(n.toolNames&&n.toolNames.includes(s)||(n.toolNames?n.toolNames.push(s):n.toolNames=[s]))}}function $(x){const{toolGroupManager:e,getAllTools:s,capabilityToolRelay:n}=x,a=()=>{const r=[];for(const t of e.getAllGroups())!t.collapsible||e.getConfigState(t.key)!=="collapsed"||r.push(`- ${t.key}\uFF1A${t.label}\uFF08${t.summary}\uFF09`);return r.length===0?"":`
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
3
 
4
4
  \u5F53\u524D\u53EF\u5C55\u5F00\u7684\u6536\u7EB3\u7EC4\uFF1A
5
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\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\u7EC4 key\uFF0Caction \u4E3A "expand"\uFF08\u9ED8\u8BA4\uFF09\u6216 "collapse"\u3002\u7528 group="all" \u64CD\u4F5C\u5168\u90E8\u7EC4\u3002',inputSchema:{type:"object",properties:{group:{type:"string",description:'\u7EC4 key\uFF08\u5982 pencil\uFF09\uFF0C\u6216 "all" \u5C55\u5F00/\u6536\u8D77\u5168\u90E8'},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(),g=String(r.action??"expand").trim();if(!t)return{ok:!1,error:"\u7F3A\u5C11 group \u53C2\u6570",hint:a()};if(t==="all"){if(g==="collapse"){const u=e.collapse("all");if(n){for(const d of e.getAllGroups())if(n.handlesGroup(d.key))try{await n.collapse(d.key)}catch{}}return{ok:!0,status:"collapsed",group:"all",hint:u>0?"\u5168\u90E8\u5DE5\u5177\u7EC4\u5DF2\u6536\u8D77\u3002":"\u6240\u6709\u5DE5\u5177\u7EC4\u5747\u5DF2\u5728\u6536\u8D77\u72B6\u6001\u3002"}}const o=e.expand("all"),l=[];for(const u of e.getAllGroups())if(e.isExpanded(u.key)){if(n?.handlesGroup(u.key)){if(e.getConfigState(u.key)==="disabled")continue;try{l.push(...await n.expand(u.key))}catch{}continue}l.push(...e.listToolManifests(u.key,s()))}return o<=0?{ok:!0,status:o===0?"already-expanded":"expanded",group:"all",toolCount:l.length,tools:l,hint:o===0?"\u5168\u90E8\u5DE5\u5177\u7EC4\u5DF2\u5728\u5C55\u5F00\u72B6\u6001\u3002":"\u5168\u90E8\u5DE5\u5177\u7EC4\u5DF2\u5C55\u5F00\u3002"}:{ok:!0,status:"expanded",group:"all",toolCount:l.length,tools:l,hint:"\u5168\u90E8\u5DE5\u5177\u7EC4\u5DF2\u5C55\u5F00\uFF0C\u5DE5\u5177\u5B9A\u4E49\u5DF2\u8FD4\u56DE\u3002"}}if(g==="collapse"){const o=e.collapse(t);if(o<0)return{ok:!1,error:`\u672A\u77E5\u5DE5\u5177\u7EC4: ${t}`};if(n?.handlesGroup(t))try{await n.collapse(t)}catch{}return o===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 f=e.getRegistration(t);if(!f){const o=a();return{ok:!1,error:`\u672A\u77E5\u5DE5\u5177\u7EC4: ${t}`,hint:o}}if(e.getConfigState(t)==="disabled")return{ok:!1,error:`\u80FD\u529B\u300C${f.label}\u300D\u672A\u5F00\u542F\uFF0C\u8BF7\u5728\u300C\u80FD\u529B\u914D\u7F6E\u300D\u4E2D\u5F00\u542F\u540E\u518D\u5C55\u5F00`};if(n?.handlesGroup(t)){let o;try{o=await n.expand(t)}catch(u){return{ok:!1,error:`\u5C55\u5F00\u300C${f.label}\u300D\u5931\u8D25: ${u instanceof Error?u.message:String(u)}`}}const l=e.expand(t);return{ok:!0,status:l===0?"already-expanded":"expanded",group:t,toolCount:o.length,tools:o,hint:l===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 p=e.expand(t);if(p<0)return{ok:!1,error:`\u672A\u77E5\u5DE5\u5177\u7EC4: ${t}`};const h=e.listToolManifests(t,s());return p===0?{ok:!0,status:"already-expanded",group:t,toolCount:h.length,tools:h,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:h.length,tools:h,hint:"\u5DE5\u5177\u5DF2\u5C55\u5F00\uFF0C\u4E0B\u4E00\u6761\u6D88\u606F\u5373\u53EF\u7ECF call_tool \u8C03\u7528\u3002"}}}}function S(x){const{toolGroupManager:e,pluginBridge:s,findTool:n,dispatchTool:a,capabilityToolRelay:r}=x;return{kind:"builtin",toolName:"call_tool",exposedName:"call_tool",description:`\u8C03\u7528\u5DF2\u901A\u8FC7 expand_tools \u5C55\u5F00\u7684\u6536\u7EB3\u5DE5\u5177\u7EC4\u5185\u7684\u5DE5\u5177\u3002\u5C55\u5F00\u540E\u53EF\u7528\u672C\u5DE5\u5177\u4E2D\u8F6C\u8C03\u7528\uFF1Acall_tool({ name: "<\u5DE5\u5177\u540D>", arguments: {...} })\u3002\u4E5F\u7528\u4E8E\u8C03\u7528\u63D2\u4EF6\u5DE5\u5177\uFF08name \u4E3A"\u63D2\u4EF6\u540D.\u5DE5\u5177\u540D"\u9650\u5B9A\u540D\uFF0C\u5982 "wechat-cli.send_msg"\uFF09\u3002
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
7
11
 
8
12
  \u63D2\u4EF6\u5DE5\u5177\u6A21\u5F0F\uFF08\u53EF\u9009\u63D2\u4EF6\uFF09\uFF1A
9
13
  - action="catalog"\uFF1A\u8FD4\u56DE\u5F53\u524D\u5168\u90E8\u63D2\u4EF6\u76EE\u5F55\uFF08\u7D27\u51D1\uFF09
10
14
  - action="schema" + tool="\u63D2\u4EF6\u540D.\u5DE5\u5177\u540D"\uFF1A\u8FD4\u56DE\u8BE5\u5DE5\u5177\u7684\u5B8C\u6574 inputSchema
11
15
  - action="call"\uFF08\u9ED8\u8BA4\uFF09+ name="\u63D2\u4EF6\u540D.\u5DE5\u5177\u540D" + arguments={...}\uFF1A\u8C03\u7528\u63D2\u4EF6\u5DE5\u5177
12
16
 
13
- \u8BF4\u660E\uFF1A\u53EA\u8C03\u5EA6\u5DF2\u5C55\u5F00\u7684\u7EC4\u5DE5\u5177\uFF1B\u672A\u5C55\u5F00\u7EC4\u88AB\u62D2\u7EDD\u5E76\u5F15\u5BFC\u8C03\u7528 expand_tools\u3002`,inputSchema:{type:"object",properties:{name:{type:"string",description:"\u5DE5\u5177\u540D\uFF08\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(t,g){const f=String(t.action??"call").trim();if(f==="catalog"){if(!s)return{error:"\u63D2\u4EF6\u7CFB\u7EDF\u672A\u542F\u7528"};try{return await s.getCatalog()}catch(o){return{error:`\u63D2\u4EF6\u76EE\u5F55\u67E5\u8BE2\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`}}}if(f==="schema"){if(!s)return{error:"\u63D2\u4EF6\u7CFB\u7EDF\u672A\u542F\u7528"};const o=String(t.tool??"").trim();if(!o)return{error:'\u7F3A\u5C11 tool \u53C2\u6570\uFF08\u9650\u5B9A\u540D "\u63D2\u4EF6\u540D.\u5DE5\u5177\u540D"\uFF09'};try{if(o.endsWith(".*")){const u=o.slice(0,-2),d=await s.getCatalog(),i=d.plugins.find(y=>y.plugin===u);if(!i)return{error:`\u63D2\u4EF6 ${u} \u672A\u5B89\u88C5\u6216\u5DF2\u505C\u7528`,catalog:d.plugins};const m=await Promise.all(i.tools.map(y=>s.getToolSchema(`${u}.${y.name}`)));return{plugin:u,schemas:m.filter(Boolean)}}const l=await s.getToolSchema(o);return l||{error:`\u672A\u77E5\u63D2\u4EF6\u5DE5\u5177: ${o}\uFF08\u53EF\u5148 action=catalog \u67E5\u770B\u76EE\u5F55\uFF09`}}catch(l){return{error:`\u63D2\u4EF6 schema \u67E5\u8BE2\u5931\u8D25: ${l instanceof Error?l.message:String(l)}`}}}const c=String(t.name??"").trim();if(!c)return{error:"\u7F3A\u5C11 name \u53C2\u6570\uFF08\u5DE5\u5177\u540D\u6216\u63D2\u4EF6\u9650\u5B9A\u540D\uFF09"};if(c.includes(".")){if(!s)return{error:"\u63D2\u4EF6\u7CFB\u7EDF\u672A\u542F\u7528"};const o=c.indexOf(".");if(o<=0||o>=c.length-1)return{error:`\u63D2\u4EF6\u9650\u5B9A\u540D\u4E0D\u5408\u6CD5: ${c}\uFF08\u5E94\u4E3A "\u63D2\u4EF6\u540D.\u5DE5\u5177\u540D"\uFF09`};const l=c.slice(0,o),u=c.slice(o+1);if(!u.trim())return{error:`\u63D2\u4EF6\u9650\u5B9A\u540D\u4E0D\u5408\u6CD5: ${c}\uFF08\u7F3A\u5C11\u5DE5\u5177\u540D\uFF09`};const d=t.arguments&&typeof t.arguments=="object"&&!Array.isArray(t.arguments)?t.arguments:{};try{const i=await s.invokeTool(l,u.trim(),d,{toolCallId:g?.toolCallId});if(i.ok)return i.result??{ok:!0};const m={error:i.error??"\u63D2\u4EF6\u5DE5\u5177\u8C03\u7528\u5931\u8D25"};return i.inputSchema!==void 0&&(m.inputSchema=i.inputSchema),typeof i.durationMs=="number"&&(m.durationMs=i.durationMs),m}catch(i){return{error:`\u63D2\u4EF6\u8C03\u7528\u5931\u8D25: ${i instanceof Error?i.message:String(i)}`}}}const p=n(c);if(!p){if(r?.handlesTool(c)){const o=e.getGroupForExposedName(c),l=o?e.getRegistration(o):void 0,u=o?e.getConfigState(o):"disabled";if(!o||!l||u==="disabled")return{error:`\u5DE5\u5177 ${c} \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(o))return{error:`\u5DE5\u5177\u96C6\u300C${l.label}\u300D\u5C1A\u672A\u5C55\u5F00\uFF0C\u8BF7\u5148\u8C03\u7528 expand_tools({ group: "${o}" }) \u5C55\u5F00\u540E\u518D\u8C03\u7528`,group:o};const d=t.arguments&&typeof t.arguments=="object"&&!Array.isArray(t.arguments)?t.arguments:{};try{const i=await r.call(c,d);return i.ok?i.result??{ok:!0}:{error:i.error??`\u8C03\u7528\u5DE5\u5177 ${c} \u5931\u8D25`}}catch(i){return{error:`\u8C03\u7528\u5DE5\u5177 ${c} \u5931\u8D25: ${i instanceof Error?i.message:String(i)}`}}}return{error:`\u672A\u77E5\u5DE5\u5177: ${c}\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(p.group){const o=e.getRegistration(p.group);if(o&&o.collapsible){const l=e.getConfigState(p.group);if(l==="disabled")return{error:`\u5DE5\u5177 ${c} \u6240\u5C5E\u7684\u80FD\u529B\u300C${o.label}\u300D\u672A\u5F00\u542F\uFF0C\u8BF7\u544A\u77E5\u7528\u6237\u53BB\u300C\u80FD\u529B\u914D\u7F6E\u300D\u4E2D\u5F00\u542F`};if(l==="collapsed"&&!e.isExpanded(p.group))return{error:`\u5DE5\u5177\u96C6\u300C${o.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 h=t.arguments&&typeof t.arguments=="object"&&!Array.isArray(t.arguments)?t.arguments:{};try{return await a(c,h,{toolCallId:g?.toolCallId})}catch(o){return{error:`\u8C03\u7528\u5DE5\u5177 ${c} \u5931\u8D25: ${o instanceof Error?o.message:String(o)}`}}}}}export{b as ToolGroupManager,S as createCallToolTool,$ as createExpandToolsTool};
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};
14
18
 
@@ -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 {
@@ -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[];
@@ -159,6 +165,8 @@ export interface ACodeRuntimeConfig {
159
165
  capabilityState?: (featureKey: string) => CapabilityState;
160
166
 
161
167
  capabilityToolRelay?: import("./tool-group-manager.js").CapabilityToolRelay;
168
+
169
+ runtimeResourcesProvider?: () => Promise<string | null | undefined>;
162
170
  }
163
171
  export interface ACodeResolvedProviderConfig {
164
172
  model: string;
@@ -19,7 +19,7 @@
19
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, BrowserListenerEvent, Card, DirectMessage, DmHistoryResponse, FetchUnreadMessagesOptions, FinishTaskRollbackArgs, GroupHistoryResponse, GroupRoomsResponse, HireBatchResult, HireColleagueArgs, MessageHandler, OnlineListResponse, PluginCatalogSnapshot, ProfileInfo, RegisterResult, ServerConfig, SendDmResult, SendMessageResult, StartTaskRollbackArgs, TaskInstanceCommentArgs, UnreadMessagesResult } from "./types.js";
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,20 +52,32 @@ 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?: Card): Promise<SendMessageResult>;
63
+ sendGroupMessage(content: string, projectId?: string, roomId?: string, card?: Card, replyTo?: ReplyToRef[]): Promise<SendMessageResult>;
62
64
 
63
- sendDirectMessage(targetId: string, content: string, waitReply?: boolean, replyToCallId?: string, timeoutMs?: number, card?: Card): Promise<SendDmResult>;
65
+ sendDirectMessage(targetId: string, content: string, waitReply?: boolean, replyToCallId?: string, timeoutMs?: number, card?: Card, replyTo?: ReplyToRef[]): Promise<SendDmResult>;
64
66
 
65
67
  sendCallAndWaitReply(targetId: string, content: string, timeoutMs?: number): Promise<DirectMessage>;
66
68
 
67
69
  replyToCall(callId: string, targetId: string, content: string): Promise<SendDmResult>;
68
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
+ ackEmail(mailId: string): Promise<unknown>;
80
+
69
81
  getDmHistory(targetUserId?: string, limit?: number, since?: string): Promise<DmHistoryResponse>;
70
82
 
71
83
  getGroupHistory(limit?: number, roomId?: string, since?: string): Promise<GroupHistoryResponse>;
@@ -105,18 +117,20 @@ export declare class AgentClient {
105
117
 
106
118
  getMyTasks(): Promise<unknown[]>;
107
119
 
120
+ listTaskNodeIterations(args?: {
121
+ offset?: number;
122
+ limit?: number;
123
+ nodeTemplateId?: string;
124
+ }): Promise<unknown>;
125
+
108
126
  createTaskInstanceComment(args: TaskInstanceCommentArgs): Promise<unknown>;
109
127
 
110
- submitTaskResult(nodeId: string, outputPayload: string, changeLog?: unknown[]): Promise<unknown>;
128
+ submitTaskResult(nodeId: string, outputPayload: string, changeLog?: unknown[] | string, handoverNote?: string, deliverables?: unknown[]): Promise<unknown>;
111
129
 
112
130
  startTaskRollback(args: StartTaskRollbackArgs): Promise<unknown>;
113
131
 
114
132
  finishTaskRollback(args: FinishTaskRollbackArgs): Promise<unknown>;
115
133
 
116
- rejectTask(nodeId: string, reason: string): Promise<unknown>;
117
-
118
- terminateTask(taskInstanceId: string, reason: string): Promise<unknown>;
119
-
120
134
  getDebugLogConfig(): Promise<unknown>;
121
135
 
122
136
  queryDebugLogs(args: Record<string, unknown>): Promise<unknown>;
@@ -1,2 +1,2 @@
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 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(){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,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){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,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 g={agentId:this.agentId,targetId:e,content:t,requireReply:n,waitReply:n,replyToCallId:r,card:a};if(typeof i=="number"&&i>0&&(g.timeoutMs=i),n){const h=typeof i=="number"&&i>0?i+3e4:0;return await this.httpClient.callToolOnce("send_dm",g,h)}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 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(),i=this.projectId||this.agentConfig.projectId,a=this.collectRoomIds(r,i);if(a.length===0)return{messages:[],count:0};const h=(await Promise.all(a.map(async o=>{const l={projectId:i,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:h,count:h.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(o){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",o instanceof Error?o.message:String(o)),a={groups:[]}}const g=this.collectRoomIds(a,t),h=await Promise.all(g.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 s.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(i.messages)?i.messages:[],groupMessages:h.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(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 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(){c.loadConfig(),this.agentConfig=c.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(g=>setTimeout(g,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 ackEmail(e){return await this.callAgentScopedTool("ack_email",{mailId: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