aws-runtime-bridge 1.9.151 → 1.9.162

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 (81) hide show
  1. package/CHANGELOG.md +560 -0
  2. package/dist/adapter/AcodeSdkAdapter.d.ts +51 -1
  3. package/dist/adapter/AcodeSdkAdapter.js +6 -5
  4. package/dist/adapter/prompts.d.ts +1 -1
  5. package/dist/adapter/prompts.js +1 -1
  6. package/dist/desktop/built-in-desktop-tools.js +1 -1
  7. package/dist/routes/acode-todos.js +1 -1
  8. package/dist/routes/ltr.js +1 -1
  9. package/dist/routes/sessions.d.ts +31 -0
  10. package/dist/routes/sessions.js +1 -1
  11. package/dist/routes/terminal.d.ts +8 -0
  12. package/dist/routes/terminal.js +25 -25
  13. package/dist/services/instance-features.d.ts +25 -1
  14. package/dist/services/instance-features.js +1 -1
  15. package/dist/services/workspace-files.js +1 -1
  16. package/dist/services/workspace-watch.js +1 -1
  17. package/dist/utils/file-utils.d.ts +2 -0
  18. package/dist/utils/file-utils.js +2 -2
  19. package/package/acode/dist/ask-user-question-tool.js +1 -1
  20. package/package/acode/dist/await-complete-tool.js +1 -1
  21. package/package/acode/dist/background-command-manager.js +1 -1
  22. package/package/acode/dist/background-command-tools.js +1 -1
  23. package/package/acode/dist/built-in-file-tools.d.ts +18 -2
  24. package/package/acode/dist/built-in-file-tools.js +2 -2
  25. package/package/acode/dist/built-in-symbols-tool.js +1 -1
  26. package/package/acode/dist/context-overflow.d.ts +19 -0
  27. package/package/acode/dist/context-overflow.js +2 -0
  28. package/package/acode/dist/grammars/grammars/tree-sitter-lua.wasm +0 -0
  29. package/package/acode/dist/index.d.ts +3 -1
  30. package/package/acode/dist/index.js +1 -1
  31. package/package/acode/dist/parsers/ast-cache.d.ts +12 -1
  32. package/package/acode/dist/parsers/ast-cache.js +1 -1
  33. package/package/acode/dist/parsers/language-queries.js +1 -1
  34. package/package/acode/dist/parsers/symbol-extractor.js +2 -2
  35. package/package/acode/dist/parsers/tree-sitter-loader.d.ts +1 -1
  36. package/package/acode/dist/parsers/tree-sitter-loader.js +1 -1
  37. package/package/acode/dist/plugin-types.d.ts +5 -0
  38. package/package/acode/dist/plugin-types.js +1 -0
  39. package/package/acode/dist/read-file-state.d.ts +48 -0
  40. package/package/acode/dist/read-file-state.js +2 -0
  41. package/package/acode/dist/runtime.d.ts +63 -3
  42. package/package/acode/dist/runtime.js +30 -26
  43. package/package/acode/dist/skill-tool.js +3 -3
  44. package/package/acode/dist/sub-agent-manager.js +1 -1
  45. package/package/acode/dist/sub-agent-tools.js +5 -5
  46. package/package/acode/dist/todo-tool.js +3 -3
  47. package/package/acode/dist/tool-concurrency/index.d.ts +5 -0
  48. package/package/acode/dist/tool-concurrency/index.js +2 -0
  49. package/package/acode/dist/tool-concurrency/observability.d.ts +46 -0
  50. package/package/acode/dist/tool-concurrency/observability.js +3 -0
  51. package/package/acode/dist/tool-concurrency/resource-lock.d.ts +25 -0
  52. package/package/acode/dist/tool-concurrency/resource-lock.js +2 -0
  53. package/package/acode/dist/tool-concurrency/scheduler.d.ts +30 -0
  54. package/package/acode/dist/tool-concurrency/scheduler.js +2 -0
  55. package/package/acode/dist/tool-concurrency/types.d.ts +80 -0
  56. package/package/acode/dist/tool-concurrency/types.js +2 -0
  57. package/package/acode/dist/tool-group-manager.d.ts +116 -0
  58. package/package/acode/dist/tool-group-manager.js +14 -0
  59. package/package/acode/dist/types.d.ts +14 -1
  60. package/package/acode/package.json +2 -2
  61. package/package/aws-client-agent-mcp/dist/agent-client.d.ts +4 -4
  62. package/package/aws-client-agent-mcp/dist/agent-client.js +1 -1
  63. package/package/aws-client-agent-mcp/dist/http-client.d.ts +1 -1
  64. package/package/aws-client-agent-mcp/dist/http-client.js +1 -1
  65. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +62 -17
  66. package/package/aws-client-agent-mcp/dist/mcp-server.js +29 -29
  67. package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +46 -0
  68. package/package/aws-client-agent-mcp/dist/mcp-tools.js +149 -7
  69. package/package/aws-client-agent-mcp/dist/office/office-equation.d.ts +5 -0
  70. package/package/aws-client-agent-mcp/dist/office/office-equation.js +2 -0
  71. package/package/aws-client-agent-mcp/dist/office/office-image.d.ts +12 -0
  72. package/package/aws-client-agent-mcp/dist/office/office-image.js +2 -0
  73. package/package/aws-client-agent-mcp/dist/office/office-workspace.d.ts +25 -0
  74. package/package/aws-client-agent-mcp/dist/office/office-workspace.js +2 -0
  75. package/package/aws-client-agent-mcp/dist/tool-groups.d.ts +57 -0
  76. package/package/aws-client-agent-mcp/dist/tool-groups.js +3 -0
  77. package/package/aws-client-agent-mcp/dist/types.d.ts +27 -0
  78. package/package/aws-client-agent-mcp/package.json +2 -1
  79. package/package.json +1 -1
  80. package/package/acode/dist/plugin-tools.d.ts +0 -14
  81. package/package/acode/dist/plugin-tools.js +0 -9
@@ -1,5 +1,5 @@
1
- import{promises as k}from"node:fs";import w from"node:path";import{pathToFileURL as p}from"node:url";const y=10;async function b(o,e){const i=[];async function n(a){if(i.length>=e)return;let r;try{r=await k.readdir(a,{withFileTypes:!0})}catch{return}for(const t of r){if(i.length>=e)return;if(t.name.startsWith("."))continue;const s=w.join(a,t.name);t.isDirectory()?await n(s):t.isFile()&&t.name!=="SKILL.md"&&i.push(s)}}return await n(o),i}function u(o){if(o.length===0)return["Load a specialized skill that provides domain-specific instructions and workflows.","No skills are currently available."].join(" ");const e=["Load a specialized skill that provides domain-specific instructions and workflows.","","When you recognize that a task matches one of the available skills listed below, use this tool to load the full skill instructions.","","The skill will inject detailed instructions, workflows, and access to bundled resources (scripts, references, templates) into the conversation context.","",'Tool output includes a `<skill_content name="...">` block with the loaded content.',"","The following skills provide specialized sets of instructions for particular tasks.","Invoke this tool to load a skill when a task matches one of the available skills listed below:","","<available_skills>"];for(const i of o)e.push(" <skill>"),e.push(` <name>${i.name}</name>`),e.push(` <description>${i.description??""}</description>`),e.push(` <location>${p(i.directory).href}</location>`),e.push(" </skill>");return e.push("</available_skills>"),e.join(`
2
- `)}function S(o){const e=new Map;function i(t){e.clear();for(const s of t)e.set(s.name,s)}i(o);const n=o.map(t=>`'${t.name}'`).slice(0,3).join(", "),a=n.length>0?` (e.g., ${n}, ...)`:"";return{kind:"builtin",toolName:"skill",exposedName:"skill",description:u(o),inputSchema:{type:"object",properties:{name:{type:"string",description:`The name of the skill from available_skills${a}`}},required:["name"],additionalProperties:!1},async execute(t){const s=t.name;if(typeof s!="string"||!s.trim())throw new Error("name is required");const f=s.trim(),l=e.get(f);if(!l){const c=Array.from(e.keys()).join(", ")||"none";throw new Error(`Skill "${f}" not found. Available skills: ${c}`)}const h=p(l.directory).href,d=(await b(l.directory,y)).map(c=>`<file>${c}</file>`).join(`
3
- `),m=l.content||"";return{content:[{type:"text",text:[`<skill_content name="${l.name}">`,`# Skill: ${l.name}`,"",m,"",`Base directory for this skill: ${h}`,"Relative paths in this skill (e.g., scripts/, reference/) are relative to this base directory.","Note: file list is sampled.","","<skill_files>",d,"</skill_files>","</skill_content>"].join(`
1
+ import{promises as m}from"node:fs";import y from"node:path";import{pathToFileURL as p}from"node:url";const w=10;async function b(o,e){const i=[];async function n(a){if(i.length>=e)return;let r;try{r=await m.readdir(a,{withFileTypes:!0})}catch{return}for(const t of r){if(i.length>=e)return;if(t.name.startsWith("."))continue;const s=y.join(a,t.name);t.isDirectory()?await n(s):t.isFile()&&t.name!=="SKILL.md"&&i.push(s)}}return await n(o),i}function u(o){if(o.length===0)return["Load a specialized skill that provides domain-specific instructions and workflows.","No skills are currently available."].join(" ");const e=["Load a specialized skill that provides domain-specific instructions and workflows.","","When you recognize that a task matches one of the available skills listed below, use this tool to load the full skill instructions.","","The skill will inject detailed instructions, workflows, and access to bundled resources (scripts, references, templates) into the conversation context.","",'Tool output includes a `<skill_content name="...">` block with the loaded content.',"","The following skills provide specialized sets of instructions for particular tasks.","Invoke this tool to load a skill when a task matches one of the available skills listed below:","","<available_skills>"];for(const i of o)e.push(" <skill>"),e.push(` <name>${i.name}</name>`),e.push(` <description>${i.description??""}</description>`),e.push(` <location>${p(i.directory).href}</location>`),e.push(" </skill>");return e.push("</available_skills>"),e.join(`
2
+ `)}function S(o){const e=new Map;function i(t){e.clear();for(const s of t)e.set(s.name,s)}i(o);const n=o.map(t=>`'${t.name}'`).slice(0,3).join(", "),a=n.length>0?` (e.g., ${n}, ...)`:"";return{kind:"builtin",toolName:"skill",exposedName:"skill",concurrencyMode:"read",resourceKeys:()=>[{key:"runtime:skills",access:"read"}],description:u(o),inputSchema:{type:"object",properties:{name:{type:"string",description:`The name of the skill from available_skills${a}`}},required:["name"],additionalProperties:!1},async execute(t){const s=t.name;if(typeof s!="string"||!s.trim())throw new Error("name is required");const f=s.trim(),l=e.get(f);if(!l){const c=Array.from(e.keys()).join(", ")||"none";throw new Error(`Skill "${f}" not found. Available skills: ${c}`)}const d=p(l.directory).href,h=(await b(l.directory,w)).map(c=>`<file>${c}</file>`).join(`
3
+ `),k=l.content||"";return{content:[{type:"text",text:[`<skill_content name="${l.name}">`,`# Skill: ${l.name}`,"",k,"",`Base directory for this skill: ${d}`,"Relative paths in this skill (e.g., scripts/, reference/) are relative to this base directory.","Note: file list is sampled.","","<skill_files>",h,"</skill_files>","</skill_content>"].join(`
4
4
  `)}]}},refresh(t){i(t),this.description=u(t)}}}export{S as createSkillTool};
5
5
 
@@ -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 _{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":e.data?.estimatedContextTokens!=null&&(n.tokenUsage.input=e.data.estimatedContextTokens??n.tokenUsage.input),n.currentTool="[model_request]",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{_ 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(),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};
2
2
 
@@ -28,7 +28,7 @@ Guidelines:
28
28
  - Write a clear, self-contained prompt (the sub-agent starts with a fresh context)
29
29
  - Launch multiple agents concurrently when possible (multiple tool calls in one message)
30
30
  - Sub-agents cannot spawn further sub-agents (no nesting)
31
- - Always call await_complete (with this subId in 'sub_agent_ids') before reporting completion to the user`;function h(a){return{kind:"builtin",toolName:"sub_agent",exposedName:"sub_agent",description:b,inputSchema:{type:"object",properties:{description:{type:"string",description:"A short (3-5 words) description of the task."},prompt:{type:"string",description:"The task for the sub-agent to perform (self-contained, fresh context)."},subagent_type:{type:"string",enum:["explore","core","custom"],description:"Sub-agent type: 'explore' (read-only default), 'core' (all core tools), or 'custom' (specific tools via 'tools' param)."},tools:{type:"array",items:{type:"string"},description:"Tool allocation for 'custom' type (required when subagent_type is 'custom'). Category names ('office', 'browser') or exact tool paths ('default.read_file'). Elements combine by union."}},required:["description","prompt","subagent_type"]},async execute(n){const o=typeof n.description=="string"?n.description.trim():"",t=typeof n.prompt=="string"?n.prompt.trim():"",e=typeof n.subagent_type=="string"?n.subagent_type.trim():"";if(!o)return{title:"sub_agent validation error",output:"Invalid input: 'description' is required and must be non-empty.",metadata:{error:!0}};if(!t)return{title:"sub_agent validation error",output:"Invalid input: 'prompt' is required and must be non-empty.",metadata:{error:!0}};if(!e||!["explore","core","custom"].includes(e))return{title:"sub_agent validation error",output:"Invalid input: 'subagent_type' must be one of 'explore', 'core', or 'custom'.",metadata:{error:!0}};const s=n.tools,r=typeof s=="string"?[s]:Array.isArray(s)?s.filter(i=>typeof i=="string"):[];let u,l;try{const i=await a.listSubAgentToolCatalog(),c=d(e,r,i);u=c.patterns,l=c.label}catch(i){if(i instanceof g)return{title:"sub_agent validation error",output:`Invalid input: ${i.message}`,metadata:{error:!0}};throw i}const p=u.length>0;try{const{subId:i}=await a.spawnSubAgent({subagentType:l,description:o,prompt:t,...p?{allowedTools:u}:{}}),c=p?`
31
+ - Always call await_complete (with this subId in 'sub_agent_ids') before reporting completion to the user`;function h(a){return{kind:"builtin",toolName:"sub_agent",exposedName:"sub_agent",description:b,inputSchema:{type:"object",properties:{description:{type:"string",description:"A short (3-5 words) description of the task."},prompt:{type:"string",description:"The task for the sub-agent to perform (self-contained, fresh context)."},subagent_type:{type:"string",enum:["explore","core","custom"],description:"Sub-agent type: 'explore' (read-only default), 'core' (all core tools), or 'custom' (specific tools via 'tools' param)."},tools:{type:"array",items:{type:"string"},description:"Tool allocation for 'custom' type (required when subagent_type is 'custom'). Category names ('office', 'browser') or exact tool paths ('default.read_file'). Elements combine by union."}},required:["description","prompt","subagent_type"]},async execute(r){const o=typeof r.description=="string"?r.description.trim():"",t=typeof r.prompt=="string"?r.prompt.trim():"",e=typeof r.subagent_type=="string"?r.subagent_type.trim():"";if(!o)return{title:"sub_agent validation error",output:"Invalid input: 'description' is required and must be non-empty.",metadata:{error:!0}};if(!t)return{title:"sub_agent validation error",output:"Invalid input: 'prompt' is required and must be non-empty.",metadata:{error:!0}};if(!e||!["explore","core","custom"].includes(e))return{title:"sub_agent validation error",output:"Invalid input: 'subagent_type' must be one of 'explore', 'core', or 'custom'.",metadata:{error:!0}};const s=r.tools,n=typeof s=="string"?[s]:Array.isArray(s)?s.filter(i=>typeof i=="string"):[];let u,l;try{const i=await a.listSubAgentToolCatalog(),c=d(e,n,i);u=c.patterns,l=c.label}catch(i){if(i instanceof g)return{title:"sub_agent validation error",output:`Invalid input: ${i.message}`,metadata:{error:!0}};throw i}const p=u.length>0;try{const{subId:i}=await a.spawnSubAgent({subagentType:l,description:o,prompt:t,...p?{allowedTools:u}:{}}),c=p?`
32
32
  tool allocation (${l}): ${u.join(", ")} (whitelist mode \u2014 only matching tools are exposed)`:`
33
33
  mode: ${l} (no allocatable tools found in catalog)`;return{title:o,output:`sub_agent spawned: ${i}
34
34
  type: ${l}${c}
@@ -43,7 +43,7 @@ Returns two arrays:
43
43
  Use this to:
44
44
  1. Check which sub-agents are still running
45
45
  2. Review completed sub-agent history
46
- 3. Find a subId before calling await_complete (sub_agent_ids) or get_sub_agent_status`;function f(a){return{kind:"builtin",toolName:"list_sub_agents",exposedName:"list_sub_agents",description:m,inputSchema:{type:"object",properties:{}},async execute(n){try{const{running:o,history:t}=await a.listSubAgents(),e=r=>{const u=r.durationMs!==void 0?`${(r.durationMs/1e3).toFixed(1)}s`:r.endedAt?`${((r.endedAt-r.startedAt)/1e3).toFixed(1)}s`:"ongoing";return` - ${r.subId} [${r.status}] (${u}) ${r.description}`},s=[];return s.push(`Running (${o.length}):`),o.length===0?s.push(" (none)"):o.forEach(r=>s.push(e(r))),s.push(""),s.push(`History (${t.length}):`),t.length===0?s.push(" (none)"):t.forEach(r=>s.push(e(r))),{title:"sub-agents list",output:s.join(`
46
+ 3. Find a subId before calling await_complete (sub_agent_ids) or get_sub_agent_status`;function f(a){return{kind:"builtin",toolName:"list_sub_agents",exposedName:"list_sub_agents",concurrencyMode:"read",resourceKeys:()=>[{key:"runtime:subagents",access:"read"}],description:m,inputSchema:{type:"object",properties:{}},async execute(r){try{const{running:o,history:t}=await a.listSubAgents(),e=n=>{const u=n.durationMs!==void 0?`${(n.durationMs/1e3).toFixed(1)}s`:n.endedAt?`${((n.endedAt-n.startedAt)/1e3).toFixed(1)}s`:"ongoing";return` - ${n.subId} [${n.status}] (${u}) ${n.description}`},s=[];return s.push(`Running (${o.length}):`),o.length===0?s.push(" (none)"):o.forEach(n=>s.push(e(n))),s.push(""),s.push(`History (${t.length}):`),t.length===0?s.push(" (none)"):t.forEach(n=>s.push(e(n))),{title:"sub-agents list",output:s.join(`
47
47
  `),metadata:{runningCount:o.length,historyCount:t.length}}}catch(o){return{title:"list_sub_agents error",output:`Failed to list sub-agents: ${o instanceof Error?o.message:String(o)}`,metadata:{error:!0}}}}}}const _=`Get the current status and context snapshot of a sub-agent.
48
48
 
49
49
  Returns:
@@ -55,7 +55,7 @@ Returns:
55
55
  - result: final output (if completed)
56
56
  - error: error message (if failed)
57
57
 
58
- Use this to check progress of a running sub-agent before awaiting it.`;function y(a){return{kind:"builtin",toolName:"get_sub_agent_status",exposedName:"get_sub_agent_status",description:_,inputSchema:{type:"object",properties:{sub_id:{type:"string",description:"The sub-agent ID returned by sub_agent tool."}},required:["sub_id"]},async execute(n){const o=typeof n.sub_id=="string"?n.sub_id.trim():"";if(!o)return{title:"get_sub_agent_status validation error",output:"Invalid input: 'sub_id' is required.",metadata:{error:!0}};try{const t=await a.getSubAgentStatus(o);if(!t)return{title:"sub-agent not found",output:`sub-agent not found: ${o}`,metadata:{subId:o,error:!0}};const e=[];if(e.push(`subId: ${t.subId}`),e.push(`type: ${t.subagentType}`),e.push(`description: ${t.description}`),e.push(`status: ${t.status}`),t.startedAt&&e.push(`startedAt: ${new Date(t.startedAt).toISOString()}`),t.endedAt&&e.push(`endedAt: ${new Date(t.endedAt).toISOString()}`),t.durationMs!==void 0&&e.push(`duration: ${(t.durationMs/1e3).toFixed(2)}s`),t.contextSnapshot){if(e.push(""),e.push("Context:"),t.contextSnapshot.currentTool&&e.push(` currentTool: ${t.contextSnapshot.currentTool}`),t.contextSnapshot.lastAssistantText){const s=t.contextSnapshot.lastAssistantText;e.push(` lastOutput: ${s.length>200?s.slice(-200)+"...":s}`)}e.push(` tokens: input=${t.contextSnapshot.tokenUsage.input}, output=${t.contextSnapshot.tokenUsage.output}`),e.push(` messages: ${t.contextSnapshot.messageCount}`),e.push(` updatedAt: ${t.contextSnapshot.updatedAt}`)}if(t.result){e.push(""),e.push("Result:");const s=t.result;e.push(s.length>500?s.slice(0,500)+`
58
+ Use this to check progress of a running sub-agent before awaiting it.`;function y(a){return{kind:"builtin",toolName:"get_sub_agent_status",exposedName:"get_sub_agent_status",concurrencyMode:"read",resourceKeys:()=>[{key:"runtime:subagents",access:"read"}],description:_,inputSchema:{type:"object",properties:{sub_id:{type:"string",description:"The sub-agent ID returned by sub_agent tool."}},required:["sub_id"]},async execute(r){const o=typeof r.sub_id=="string"?r.sub_id.trim():"";if(!o)return{title:"get_sub_agent_status validation error",output:"Invalid input: 'sub_id' is required.",metadata:{error:!0}};try{const t=await a.getSubAgentStatus(o);if(!t)return{title:"sub-agent not found",output:`sub-agent not found: ${o}`,metadata:{subId:o,error:!0}};const e=[];if(e.push(`subId: ${t.subId}`),e.push(`type: ${t.subagentType}`),e.push(`description: ${t.description}`),e.push(`status: ${t.status}`),t.startedAt&&e.push(`startedAt: ${new Date(t.startedAt).toISOString()}`),t.endedAt&&e.push(`endedAt: ${new Date(t.endedAt).toISOString()}`),t.durationMs!==void 0&&e.push(`duration: ${(t.durationMs/1e3).toFixed(2)}s`),t.contextSnapshot){if(e.push(""),e.push("Context:"),t.contextSnapshot.currentTool&&e.push(` currentTool: ${t.contextSnapshot.currentTool}`),t.contextSnapshot.lastAssistantText){const s=t.contextSnapshot.lastAssistantText;e.push(` lastOutput: ${s.length>200?s.slice(-200)+"...":s}`)}e.push(` tokens: input=${t.contextSnapshot.tokenUsage.input}, output=${t.contextSnapshot.tokenUsage.output}`),e.push(` messages: ${t.contextSnapshot.messageCount}`),e.push(` updatedAt: ${t.contextSnapshot.updatedAt}`)}if(t.result){e.push(""),e.push("Result:");const s=t.result;e.push(s.length>500?s.slice(0,500)+`
59
59
  ... (truncated)`:s)}return t.errorMessage&&(e.push(""),e.push(`Error: ${t.errorMessage}`)),{title:`status: ${t.description}`,output:e.join(`
60
60
  `),metadata:{subId:t.subId,status:t.status}}}catch(t){return{title:"get_sub_agent_status error",output:`Failed to get status: ${t instanceof Error?t.message:String(t)}`,metadata:{subId:o,error:!0}}}}}}const w=`Abort a running sub-agent.
61
61
 
@@ -65,7 +65,7 @@ Only pending or running sub-agents can be aborted; completed/failed/cancelled ar
65
65
  After abort:
66
66
  - The sub-agent's status becomes 'cancelled'
67
67
  - Its completionPromise resolves with error='aborted'
68
- - Any await_complete waiting on it (with this subId in 'sub_agent_ids') will return immediately`;function S(a){return{kind:"builtin",toolName:"abort_sub_agent",exposedName:"abort_sub_agent",description:w,inputSchema:{type:"object",properties:{sub_id:{type:"string",description:"The sub-agent ID to abort."}},required:["sub_id"]},async execute(n){const o=typeof n.sub_id=="string"?n.sub_id.trim():"";if(!o)return{title:"abort_sub_agent validation error",output:"Invalid input: 'sub_id' is required.",metadata:{error:!0}};try{return await a.abortSubAgent(o),{title:"sub-agent aborted",output:`sub-agent ${o} has been aborted.`,metadata:{subId:o,aborted:!0}}}catch(t){return{title:"abort_sub_agent error",output:`Failed to abort sub-agent: ${t instanceof Error?t.message:String(t)}`,metadata:{subId:o,error:!0}}}}}}const T=`List all tool categories and tools that can be allocated to sub-agents.
68
+ - Any await_complete waiting on it (with this subId in 'sub_agent_ids') will return immediately`;function S(a){return{kind:"builtin",toolName:"abort_sub_agent",exposedName:"abort_sub_agent",description:w,inputSchema:{type:"object",properties:{sub_id:{type:"string",description:"The sub-agent ID to abort."}},required:["sub_id"]},async execute(r){const o=typeof r.sub_id=="string"?r.sub_id.trim():"";if(!o)return{title:"abort_sub_agent validation error",output:"Invalid input: 'sub_id' is required.",metadata:{error:!0}};try{return await a.abortSubAgent(o),{title:"sub-agent aborted",output:`sub-agent ${o} has been aborted.`,metadata:{subId:o,aborted:!0}}}catch(t){return{title:"abort_sub_agent error",output:`Failed to abort sub-agent: ${t instanceof Error?t.message:String(t)}`,metadata:{subId:o,error:!0}}}}}}const T=`List all tool categories and tools that can be allocated to sub-agents.
69
69
 
70
70
  Output shows categories (suite). Each category line shows its tool short names:
71
71
  - default: core file/shell tools (read_file, write_file, grep, Bash, ...)
@@ -83,6 +83,6 @@ Sub-agent types:
83
83
  - "custom": allocate specific tools via 'tools' parameter
84
84
 
85
85
  If a tool you need is not listed, it cannot be allocated (the sub-agent pool
86
- equals the current agent's tool set).`;function x(a){return{kind:"builtin",toolName:"list_sub_agent_tools",exposedName:"list_sub_agent_tools",description:T,inputSchema:{type:"object",properties:{}},async execute(n){try{const o=await a.listSubAgentToolCatalog();if(o.length===0)return{title:"allocatable tools",output:"No allocatable tools found (tool catalog is empty).",metadata:{categories:0}};const t=["Sub-agent types:"," explore \u2014 read-only set (default category minus write tools + memory MCP tools)"," core \u2014 all core default tools (no suites/MCP)"," custom \u2014 allocate specific tools via 'tools' parameter","","Allocatable tool categories:",""];for(const e of o)t.push(`[${e.category}] ${e.kind} (${e.tools.length}):`),t.push(` ${e.tools.join(", ")}`);return t.push(""),t.push("Usage:"),t.push('- subagent_type: "explore" \u2192 read-only mode (default)'),t.push('- subagent_type: "core" \u2192 all core default tools'),t.push('- subagent_type: "custom", tools: ["<category>"] \u2192 all tools in that category'),t.push('- subagent_type: "custom", tools: ["<category>.<tool>"] \u2192 exactly that tool'),t.push('- tools elements combine by union, e.g. ["browser", "default.read_file"]'),{title:"allocatable tools",output:t.join(`
86
+ equals the current agent's tool set).`;function x(a){return{kind:"builtin",toolName:"list_sub_agent_tools",exposedName:"list_sub_agent_tools",concurrencyMode:"read",resourceKeys:()=>[{key:"runtime:subagents",access:"read"}],description:T,inputSchema:{type:"object",properties:{}},async execute(r){try{const o=await a.listSubAgentToolCatalog();if(o.length===0)return{title:"allocatable tools",output:"No allocatable tools found (tool catalog is empty).",metadata:{categories:0}};const t=["Sub-agent types:"," explore \u2014 read-only set (default category minus write tools + memory MCP tools)"," core \u2014 all core default tools (no suites/MCP)"," custom \u2014 allocate specific tools via 'tools' parameter","","Allocatable tool categories:",""];for(const e of o)t.push(`[${e.category}] ${e.kind} (${e.tools.length}):`),t.push(` ${e.tools.join(", ")}`);return t.push(""),t.push("Usage:"),t.push('- subagent_type: "explore" \u2192 read-only mode (default)'),t.push('- subagent_type: "core" \u2192 all core default tools'),t.push('- subagent_type: "custom", tools: ["<category>"] \u2192 all tools in that category'),t.push('- subagent_type: "custom", tools: ["<category>.<tool>"] \u2192 exactly that tool'),t.push('- tools elements combine by union, e.g. ["browser", "default.read_file"]'),{title:"allocatable tools",output:t.join(`
87
87
  `),metadata:{categories:o.length}}}catch(o){return{title:"list_sub_agent_tools error",output:`Failed to list allocatable tools: ${o instanceof Error?o.message:String(o)}`,metadata:{error:!0}}}}}}function $(a){return[h(a),f(a),y(a),S(a),x(a)]}export{S as createAbortSubAgentTool,y as createGetSubAgentStatusTool,x as createListSubAgentToolsTool,f as createListSubAgentsTool,h as createSubAgentTool,$ as createSubAgentTools};
88
88
 
@@ -1,4 +1,4 @@
1
- import{TodoStore as a}from"./todo-store.js";const l={type:"object",properties:{content:{type:"string",description:"Brief description of the task (required, non-empty)."},status:{type:"string",enum:["pending","in_progress","completed","cancelled"],description:"Current status of the task."},priority:{type:"string",enum:["high","medium","low"],description:"Priority level of the task."}},required:["content","status","priority"]},c=`Update the todo list for the current agent (full replacement).
1
+ import{TodoStore as a}from"./todo-store.js";const c={type:"object",properties:{content:{type:"string",description:"Brief description of the task (required, non-empty)."},status:{type:"string",enum:["pending","in_progress","completed","cancelled"],description:"Current status of the task."},priority:{type:"string",enum:["high","medium","low"],description:"Priority level of the task."}},required:["content","status","priority"]},u=`Update the todo list for the current agent (full replacement).
2
2
 
3
3
  Use this tool proactively to:
4
4
  1. Track complex multi-step tasks (3+ distinct steps)
@@ -11,12 +11,12 @@ Guidelines:
11
11
  - The top-level "background" field is REQUIRED \u2014 it captures the overall task list context (source, goal, constraints) so future reads (todo_read) can resume full context
12
12
  - Each todo item only needs content/status/priority (no per-item background)
13
13
  - This tool replaces the entire todo list; always include all current todos in the array
14
- - The todo list is persisted per agent (not per session), so it survives across sessions for the same agent`,u=`Read the current agent's todo list, including the overall background of the task list.
14
+ - The todo list is persisted per agent (not per session), so it survives across sessions for the same agent`,l=`Read the current agent's todo list, including the overall background of the task list.
15
15
 
16
16
  Use this when:
17
17
  1. You need to recall the current task context (including the list background)
18
18
  2. Starting a new session and need to resume prior work
19
19
  3. Verifying task status before reporting completion to the user
20
20
 
21
- Returns the overall background plus the full todo list with content/status/priority for each item.`;function p(t){return t!==null&&typeof t=="object"&&typeof t.content=="string"&&t.content.trim().length>0&&(t.status==="pending"||t.status==="in_progress"||t.status==="completed"||t.status==="cancelled")&&(t.priority==="high"||t.priority==="medium"||t.priority==="low")}function d(t){return t.filter(o=>o.status!=="completed").length}function h(t){const o=new a;return{kind:"builtin",toolName:"todo_write",exposedName:"todo_write",description:c,inputSchema:{type:"object",properties:{background:{type:"string",description:"Overall background of this todo list (required, non-empty). Describe the task list source, goal, dependencies, and constraints \u2014 context that helps resume work later."},todos:{type:"array",items:l,description:"The updated todo list (replaces the entire list)."}},required:["background","todos"]},async execute(e){const r=typeof e.background=="string"?e.background.trim():"";if(!r)return{title:"todo_write validation error",output:"Invalid input: top-level 'background' is required and must be non-empty. Describe the overall task list context (source, goal, constraints).",metadata:{error:!0}};const i=e.todos??[];for(let s=0;s<i.length;s++)if(!p(i[s]))return{title:"todo_write validation error",output:`Invalid todo item at index ${s}: each item must have non-empty content, valid status (pending|in_progress|completed|cancelled), and valid priority (high|medium|low).`,metadata:{error:!0}};const n=i;return await o.write(t,r,n),{title:`${d(n)} todos`,output:JSON.stringify({background:r,todos:n},null,2),metadata:{background:r,todos:n}}}}}function m(t){const o=new a;return{kind:"builtin",toolName:"todo_read",exposedName:"todo_read",description:u,inputSchema:{type:"object",properties:{},required:[]},async execute(){const e=await o.read(t);return{title:`${d(e.todos)} todos`,output:JSON.stringify({background:e.background,todos:e.todos},null,2),metadata:{background:e.background,todos:e.todos}}}}}export{m as createTodoReadTool,h as createTodoWriteTool};
21
+ Returns the overall background plus the full todo list with content/status/priority for each item.`;function p(t){return t!==null&&typeof t=="object"&&typeof t.content=="string"&&t.content.trim().length>0&&(t.status==="pending"||t.status==="in_progress"||t.status==="completed"||t.status==="cancelled")&&(t.priority==="high"||t.priority==="medium"||t.priority==="low")}function d(t){return t.filter(o=>o.status!=="completed").length}function h(t){const o=new a;return{kind:"builtin",toolName:"todo_write",exposedName:"todo_write",concurrencyMode:"write",resourceKeys:()=>[{key:"runtime:todo",access:"write"}],description:u,inputSchema:{type:"object",properties:{background:{type:"string",description:"Overall background of this todo list (required, non-empty). Describe the task list source, goal, dependencies, and constraints \u2014 context that helps resume work later."},todos:{type:"array",items:c,description:"The updated todo list (replaces the entire list)."}},required:["background","todos"]},async execute(e){const r=typeof e.background=="string"?e.background.trim():"";if(!r)return{title:"todo_write validation error",output:"Invalid input: top-level 'background' is required and must be non-empty. Describe the overall task list context (source, goal, constraints).",metadata:{error:!0}};const i=e.todos??[];for(let s=0;s<i.length;s++)if(!p(i[s]))return{title:"todo_write validation error",output:`Invalid todo item at index ${s}: each item must have non-empty content, valid status (pending|in_progress|completed|cancelled), and valid priority (high|medium|low).`,metadata:{error:!0}};const n=i;return await o.write(t,r,n),{title:`${d(n)} todos`,output:JSON.stringify({background:r,todos:n},null,2),metadata:{background:r,todos:n}}}}}function m(t){const o=new a;return{kind:"builtin",toolName:"todo_read",exposedName:"todo_read",concurrencyMode:"read",resourceKeys:()=>[{key:"runtime:todo",access:"read"}],description:l,inputSchema:{type:"object",properties:{},required:[]},async execute(){const e=await o.read(t);return{title:`${d(e.todos)} todos`,output:JSON.stringify({background:e.background,todos:e.todos},null,2),metadata:{background:e.background,todos:e.todos}}}}}export{m as createTodoReadTool,h as createTodoWriteTool};
22
22
 
@@ -0,0 +1,5 @@
1
+
2
+ export * from "./types.js";
3
+ export * from "./resource-lock.js";
4
+ export * from "./scheduler.js";
5
+ export * from "./observability.js";
@@ -0,0 +1,2 @@
1
+ export*from"./types.js";export*from"./resource-lock.js";export*from"./scheduler.js";export*from"./observability.js";
2
+
@@ -0,0 +1,46 @@
1
+
2
+ import type { ToolBatchMetrics, ToolConcurrencyMode, ToolLifecycle, ToolTrace } from "./types.js";
3
+
4
+ export declare const CONTENTION_THRESHOLD_MS = 5;
5
+ export declare class ToolTraceRecorder {
6
+ private readonly traces;
7
+ private readonly batchId;
8
+ private readonly batchQueuedAt;
9
+
10
+ private readonly clockOrigin;
11
+
12
+ private readonly createdAt;
13
+
14
+ private runningCount;
15
+ private maxConcurrentObserved;
16
+ constructor(batchId: string, now?: number);
17
+
18
+ register(input: {
19
+ toolCallId: string;
20
+ toolName: string;
21
+ mode: ToolConcurrencyMode;
22
+ resourceKeys: readonly string[];
23
+ queuedAt?: number;
24
+ }): void;
25
+
26
+ private now;
27
+
28
+ transition(toolCallId: string, status: ToolLifecycle, now?: number): void;
29
+
30
+ setError(toolCallId: string, error: string): void;
31
+ getTrace(toolCallId: string): ToolTrace | undefined;
32
+ list(): ToolTrace[];
33
+
34
+ finalize(endedAt?: number): ToolBatchMetrics;
35
+
36
+ formatSummary(): string;
37
+ }
38
+
39
+ export declare class ConcurrencyLimiter {
40
+ private readonly limit;
41
+ private available;
42
+ private readonly queue;
43
+ constructor(limit: number);
44
+ acquire(): Promise<() => void>;
45
+ private makeRelease;
46
+ }
@@ -0,0 +1,3 @@
1
+ const d=5;class m{constructor(t,e=Date.now()){this.traces=new Map,this.runningCount=0,this.maxConcurrentObserved=0,this.batchId=t,this.batchQueuedAt=e,this.clockOrigin=e,this.createdAt=Date.now()}register(t){this.traces.set(t.toolCallId,{toolCallId:t.toolCallId,toolName:t.toolName,mode:t.mode,resourceKeys:[...t.resourceKeys],queuedAt:t.queuedAt??this.now(),startedAt:null,completedAt:null,committedAt:null,waitDurationMs:null,executionDurationMs:null,status:"pending"})}now(){return this.clockOrigin+(Date.now()-this.createdAt)}transition(t,e,i=this.now()){const s=this.traces.get(t);if(s)switch(s.status=e,e){case"waiting_resource":break;case"running":s.startedAt=i,s.waitDurationMs=i-s.queuedAt,this.runningCount+=1,this.runningCount>this.maxConcurrentObserved&&(this.maxConcurrentObserved=this.runningCount);break;case"completed":case"failed":case"timeout":case"aborted":case"superseded":s.completedAt===null&&(s.completedAt=i,s.startedAt!==null&&(s.executionDurationMs=i-s.startedAt),this.runningCount>0&&(this.runningCount-=1));break;case"committing":case"committed":s.committedAt=i;break;default:break}}setError(t,e){const i=this.traces.get(t);i&&(i.error=e)}getTrace(t){return this.traces.get(t)}list(){return Array.from(this.traces.values())}finalize(t=Date.now()){const e=this.list();let i=0,s=0,o=0,n=0;for(const r of e)r.waitDurationMs!==null&&(i+=r.waitDurationMs,r.waitDurationMs>=5&&(s+=1)),r.executionDurationMs!==null&&(n+=r.executionDurationMs),(r.status==="failed"||r.status==="timeout"||r.status==="aborted")&&(o+=1);const a=Math.max(0,t-this.batchQueuedAt),l=a>0?n/a:0,c=Math.max(n,a),h=a>0?Math.min(c/a,Math.max(1,this.maxConcurrentObserved)):0;return{batchId:this.batchId,toolCount:e.length,parallelism:Number(l.toFixed(2)),speedup:Number(h.toFixed(2)),wallClockMs:a,totalWaitMs:i,contentionCount:s,failureCount:o,maxConcurrentObserved:this.maxConcurrentObserved,traces:e}}formatSummary(){return this.list().map(t=>{const e=t.waitDurationMs??0,i=t.executionDurationMs??0;return`${t.toolName} wait ${e}ms run ${i}ms ${t.status}`}).join(`
2
+ `)}}class f{constructor(t){this.limit=t,this.queue=[],this.available=t}async acquire(){return!Number.isFinite(this.limit)||this.limit<=0?()=>{}:this.available>0?(this.available-=1,this.makeRelease()):(await new Promise(t=>{this.queue.push(t)}),this.makeRelease())}makeRelease(){let t=!1;return()=>{if(t)return;t=!0;const e=this.queue.shift();if(e){e();return}this.available+=1}}}export{d as CONTENTION_THRESHOLD_MS,f as ConcurrencyLimiter,m as ToolTraceRecorder};
3
+
@@ -0,0 +1,25 @@
1
+
2
+ import { type ResourceAccess, type ResourceClaim } from "./types.js";
3
+ export declare class ResourceLock {
4
+ private readonly activeHolders;
5
+ private readonly writerQueue;
6
+ private readonly readerQueue;
7
+
8
+ acquire(claims: readonly ResourceClaim[], defaultAccess: ResourceAccess): Promise<() => void>;
9
+
10
+ hasWaiters(): boolean;
11
+
12
+ private canAcquireNow;
13
+
14
+ private conflictsWithActive;
15
+
16
+ private registerAndRelease;
17
+
18
+ private makeRelease;
19
+
20
+ private drain;
21
+ }
22
+
23
+ export declare function claimsConflict(left: ResourceClaim, right: ResourceClaim): boolean;
24
+
25
+ export declare function getSharedResourceLock(): ResourceLock;
@@ -0,0 +1,2 @@
1
+ import{normalizeResourceKey as l,resourceKeysOverlap as u}from"./types.js";let o=0;class d{constructor(){this.activeHolders=[],this.writerQueue=[],this.readerQueue=[]}async acquire(e,s){if(e.length===0)return()=>{};const r=f(e,s);if(this.canAcquireNow(r))return this.registerAndRelease(r);const t=r.every(c=>c.access==="read"),n=await new Promise(c=>{const a={id:++o,claims:r,resolve:()=>c(a.id)};t?this.readerQueue.push(a):this.writerQueue.push(a)});return this.makeRelease(n)}hasWaiters(){return this.writerQueue.length>0||this.readerQueue.length>0}canAcquireNow(e){return this.writerQueue.length>0||this.readerQueue.length>0?!1:!this.conflictsWithActive(e)}conflictsWithActive(e){for(const s of this.activeHolders)for(const r of s.claims)for(const t of e)if(u(r.key,t.key)&&(r.access!=="read"||t.access!=="read"))return!0;return!1}registerAndRelease(e){const s=++o;return this.activeHolders.push({id:s,claims:e}),this.makeRelease(s)}makeRelease(e){let s=!1;return()=>{if(s)return;s=!0;const r=this.activeHolders.findIndex(t=>t.id===e);r>=0&&this.activeHolders.splice(r,1),this.drain()}}drain(){for(;this.writerQueue.length>0;){const e=this.writerQueue[0];if(this.conflictsWithActive(e.claims))return;this.writerQueue.shift(),this.activeHolders.push({id:e.id,claims:e.claims}),e.resolve()}for(;this.readerQueue.length>0;){const e=this.readerQueue[0];if(this.conflictsWithActive(e.claims))return;this.readerQueue.shift(),this.activeHolders.push({id:e.id,claims:e.claims}),e.resolve()}}}function v(i,e){return u(i.key,e.key)?i.access!=="read"||e.access!=="read":!1}function f(i,e){const s=new Map;for(const r of i){const t=l(r.key),n=r.access??e,c=s.get(t);(c===void 0||h(n)>h(c))&&s.set(t,n)}return Array.from(s.entries()).map(([r,t])=>({key:r,access:t})).sort((r,t)=>r.key<t.key?-1:r.key>t.key?1:0)}function h(i){switch(i){case"read":return 0;case"write":return 1;case"exclusive":return 2}}const m=new d;function y(){return m}export{d as ResourceLock,v as claimsConflict,y as getSharedResourceLock};
2
+
@@ -0,0 +1,30 @@
1
+
2
+ import { type ResourceScope, type ToolConcurrencyMode, type ToolConcurrencyPlan, type ResourceClaim } from "./types.js";
3
+
4
+ export interface ToolScheduleInput {
5
+ toolCallId: string;
6
+
7
+ toolName: string;
8
+
9
+ mode: ToolConcurrencyMode;
10
+
11
+ scope?: ResourceScope;
12
+
13
+ claims: readonly ResourceClaim[];
14
+ }
15
+
16
+ export interface ToolWave {
17
+ index: number;
18
+
19
+ planIds: string[];
20
+
21
+ blocking: boolean;
22
+ }
23
+ export interface ToolScheduleResult {
24
+ plans: Map<string, ToolConcurrencyPlan>;
25
+ waves: ToolWave[];
26
+ }
27
+ export declare class ToolConcurrencyScheduler {
28
+
29
+ schedule(inputs: readonly ToolScheduleInput[]): ToolScheduleResult;
30
+ }
@@ -0,0 +1,2 @@
1
+ import{claimsConflict as d}from"./resource-lock.js";import{normalizeResourceKey as p}from"./types.js";class h{schedule(c){const l=new Map;for(const o of c)l.set(o.toolCallId,{toolCallId:o.toolCallId,toolName:o.toolName,mode:o.mode,scope:o.scope??"exact",claims:k(o)});const s=c.filter(o=>o.mode!=="blocking"),t=c.filter(o=>o.mode==="blocking"),n=[],a=[];for(const o of s){const r=l.get(o.toolCallId);let f=!1;for(const m of a)if(!m.some(u=>C(l.get(u.toolCallId),r))){m.push(o),f=!0;break}f||a.push([o])}let i=0;for(const o of a)n.push({index:i++,planIds:o.map(r=>r.toolCallId),blocking:!1});for(const o of t)n.push({index:i++,planIds:[o.toolCallId],blocking:!0});return{plans:l,waves:n}}}function C(e,c){if(e.claims.length===0||c.claims.length===0)return!0;for(const l of e.claims)for(const s of c.claims)if(d(l,s))return!0;return!1}function k(e){const c=e.mode==="blocking"||e.mode==="exclusive"?"exclusive":e.mode,l=new Map;for(const s of e.claims){const t=p(s.key);l.set(t,{key:t,access:s.access??c})}return Array.from(l.values())}export{h as ToolConcurrencyScheduler};
2
+
@@ -0,0 +1,80 @@
1
+
2
+
3
+ export type ResourceAccess = "read" | "write" | "exclusive";
4
+
5
+ export type ToolConcurrencyMode = ResourceAccess | "blocking";
6
+
7
+ export type ResourceScope = "exact" | "workspace" | "unknown";
8
+
9
+ export interface ResourceClaim {
10
+
11
+ key: string;
12
+
13
+ access?: ResourceAccess;
14
+ }
15
+
16
+ export interface ToolConcurrencyDeclaration {
17
+
18
+ concurrencyMode?: ToolConcurrencyMode;
19
+
20
+ resourceScope?: ResourceScope;
21
+ }
22
+
23
+ export interface ToolConcurrencyPlan {
24
+ toolCallId: string;
25
+ toolName: string;
26
+ mode: ToolConcurrencyMode;
27
+ scope: ResourceScope;
28
+
29
+ claims: ResourceClaim[];
30
+ }
31
+
32
+ export type ToolLifecycle = "pending" | "precheck" | "waiting_resource" | "running" | "completed" | "failed" | "timeout" | "aborted" | "superseded" | "committing" | "committed";
33
+
34
+ export interface ToolTrace {
35
+ toolCallId: string;
36
+ toolName: string;
37
+ mode: ToolConcurrencyMode;
38
+ resourceKeys: string[];
39
+
40
+ queuedAt: number;
41
+
42
+ startedAt: number | null;
43
+
44
+ completedAt: number | null;
45
+
46
+ committedAt: number | null;
47
+
48
+ waitDurationMs: number | null;
49
+
50
+ executionDurationMs: number | null;
51
+ status: ToolLifecycle;
52
+ error?: string;
53
+ }
54
+
55
+ export interface ToolBatchMetrics {
56
+ batchId: string;
57
+ toolCount: number;
58
+
59
+ parallelism: number;
60
+
61
+ speedup: number;
62
+
63
+ wallClockMs: number;
64
+
65
+ totalWaitMs: number;
66
+
67
+ contentionCount: number;
68
+
69
+ failureCount: number;
70
+ maxConcurrentObserved: number;
71
+ traces: ToolTrace[];
72
+ }
73
+
74
+ export declare function resourceAncestors(key: string): string[];
75
+
76
+ export declare function resourceIsAncestorOrSelf(ancestor: string, descendant: string): boolean;
77
+
78
+ export declare function resourceKeysOverlap(left: string, right: string): boolean;
79
+
80
+ export declare function normalizeResourceKey(key: string, platform?: NodeJS.Platform): string;
@@ -0,0 +1,2 @@
1
+ function p(r){const n=[r],e=r.indexOf(":");if(e<0)return n;const t=r.slice(0,e),c=r.slice(e+1);if(t!=="file"&&t!=="dir"&&t!=="workspace")return n;const a=u(c).split("/").filter(o=>o.length>0);let s="";for(let o=0;o<a.length-1;o++)s+=`/${a[o]}`,n.push(`dir:${s}`);const l=s.length>0?s:"/";return n.push(`workspace:${l}`),n.push("workspace:/"),f(n)}function i(r,n){return p(n).includes(r)}function h(r,n){return i(r,n)||i(n,r)}function m(r,n=process.platform){const e=r.indexOf(":");if(e<0)return r;const t=r.slice(0,e).toLowerCase(),c=u(r.slice(e+1),n);return`${t}:${c}`}function u(r,n=process.platform){let e=r.replace(/\\/g,"/").replace(/\/+/g,"/");return/^[a-zA-Z]:/.test(e)&&(e=e.charAt(0).toLowerCase()+e.slice(1)),e.length>1&&e.endsWith("/")&&(e=e.replace(/\/+$/,"")),n==="win32"?e.toLowerCase():e}function f(r){const n=new Set,e=[];for(const t of r)n.has(t)||(n.add(t),e.push(t));return e}export{m as normalizeResourceKey,p as resourceAncestors,i as resourceIsAncestorOrSelf,h as resourceKeysOverlap};
2
+
@@ -0,0 +1,116 @@
1
+
2
+ import type { ACodeBuiltInTool, JsonObject } from "./built-in-file-tools.js";
3
+ import type { ACodePluginBridge } from "./plugin-types.js";
4
+ export type CapabilityState = "disabled" | "collapsed" | "expanded";
5
+ export interface ToolGroupRegistration {
6
+
7
+ key: string;
8
+
9
+ label: string;
10
+
11
+ summary: string;
12
+
13
+ collapsible: boolean;
14
+
15
+ toolNames?: readonly string[];
16
+ }
17
+ export interface ToolGroupManagerOptions {
18
+
19
+ stateOf: (key: string) => CapabilityState | undefined;
20
+ }
21
+ export declare class ToolGroupManager {
22
+ private groups;
23
+ private expandedGroups;
24
+ private stateOf;
25
+ constructor(options: ToolGroupManagerOptions);
26
+ register(def: ToolGroupRegistration): void;
27
+ unregister(key: string): void;
28
+ getRegistration(key: string): ToolGroupRegistration | undefined;
29
+
30
+ getAllGroups(): readonly ToolGroupRegistration[];
31
+
32
+ getConfigState(key: string): CapabilityState;
33
+
34
+ isEnabled(key: string): boolean;
35
+ isExpanded(key: string): boolean;
36
+
37
+ expand(key: string): number;
38
+
39
+ collapse(key: string): number;
40
+
41
+ resetExpanded(): void;
42
+
43
+ shouldShowToLLM(groupKey: string | undefined): boolean;
44
+
45
+ getGroupForExposedName(exposedName: string): string | undefined;
46
+
47
+ shouldShowToLLMByName(exposedName: string): boolean;
48
+
49
+ listToolManifests(key: string, tools: ReadonlyArray<{
50
+ exposedName: string;
51
+ description?: string;
52
+ inputSchema?: unknown;
53
+ }>): Array<{
54
+ name: string;
55
+ description?: string;
56
+ inputSchema?: unknown;
57
+ }>;
58
+
59
+ buildCapabilityPrompt(): string;
60
+
61
+ registerFromMeta(groupKey: string, label?: string, summary?: string, toolName?: string): void;
62
+
63
+ addToolName(groupKey: string, toolName: string): void;
64
+ }
65
+
66
+ export interface CapabilityToolRelay {
67
+
68
+ handlesGroup(group: string): boolean;
69
+
70
+ handlesTool(toolName: string): boolean;
71
+
72
+ expand(group: string): Promise<Array<{
73
+ name: string;
74
+ description?: string;
75
+ inputSchema?: unknown;
76
+ }>>;
77
+
78
+ collapse(group: string): Promise<void>;
79
+
80
+ call(toolName: string, args: JsonObject): Promise<{
81
+ ok: boolean;
82
+ result?: unknown;
83
+ error?: string;
84
+ }>;
85
+ }
86
+ export interface ExpandToolsDeps {
87
+ toolGroupManager: ToolGroupManager;
88
+
89
+ getAllTools: () => ReadonlyArray<{
90
+ exposedName: string;
91
+ description?: string;
92
+ inputSchema?: unknown;
93
+ }>;
94
+
95
+ capabilityToolRelay?: CapabilityToolRelay;
96
+ }
97
+
98
+ export declare function createExpandToolsTool(deps: ExpandToolsDeps): ACodeBuiltInTool;
99
+ export interface CallToolDeps {
100
+ toolGroupManager: ToolGroupManager;
101
+ pluginBridge?: ACodePluginBridge;
102
+
103
+ findTool: (exposedName: string) => {
104
+ kind: "mcp" | "builtin";
105
+ group?: string;
106
+ toolName: string;
107
+ } | undefined;
108
+
109
+ dispatchTool: (toolName: string, args: JsonObject, context?: {
110
+ toolCallId?: string;
111
+ }) => Promise<unknown>;
112
+
113
+ capabilityToolRelay?: CapabilityToolRelay;
114
+ }
115
+
116
+ export declare function createCallToolTool(deps: CallToolDeps): ACodeBuiltInTool;
@@ -0,0 +1,14 @@
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?"":`
3
+
4
+ \u5F53\u524D\u53EF\u5C55\u5F00\u7684\u6536\u7EB3\u7EC4\uFF1A
5
+ `+r.join(`
6
+ `)};return{kind:"builtin",toolName:"expand_tools",exposedName:"expand_tools",description:'\u5C55\u5F00/\u6536\u8D77\u6536\u7EB3\u5DE5\u5177\u7EC4\u3002\u6536\u7EB3\u7EC4\u7684\u5DE5\u5177\u9ED8\u8BA4\u4E0D\u51FA\u73B0\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
7
+
8
+ \u63D2\u4EF6\u5DE5\u5177\u6A21\u5F0F\uFF08\u53EF\u9009\u63D2\u4EF6\uFF09\uFF1A
9
+ - action="catalog"\uFF1A\u8FD4\u56DE\u5F53\u524D\u5168\u90E8\u63D2\u4EF6\u76EE\u5F55\uFF08\u7D27\u51D1\uFF09
10
+ - action="schema" + tool="\u63D2\u4EF6\u540D.\u5DE5\u5177\u540D"\uFF1A\u8FD4\u56DE\u8BE5\u5DE5\u5177\u7684\u5B8C\u6574 inputSchema
11
+ - action="call"\uFF08\u9ED8\u8BA4\uFF09+ name="\u63D2\u4EF6\u540D.\u5DE5\u5177\u540D" + arguments={...}\uFF1A\u8C03\u7528\u63D2\u4EF6\u5DE5\u5177
12
+
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};
14
+