@alvin0/ai-agent-sdk-core 0.1.4 → 0.1.5

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 (105) hide show
  1. package/README.md +13 -1
  2. package/dist/agent/define/definition.d.ts +1 -1
  3. package/dist/agent/define/definition.js +1 -1
  4. package/dist/agent/define/definition.js.map +1 -1
  5. package/dist/agent/define/session/types.d.ts +6 -0
  6. package/dist/agent/define/session/types.d.ts.map +1 -1
  7. package/dist/agent/define/session.d.ts +25 -2
  8. package/dist/agent/define/session.d.ts.map +1 -1
  9. package/dist/agent/define/session.js +1 -1
  10. package/dist/agent/define/session.js.map +1 -1
  11. package/dist/agent/loop/admission.js +2 -0
  12. package/dist/agent/loop/admission.js.map +1 -0
  13. package/dist/agent/loop/events.d.ts +4 -0
  14. package/dist/agent/loop/events.d.ts.map +1 -1
  15. package/dist/agent/loop/program.js +2 -0
  16. package/dist/agent/loop/program.js.map +1 -0
  17. package/dist/agent/loop/run-turn.d.ts.map +1 -1
  18. package/dist/agent/loop/run-turn.js +1 -1
  19. package/dist/agent/loop/run-turn.js.map +1 -1
  20. package/dist/agent/loop/schedule.d.ts.map +1 -1
  21. package/dist/agent/loop/schedule.js +2 -2
  22. package/dist/agent/loop/schedule.js.map +1 -1
  23. package/dist/agent/loop/tool-call-support.js +2 -0
  24. package/dist/agent/loop/tool-call-support.js.map +1 -0
  25. package/dist/agent/loop/turn/hooks.js +1 -1
  26. package/dist/agent/loop/turn/hooks.js.map +1 -1
  27. package/dist/agent/loop/turn/model-request-boundary.js +2 -0
  28. package/dist/agent/loop/turn/model-request-boundary.js.map +1 -0
  29. package/dist/agent/loop/turn/model-round.js +1 -1
  30. package/dist/agent/loop/turn/model-round.js.map +1 -1
  31. package/dist/agent/loop/turn/step-projection.js +2 -0
  32. package/dist/agent/loop/turn/step-projection.js.map +1 -0
  33. package/dist/agent/loop/turn/types.d.ts +6 -0
  34. package/dist/agent/loop/turn/types.d.ts.map +1 -1
  35. package/dist/agent/memory/context-optimizer.d.ts +61 -0
  36. package/dist/agent/memory/context-optimizer.d.ts.map +1 -0
  37. package/dist/agent/memory/context-optimizer.js +4 -0
  38. package/dist/agent/memory/context-optimizer.js.map +1 -0
  39. package/dist/agent/memory/memory.js +1 -1
  40. package/dist/agent/memory/memory.js.map +1 -1
  41. package/dist/agent/mode/run-agent.d.ts +15 -1
  42. package/dist/agent/mode/run-agent.d.ts.map +1 -1
  43. package/dist/agent/mode/run-agent.js +2 -2
  44. package/dist/agent/mode/run-agent.js.map +1 -1
  45. package/dist/agent/skill/provider/snapshot.js +1 -1
  46. package/dist/agent/team/managed.d.ts +33 -64
  47. package/dist/agent/team/managed.d.ts.map +1 -1
  48. package/dist/agent/team/managed.js +6 -3
  49. package/dist/agent/team/managed.js.map +1 -1
  50. package/dist/agent/team/team.d.ts +2 -0
  51. package/dist/agent/team/team.d.ts.map +1 -1
  52. package/dist/agent/team/team.js +1 -1
  53. package/dist/agent/team/team.js.map +1 -1
  54. package/dist/agent/team/types.d.ts +1 -0
  55. package/dist/agent/team/types.d.ts.map +1 -1
  56. package/dist/agent/tool/action-fusion.d.ts +30 -0
  57. package/dist/agent/tool/action-fusion.d.ts.map +1 -0
  58. package/dist/agent/tool/action-fusion.js +2 -0
  59. package/dist/agent/tool/action-fusion.js.map +1 -0
  60. package/dist/agent/tool/capture.js +1 -1
  61. package/dist/agent/tool/capture.js.map +1 -1
  62. package/dist/agent/tool/definition.d.ts +8 -0
  63. package/dist/agent/tool/definition.d.ts.map +1 -1
  64. package/dist/agent/tool/definition.js.map +1 -1
  65. package/dist/agent/tool/evidence-reducer.d.ts +41 -0
  66. package/dist/agent/tool/evidence-reducer.d.ts.map +1 -0
  67. package/dist/agent/tool/evidence-reducer.js +7 -0
  68. package/dist/agent/tool/evidence-reducer.js.map +1 -0
  69. package/dist/agent/tool/nested.d.ts +117 -0
  70. package/dist/agent/tool/nested.d.ts.map +1 -0
  71. package/dist/agent/tool/nested.js +2 -0
  72. package/dist/agent/tool/nested.js.map +1 -0
  73. package/dist/agent/tool/output-budget.d.ts.map +1 -1
  74. package/dist/agent/tool/output-budget.js +2 -2
  75. package/dist/agent/tool/output-budget.js.map +1 -1
  76. package/dist/agent/tool/output-schema.js +2 -0
  77. package/dist/agent/tool/output-schema.js.map +1 -0
  78. package/dist/agent/tool/pipeline.d.ts +7 -0
  79. package/dist/agent/tool/pipeline.d.ts.map +1 -1
  80. package/dist/agent/tool/pipeline.js +2 -2
  81. package/dist/agent/tool/pipeline.js.map +1 -1
  82. package/dist/agent/tool/program-results.js +2 -0
  83. package/dist/agent/tool/program-results.js.map +1 -0
  84. package/dist/agent.d.ts +6 -2
  85. package/dist/agent.js +1 -1
  86. package/dist/composition/agent/definition.js +1 -1
  87. package/dist/composition/agent/options.js +1 -1
  88. package/dist/composition/agent/options.js.map +1 -1
  89. package/dist/composition/agent/session.js +1 -1
  90. package/dist/composition/agent/session.js.map +1 -1
  91. package/dist/composition/agent/types.d.ts +6 -0
  92. package/dist/composition/agent/types.d.ts.map +1 -1
  93. package/dist/composition/tool-source/snapshot.js +1 -1
  94. package/dist/index.d.ts +2 -1
  95. package/dist/index.js +1 -1
  96. package/dist/memory.d.ts +2 -1
  97. package/dist/memory.js +1 -1
  98. package/dist/observability/bus.js +1 -1
  99. package/dist/primitives/version.d.ts +1 -1
  100. package/dist/primitives/version.js +1 -1
  101. package/dist/primitives/version.js.map +1 -1
  102. package/dist/runtime/registry.js +1 -1
  103. package/dist/tools.d.ts +4 -1
  104. package/dist/tools.js +1 -1
  105. package/package.json +1 -1
@@ -1,4 +1,7 @@
1
- import{waitForSettlement as e}from"../../async/settlement.js";import{timeoutValue as t}from"../../platform/config.js";import{createTextMessage as n}from"../../message/message.js";import{defineTool as r}from"../tool/definition.js";import{ToolRegistry as i}from"../tool/registry.js";import{History as a}from"../history/history.js";import{cloneAgent as o}from"../define/definition.js";import"./common.js";import{AgentTeam as s}from"./team.js";const c=3e4,l=3e4,u=15e3,d=[`You lead a managed dynamic team. Delegation buys parallelism; it is not a way to distribute a task you have not yet understood.`,`PLAN BEFORE YOU DELEGATE. State briefly what the objective needs, which steps block the others, and which can run alongside them, and decide what you will do yourself right now. Only then spawn.`,`Do the blocking step yourself. If your very next action depends on a result, producing it locally is faster than delegating it and waiting for it.`,`Delegate work that runs alongside your own: concrete, bounded, self-contained, and worth a whole worker.`,"GIVE EACH WORKER A DISJOINT SET OF FILES TO WRITE. Declare them in `writes`, and say which in its task. Two workers building different features of one file will each write that file, and the later write erases the earlier one; a spawn that would do this is refused.",'A WORKER THAT ONLY READS DECLARES NOTHING: leave `writes` out. Do not invent a placeholder such as "none" or "/tmp/no-write" — that claims a real scope, and several readers sharing one stand-in are refused for colliding over a file none of them writes.',"EXPRESS ORDER WITH `dependsOn`, NOT BY SPAWNING LATE. A worker that reviews, integrates, or builds on another names it there: it is created now, held until that work settles, and then given what it produced. Spawn the whole plan in one step and let the order be enforced rather than remembered.","Do not delegate review, audit or verification against nothing. Either the thing to be reviewed already exists, or the reviewer `dependsOn` whoever is producing it. A reviewer started over an empty workspace produces a checklist, not a review.",`When the work does not exist yet, the first step is yours: establish its shape — scaffold, layout, shared types — and then delegate the independent pieces of it.`,`Choose each worker context deliberately: fork when it needs what you have already found out, fresh when its task genuinely stands alone. Given neither, every worker rediscovers the workspace for itself.`,`Call spawn_agent several times in one step for work that is genuinely independent, and once for work that is not.`,`spawn_agent does not return a result: workers run while you keep working, and each one reports back to you when it finishes.`,`After delegating, do useful non-overlapping work. Do not wait by reflex, and do not redo what you delegated.`,`Use wait_agents only when you need a result to continue. It returns within its timeout whether or not anyone finished, so read the reported status and decide again.`,`Read a finished worker result from list_agents, then call close_agent to release its slot.`,`A send_message update or accepted self-check is not the worker final report. Wait for its completed/failed status before normal closure. Use cancelRunning only when deliberately abandoning its unfinished work.`,`Never answer as if a worker had reported when it has not; say what is still outstanding instead.`,`Synthesize worker results yourself and remain responsible for the final answer.`].join(` `);var f=class{team;lead;leadName;options;maxWorkers;maxTaskBytes;maxSpecialtyBytes;workerTimeoutMs;observerTimeoutMs;closeTimeoutMs;holdWaitMs;spawnTimeoutMs;workerRuntimes=new Map;reservedNames=new Set;workerSequence=0;maxDependencyReportBytes;roles;constructor(e){if(this.options=e,this.maxWorkers=w(e.maxWorkers??7,`maxWorkers`),this.maxTaskBytes=w(e.maxTaskBytes??65536,`maxTaskBytes`),this.maxSpecialtyBytes=w(e.maxSpecialtyBytes??8192,`maxSpecialtyBytes`),this.workerTimeoutMs=t(e.workerTimeoutMs??6e5),this.observerTimeoutMs=t(e.observerTimeoutMs??1e3),this.closeTimeoutMs=t(e.closeTimeoutMs??3e4),this.holdWaitMs=t(e.holdWaitMs??15e3),this.spawnTimeoutMs=t(e.spawnTimeoutMs??3e4),this.maxDependencyReportBytes=w(e.maxDependencyReportBytes??8192,`maxDependencyReportBytes`),this.roles=new Map((e.roles??[]).map(e=>[e.name,e])),this.roles.size!==(e.roles??[]).length)throw Error(`managed agent roles contain a duplicate name`);this.team=e.team instanceof s?e.team:new s({...e.team,maxMembers:e.team?.maxMembers??this.maxWorkers+1}),this.leadName=x(e.leadName??e.lead.id),this.lead=e.lead.createSession({...e.leadSessionOptions,hooks:this.leadHooks(e.leadSessionOptions?.hooks),registry:e.registry,tools:m(e.leadSessionOptions?.tools,this.controlTools()),team:{team:this.team,name:this.leadName,role:`lead`,instructions:d,...e.leadDescription===void 0?{}:{description:e.leadDescription}}})}leadHooks(e){return{...e,beforeStep:async t=>(this.unreadReports=!1,await e?.beforeStep?.(t)??{kind:`proceed`}),onTurnEnd:async t=>{if(await e?.onTurnEnd?.(t),!t.canContinue){if(this.unreadReports){this.unreadReports=!1;try{this.team.wake(this.leadName)}catch{}}return}let n=[...this.workerRuntimes.values()].filter(e=>e.status===`running`||e.status===`pending`);if(n.length===0)return;await this.awaitWorkerNews(n);let r=[...this.workerRuntimes.values()].filter(e=>e.status===`running`||e.status===`pending`).map(e=>e.request.name);if(r.length===0){this.lead.inject(`Every worker has reported. Read their results and write the answer you owe the user; do not delegate again unless something is genuinely missing.`);return}this.lead.inject(`Not finished: ${r.join(`, `)} ${r.length===1?`is`:`are`} still running. Use wait_agents to wait for them and read their results, or close_agent with cancelRunning: true to give up on one. Do not present a conclusion that depends on work they have not reported yet.`)}}}run(e,t={}){return this.lead.run(e,t)}steer(e){this.lead.inject(e);try{this.team.notifySteer(this.leadName)}catch{}if(!this.lead.isRunning)try{this.team.wake(this.leadName)}catch{}return!0}async spawn(e,t){t?.throwIfAborted();let r={name:x(e.name??this.nextWorkerName()),task:C(e.task,`worker task`,this.maxTaskBytes),...e.specialty===void 0?{}:{specialty:C(e.specialty,`worker specialty`,this.maxSpecialtyBytes)},context:e.context??this.options.defaultSpawnContext??`fresh`,...e.role===void 0?{}:{role:this.requireRole(e.role)},dependsOn:this.resolveDependencies(e.dependsOn??[]),writes:[...new Set((e.writes??[]).map(j))]};if(this.workerRuntimes.size+this.reservedNames.size>=this.maxWorkers)throw Error(`managed agent team reached its ${this.maxWorkers}-worker limit`);if(this.reservedNames.has(r.name)||this.workerRuntimes.has(r.name)||this.team.members().some(e=>e.name===r.name))throw Error(`managed worker '${r.name}' already exists`);this.reservedNames.add(r.name);let i;try{let e=this.checkWriteScopes(r),a=D(t,AbortSignal.timeout(this.workerTimeoutMs)),o=await E(this.workerDefinition(r),a);a.throwIfAborted();let s=this.options.workerSessionOptionsFactory===void 0?void 0:await E(Promise.resolve(this.options.workerSessionOptionsFactory(r)),a);a.throwIfAborted();let c=o.createSession({...this.options.workerSessionOptions,...s,...r.context===`fork`?{history:this.forkLeadHistory()}:{},registry:this.options.registry,team:{team:this.team,name:r.name,role:`peer`,tools:`reporting`,instructions:[`You are a dynamically created worker reporting to '${this.leadName}'.`,`Complete the delegated task independently and return a concise evidence-backed result.`,`Do not broaden the task or attempt to become team lead.`,`Your result is delivered to '${this.leadName}' when you finish, so do not use send_message to report it; that tool is only for passing context to a DIFFERENT worker, never to yourself.`,`If you lack information, state what is missing in your result rather than waiting for an answer.`].join(` `),...r.specialty===void 0?{}:{description:r.specialty}}}),l=new AbortController,u;if(i={request:r,session:c,status:`pending`,leadDriven:this.lead.isRunning,closing:!1,deadline:void 0,controller:l,settled:new Promise(e=>{u=e}),markSettled:u,start:void 0,warnings:e,result:void 0,error:void 0},this.workerRuntimes.set(r.name,i),this.reservedNames.delete(r.name),await this.team.sendMessage({from:this.leadName,target:r.name,message:r.task,delivery:`quiet`,signal:a}),o.memory.autoCaptureObjective&&c.memory.captureOriginalObjective(n(r.task)),r.dependsOn.length>0&&!this.dependenciesSettled(r.dependsOn)){let e=new Promise(e=>{i.start=e});return this.team.markPending(r.name,e),this.workerView(i)}return this.beginWorker(i),this.workerView(i)}catch(e){throw i!==void 0&&(i.status=`failed`,i.error=T(e),i.start=void 0,i.markSettled()),e}finally{this.reservedNames.delete(r.name)}}beginWorker(e){let t=e.request.name;if(e.start?.(),e.start=void 0,this.team.markPending(t,void 0),e.status!==`pending`)return;e.status=`running`;let n=AbortSignal.timeout(this.workerTimeoutMs);e.deadline=n;let r=e.session.runPending({signal:D(e.controller.signal,n),...this.options.onWorkerEvent===void 0?{}:{onEvent:e=>this.observeWorkerEvent(t,e)}});this.followWorker(e,r)}roleSchema(){if(this.roles.size===0)return{};let e=[...this.roles.values()].map(e=>`- ${e.name}: ${e.description}`+(e.whenToUse===void 0?``:` Use when: ${e.whenToUse}`));return{role:{type:`string`,enum:[...this.roles.keys()],description:`Which kind of worker this is.\n${e.join(`
2
- `)}`}}}requireRole(e){let t=S(e,`worker role`);if(this.roles.size===0)throw Error(`this managed team declares no roles, so spawn_agent takes no role`);if(!this.roles.has(t))throw Error(`unknown worker role '${t}'; declared roles are ${[...this.roles.keys()].join(`, `)}`);return t}resolveDependencies(e){return[...new Set(e.map(e=>{let t=x(e);if(!this.workerRuntimes.has(t))throw Error(`unknown dependency '${t}'; a worker can only depend on one that already exists`);return t}))]}checkWriteScopes(e){let t=this.options.writeScopePolicy??`reject`;if(t===`off`||e.writes.length===0)return[];let n=this.ancestorsOf(e.dependsOn),r=[];for(let i of this.workerRuntimes.values()){if(i.status!==`pending`&&i.status!==`running`||n.has(i.request.name))continue;let a=e.writes.filter(e=>i.request.writes.some(t=>M(e,t)));if(a.length===0)continue;let o=`'${i.request.name}' also writes ${a.join(`, `)}`;if(t===`reject`)throw Error(`worker '${e.name}' would write files another running worker writes: ${o}. Add '${i.request.name}' to dependsOn so it runs after, or narrow the scopes — or omit writes entirely if this worker only reads.`);r.push(o)}return r}describeWorkerFailure(e,t){if(t?.deadline?.aborted===!0)return this.deadlineFailure();let n=e?.name;return n===`TimeoutError`?this.deadlineFailure():n===`AbortError`?`its work was cancelled before it finished`:T(e)}deadlineFailure(){return`it ran past its ${String(this.workerTimeoutMs)}ms deadline without finishing. Narrow the task, or split it, before delegating it again`}async awaitWorkerNews(e){let t,n=new Promise(e=>{t=setTimeout(e,this.holdWaitMs),t.unref?.()});try{await Promise.race([...e.map(e=>e.settled),n])}finally{t!==void 0&&clearTimeout(t)}}ancestorsOf(e,t=new Set){for(let n of e){if(t.has(n))continue;t.add(n);let e=this.workerRuntimes.get(n);e!==void 0&&this.ancestorsOf(e.request.dependsOn,t)}return t}dependenciesSettled(e){return e.every(e=>{let t=this.workerRuntimes.get(e);return t===void 0||k.has(t.status)})}async releaseDependents(e){let t=[...this.workerRuntimes.values()].filter(t=>t.status===`pending`&&t.request.dependsOn.includes(e)&&this.dependenciesSettled(t.request.dependsOn));for(let e of t){let t=this.dependencyReport(e.request.dependsOn);if(t!==void 0)try{await this.team.sendMessage({from:this.leadName,target:e.request.name,message:t,delivery:`quiet`})}catch{}this.beginWorker(e)}}dependencyReport(e){let t=e.map(e=>{let t=this.workerRuntimes.get(e);if(t===void 0)return`- ${e}: closed before reporting.`;if(t.error!==void 0){let n=t.result?.text;return`- ${e} FAILED: ${t.error}`+(n?`\nPartial findings (not a completed task): ${N(n,this.maxDependencyReportBytes)}`:``)}return`- ${e} finished: ${N(t.result?.text??``,this.maxDependencyReportBytes)}`});if(t.length!==0)return[`Work you depend on has finished. Its results follow; build on them rather than redoing them.`,...t].join(`
3
- `)}async followWorker(e,t){let n=e.request.name;try{let r=await t;if(e.status!==`closed`&&!e.closing){let t=e.deadline?.aborted===!0?this.deadlineFailure():A(r);t===void 0?(e.status=`completed`,e.result=Object.freeze({worker:n,agentId:e.session.definition.id,conversationId:e.session.conversationId,text:r.text,succeeded:r.outcome.completed}),this.team.recordOutcome(n,{kind:`completed`,text:r.text}),await this.notifyLead(n,`finished: ${r.text}`)):(e.status=`failed`,e.error=t,r.text.trim()!==``&&(e.result=Object.freeze({worker:n,agentId:e.session.definition.id,conversationId:e.session.conversationId,text:r.text,succeeded:!1})),this.team.recordOutcome(n,{kind:`failed`,message:t}),await this.notifyLead(n,`failed: ${t}`+(e.result===void 0?``:`\nPartial findings (not a completed task): ${e.result.text}`)))}}catch(t){e.status!==`closed`&&!e.closing&&(e.status=`failed`,e.error=this.describeWorkerFailure(t,e),this.team.recordOutcome(n,{kind:`failed`,message:e.error}),await this.notifyLead(n,`failed: ${e.error}`))}finally{e.markSettled(),await this.releaseDependents(n)}}async notifyLead(e,t){let n=this.deliveryFor(e);n===`quiet`&&(this.unreadReports=!0);try{await this.team.sendMessage({from:e,target:this.leadName,message:`Worker '${e}' ${t}`,delivery:n})}catch{}}deliveryFor(e){return this.lead.isRunning||this.workerRuntimes.get(e)?.leadDriven!==!0?`quiet`:`wakeup`}unreadReports=!1;async whenQuiet(e){for(;;){e?.throwIfAborted();let t=[...this.workerRuntimes.values()].filter(e=>e.status===`pending`||e.status===`running`);if(t.length>0&&await Promise.all(t.map(e=>e.settled)),await this.team.whenIdle(this.leadName,e),![...this.workerRuntimes.values()].some(e=>e.status===`pending`||e.status===`running`))return}}workers(){return Object.freeze([...this.workerRuntimes.values()].map(e=>this.workerView(e)))}workerView(e){return Object.freeze({name:e.request.name,agentId:e.session.definition.id,conversationId:e.session.conversationId,task:e.request.task,status:e.status,context:e.request.context,dependsOn:e.request.dependsOn,writes:e.request.writes,...e.request.role===void 0?{}:{role:e.request.role},...e.warnings.length===0?{}:{warnings:e.warnings},...e.request.specialty===void 0?{}:{specialty:e.request.specialty},...e.result===void 0?{}:{result:e.result},...e.error===void 0?{}:{error:e.error}})}async awaitWorker(e,n={}){let r=x(e),i=this.workerRuntimes.get(r);if(i===void 0)throw Error(`unknown managed worker '${r}'`);let a=t(n.timeoutMs??3e4),o,s=new Promise(e=>{o=setTimeout(e,a)});try{await Promise.race([i.settled,s])}finally{clearTimeout(o)}return n.signal?.throwIfAborted(),i.result}async closeWorker(t,n=Error(`managed worker closed`)){let r=x(t),i=this.workerRuntimes.get(r);if(i===void 0)throw Error(`unknown managed worker '${r}'`);let a=i.status;i.closing=!0,i.controller.abort(n);try{await this.team.cancel(r,n)}catch{}a===`pending`?(i.status=`closed`,i.start=void 0,this.team.markPending(r,void 0),i.markSettled()):(await e(i.settled,this.closeTimeoutMs),i.status=`closed`),this.workerRuntimes.delete(r);try{this.team.detach(r)}catch{}return await this.releaseDependents(r),a}async dispose(e=Error(`managed agent team disposed`)){let t=[...this.workerRuntimes.keys()];await Promise.allSettled(t.map(t=>this.closeWorker(t,e)))}removeWorker(e){let t=x(e),n=this.workerRuntimes.get(t);if(n===void 0)throw Error(`unknown managed worker '${t}'`);if(n.status===`running`||n.session.isRunning)throw Error(`cannot remove running managed worker '${t}'`);this.team.detach(t),this.workerRuntimes.delete(t)}controlTools(){return Object.freeze([r({name:`spawn_agent`,description:[`Create a connected specialist worker and start one task on it.`,`Returns as soon as the worker is running, WITHOUT its result: keep working,`,`and you will be told when it finishes. Use wait_agents to pause for it,`,`list_agents to read its status and result, and close_agent when done with it.`,`Before the first call, plan: name the step that blocks the others and do that`,`one yourself. Then spawn the rest of the plan in one step: declare each`,"worker's `writes` so two never write the same file, and use `dependsOn` for",`anything that must follow another worker rather than waiting to spawn it.`].join(` `),parameters:{type:`object`,properties:{name:{type:`string`,description:`Optional unique worker address; omitted generates worker_N.`},task:{type:`string`,description:`Concrete bounded task assigned to the worker. State which files it owns and may write, so two workers never write the same one.`},specialty:{type:`string`,description:`Optional worker role or domain specialization.`},context:{type:`string`,enum:[`fresh`,`fork`],description:`fresh starts the worker from its task alone; fork also gives it your conversation so far, so it does not have to rediscover what you already established. Prefer fork when the task depends on findings of yours.`},dependsOn:{type:`array`,items:{type:`string`},description:`Names of workers that must finish before this one starts. The worker is created now and held until they do, then given what they produced — so spawn the whole plan at once and express the ORDER here rather than by spawning later. Use it for anything that reviews, integrates or builds on another worker.`},writes:{type:`array`,items:{type:`string`},description:`Files and directories this worker may write, workspace-relative. A spawn that would write what another worker running at the same time writes is refused, because both would write it and the later write wins. Declare them and the conflict is caught before any work is lost. OMIT this entirely for a worker that only reads — a stand-in path such as "none" or "/tmp/no-write" claims a real scope, and several readers sharing that stand-in collide with each other over a file none of them will ever write.`},...this.roleSchema()},required:[`task`],additionalProperties:!1},parse:g,execute:async(e,t)=>O(await this.spawn(e,t.signal)),timeoutMs:this.spawnTimeoutMs,isConcurrencySafe:()=>!0}),r({name:`close_agent`,budgetExempt:!0,description:[`Close a worker you no longer need and free its slot.`,`A finished worker still occupies one until closed, so close it once you have read its result.`,`A running or pending worker is kept alive by default so it can finish its final report.`,this.options.allowModelWorkerCancellation===!1?`The host requires worker reports: you cannot cancel unfinished workers. Wait for their result.`:`Set cancelRunning: true only to deliberately abandon unfinished work and cancel it.`,`Returns the status it held before closing.`].join(` `),parameters:{type:`object`,properties:{name:{type:`string`,description:`Worker address returned by spawn_agent.`},cancelRunning:{type:`boolean`,description:`Explicitly cancel an unfinished worker. Defaults to false.`}},required:[`name`],additionalProperties:!1},parse:h,execute:async({name:e,cancelRunning:t})=>{let n=this.workerRuntimes.get(e);return n!==void 0&&(!t||this.options.allowModelWorkerCancellation===!1)&&(n.status===`pending`||n.status===`running`||n.session.isRunning)?O({worker:e,closed:!1,status:n.status===`pending`?`pending`:`running`,instruction:`The worker has not finished its final report. Use wait_agents and read its completed result before closing.`+(this.options.allowModelWorkerCancellation===!1?` Model cancellation is disabled by the host.`:` To deliberately abandon this work, call close_agent with cancelRunning: true.`)}):O({worker:e,closed:!0,previousStatus:await this.closeWorker(e)})},timeoutMs:this.workerTimeoutMs})])}forkLeadHistory(){let e=y(this.lead.snapshot().history);return a.fromSnapshot({version:1,entries:e},this.options.workerSessionOptions?.historyLimits??{})}async workerDefinition(e){if(this.options.workerFactory!==void 0)return this.options.workerFactory(e);let t=this.options.workerTemplate??this.options.lead,n=e.role===void 0?void 0:this.roles.get(e.role),r=n===void 0?``:` You are the '${n.name}' worker. ${n.instructions??n.description}`,i=e.specialty===void 0?``:` Your specialization is: ${e.specialty}.`;return o(t,{id:e.name,name:e.name,instructions:`${t.instructions}\n\nYou are dynamically assigned worker '${e.name}'.${r}${i}`})}nextWorkerName(){for(;;){let e=`worker_${++this.workerSequence}`;if(!this.reservedNames.has(e)&&!this.workerRuntimes.has(e)&&!this.team.members().some(t=>t.name===e))return e}}async observeWorkerEvent(t,n){let r=Promise.resolve().then(()=>this.options.onWorkerEvent?.(t,n));await e(r,this.observerTimeoutMs)}};function p(e){return new f(e)}function m(e,t){let n=new i;if(e!==void 0){let t=`names`in e?e.names().map(t=>e.get(t)).filter(e=>e!==void 0):e;for(let e of t)n.register(e)}for(let e of t)n.register(e);return n}function h(e){let t=b(e,`close_agent arguments`);if(Object.keys(t).some(e=>e!==`name`&&e!==`cancelRunning`))throw TypeError(`close_agent arguments contain unknown fields`);if(t.cancelRunning!==void 0&&typeof t.cancelRunning!=`boolean`)throw TypeError(`close_agent cancelRunning must be a boolean`);return{name:x(t.name),cancelRunning:t.cancelRunning===!0}}function g(e){let t=b(e,`spawn_agent arguments`),n=new Set([`name`,`task`,`specialty`,`context`,`role`,`dependsOn`,`writes`]);if(Object.keys(t).some(e=>!n.has(e)))throw TypeError(`spawn_agent arguments contain unknown fields`);return{task:S(t.task,`worker task`),...t.name===void 0?{}:{name:x(t.name)},...t.specialty===void 0?{}:{specialty:S(t.specialty,`worker specialty`)},...t.context===void 0?{}:{context:v(t.context)},...t.role===void 0?{}:{role:S(t.role,`worker role`)},...t.dependsOn===void 0?{}:{dependsOn:_(t.dependsOn,`dependsOn`)},...t.writes===void 0?{}:{writes:_(t.writes,`writes`)}}}function _(e,t){if(!Array.isArray(e))throw TypeError(`${t} must be an array of strings`);return e.map(e=>S(e,`${t} entry`))}function v(e){if(e!==`fresh`&&e!==`fork`)throw TypeError(`worker context must be 'fresh' or 'fork'`);return e}function y(e){let t=new Set,n=0;return e.entries.forEach((e,r)=>{let i=e.event;if(i.kind===`tool-call`)t.add(i.callId);else if(i.kind===`tool-result`)t.delete(i.callId);else if(i.kind===`assistant`)for(let e of i.message.content)e.type===`tool-call`&&t.add(e.id);t.size===0&&(i.kind!==`assistant`||i.interrupted!==!0)&&(n=r+1)}),e.entries.slice(0,n)}function b(e,t){if(typeof e!=`object`||!e||Array.isArray(e))throw TypeError(`${t} must be an object`);return e}function x(e){let t=S(e,`managed agent name`);if(!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(t))throw TypeError(`managed agent name must start with a letter and contain only letters, digits, _ or -`);if(t.length>128)throw TypeError(`managed agent name must not exceed 128 characters`);return t}function S(e,t){if(typeof e!=`string`||e.trim().length===0)throw TypeError(`${t} must be a non-empty string`);return e}function C(e,t,n){let r=S(e,t);if(new TextEncoder().encode(r).byteLength>n)throw TypeError(`${t} exceeds the ${n}-byte limit`);return r}function w(e,t){if(!Number.isSafeInteger(e)||e<1)throw TypeError(`${t} must be a positive integer`);return e}function T(e){return e instanceof Error?e.message:String(e)}async function E(e,t){if(t.aborted)throw t.reason??Error(`managed worker aborted`);return await new Promise((n,r)=>{let i=()=>{t.removeEventListener(`abort`,i),r(t.reason??Error(`managed worker aborted`))};t.addEventListener(`abort`,i,{once:!0}),e.then(e=>{t.removeEventListener(`abort`,i),n(e)},e=>{t.removeEventListener(`abort`,i),r(e)})})}function D(...e){let t=e.filter(e=>e!==void 0);return t.length===1?t[0]:AbortSignal.any(t)}function O(e){return e}const k=new Set([`completed`,`failed`,`closed`]);function A(e){let t=e.outcome.reason;if(t.kind===`error`)return t.failure.message;if(t.kind===`max-tokens`)return`the model stopped at its output limit`;if(t.kind===`usage-unavailable`)return`the provider reported no usage for a billed call`;if(t.kind===`aborted`)return`the run was aborted`;if(t.kind===`budget-exhausted`&&!e.outcome.completed)return`the run stopped at its ${t.budget} limit before completing the task`;if(e.text.trim()===``)return`it produced no answer`}function j(e){let t=S(e,`worker write scope`).trim().split(`\\`).join(`/`).replace(/^\.?\/+/,``).replace(/\/+$/,``);if(t.length===0||t===`.`)throw TypeError(`a worker write scope must name a file or directory, not the whole workspace`);return t}function M(e,t){return e===t||e.startsWith(`${t}/`)||t.startsWith(`${e}/`)}function N(e,t){let n=new TextEncoder().encode(e);return n.byteLength<=t?e:`${new TextDecoder(`utf-8`,{fatal:!1}).decode(n.subarray(0,t)).replace(/�$/,``)}… (truncated)`}export{u as DEFAULT_HOLD_WAIT_MS,c as DEFAULT_SPAWN_SETUP_TIMEOUT_MS,l as DEFAULT_WORKER_CLOSE_TIMEOUT_MS,f as ManagedAgentTeam,y as completedHistoryPrefix,p as createManagedAgentTeam};
1
+ import{waitForSettlement as e}from"../../async/settlement.js";import{timeoutValue as t}from"../../platform/config.js";import{createTextMessage as n}from"../../message/message.js";import{defineTool as r}from"../tool/definition.js";import{ToolRegistry as i}from"../tool/registry.js";import{History as a}from"../history/history.js";import{cloneAgent as o}from"../define/definition.js";import"./common.js";import{AgentTeam as s}from"./team.js";const c=3e4,l=3e4,u=15e3,d=[`You have access to a managed team. Your task and coordination strategy are defined by the host instructions.`,`Return only the caller-requested result in the caller’s format; include explanation only when requested.`,`spawn_agent returns a worker lifecycle view, not its final result. list_agents exposes status and retained results; wait_agents waits within its timeout.`,`dependsOn references already registered producer instances. Pending dependents start after those producers settle and receive their results or failure status, even if a producer address is later closed or reused.`,`fresh starts from the assigned task; fork also copies the completed lead conversation.`,`writes declares relative scheduling scopes under the host conflict policy; it does not grant filesystem permissions. Omit it when no write scope is needed.`,`send_message is an update, not terminal completion. completed and failed are terminal worker states; pending and running are not.`,`Finished workers occupy slots until close_agent. Closing unfinished work requires cancelRunning: true and host authorization.`].join(` `);var f=class{team;lead;leadName;options;maxWorkers;maxTaskBytes;maxSpecialtyBytes;workerTimeoutMs;observerTimeoutMs;closeTimeoutMs;holdWaitMs;spawnTimeoutMs;workerRuntimes=new Map;drainingWrites=new Set;preparing=new Map;lifecycle=new AbortController;disposeTask;workerSequence=0;maxDependencyReportBytes;roles;constructor(e){if(this.options=e,this.maxWorkers=w(e.maxWorkers??7,`maxWorkers`),this.maxTaskBytes=w(e.maxTaskBytes??65536,`maxTaskBytes`),this.maxSpecialtyBytes=w(e.maxSpecialtyBytes??8192,`maxSpecialtyBytes`),this.workerTimeoutMs=t(e.workerTimeoutMs??6e5),this.observerTimeoutMs=t(e.observerTimeoutMs??1e3),this.closeTimeoutMs=t(e.closeTimeoutMs??3e4),this.holdWaitMs=t(e.holdWaitMs??15e3),this.spawnTimeoutMs=t(e.spawnTimeoutMs??3e4),this.maxDependencyReportBytes=w(e.maxDependencyReportBytes??8192,`maxDependencyReportBytes`),this.maxDependencyReportBytes<4)throw TypeError(`maxDependencyReportBytes must be at least 4`);if(this.roles=new Map((e.roles??[]).map(e=>[e.name,e])),this.roles.size!==(e.roles??[]).length)throw Error(`managed agent roles contain a duplicate name`);this.team=e.team instanceof s?e.team:new s({...e.team,maxMembers:e.team?.maxMembers??this.maxWorkers+1}),this.leadName=x(e.leadName??e.lead.id),this.lead=e.lead.createSession({...e.leadSessionOptions,hooks:this.leadHooks(e.leadSessionOptions?.hooks),registry:e.registry,tools:m(e.leadSessionOptions?.tools,this.controlTools()),team:{team:this.team,name:this.leadName,role:`lead`,instructions:d,...e.leadDescription===void 0?{}:{description:e.leadDescription}}})}leadHooks(e){return{...e,beforeStep:async t=>(this.unreadReports=!1,this.leadSteer=new AbortController,this.leadSignal=t.signal,await e?.beforeStep?.(t)??{kind:`proceed`}),onTurnEnd:async t=>{if(await e?.onTurnEnd?.(t),this.options.autoLeadCoordination===!1)return;if(!t.canContinue){if(this.unreadReports){this.unreadReports=!1;try{this.team.wake(this.leadName)}catch{}}return}let n=[...this.workerRuntimes.values()].filter(e=>e.status===`running`||e.status===`pending`);if(n.length===0)return;await this.awaitWorkerNews(n);let r=[...this.workerRuntimes.values()].filter(e=>e.status===`running`||e.status===`pending`).map(e=>e.request.name);if(r.length===0){this.lead.inject(`All outstanding managed workers have settled. Their statuses and retained results are available through list_agents.`);return}this.lead.inject(`Outstanding managed workers: ${r.join(`, `)}. Their current lifecycle status is available through list_agents; wait_agents is bounded by its timeout.`)}}}run(e,t={}){return this.lifecycle.signal.throwIfAborted(),this.lead.run(e,t)}steer(e){this.lifecycle.signal.throwIfAborted(),this.lead.inject(e),this.leadSteer.abort();try{this.team.notifySteer(this.leadName)}catch{}if(!this.lead.isRunning)try{this.team.wake(this.leadName)}catch{}return!0}async spawn(e,t){this.lifecycle.signal.throwIfAborted(),t?.throwIfAborted();let r={name:x(e.name??this.nextWorkerName()),task:C(e.task,`worker task`,this.maxTaskBytes),...e.specialty===void 0?{}:{specialty:C(e.specialty,`worker specialty`,this.maxSpecialtyBytes)},context:v(e.context??this.options.defaultSpawnContext??`fresh`),...e.role===void 0?{}:{role:this.requireRole(e.role)},dependsOn:this.resolveDependencies(e.dependsOn??[]),writes:[...new Set((e.writes??[]).map(j))]};Object.freeze(r.dependsOn),Object.freeze(r.writes),Object.freeze(r);let i=r.dependsOn.map(e=>this.workerRuntimes.get(e));if(this.workerRuntimes.size+this.preparing.size>=this.maxWorkers)throw Error(`managed agent team reached its ${this.maxWorkers}-worker limit`);if(this.preparing.has(r.name)||this.workerRuntimes.has(r.name)||this.team.members().some(e=>e.name===r.name))throw Error(`managed worker '${r.name}' already exists`);let a,o=new Promise(e=>{a=e});this.preparing.set(r.name,{request:r,dependencies:i,settled:o});let s;try{let e=this.checkWriteScopes(r,i),a=D(t,this.lifecycle.signal,AbortSignal.timeout(this.spawnTimeoutMs)),o=await E(this.workerDefinition(r),a);a.throwIfAborted();let c=this.options.workerSessionOptionsFactory===void 0?void 0:await E(Promise.resolve(this.options.workerSessionOptionsFactory(r)),a);a.throwIfAborted();let l={...this.options.workerSessionOptions,...c},u=this.options.workerTeamTools??`reporting`,d=o.createSession({...l,...i.length===0?{}:{tools:m(l.tools,[this.dependencyReadTool(i)])},...r.context===`fork`?{history:this.forkLeadHistory(l.historyLimits)}:{},registry:this.options.registry,team:{team:this.team,name:r.name,role:`peer`,tools:u,instructions:[`You are managed worker '${r.name}'; lead: '${this.leadName}'.`,`Return only the caller-requested result in the caller’s format; include explanation only when requested.`,`Your terminal result is delivered automatically.`,...u===!1?[]:[`send_message is context, not a substitute result; it cannot target yourself.`]].join(` `),...r.specialty===void 0?{}:{description:r.specialty}}}),f=new AbortController,p;s={request:r,session:d,dependencies:i,starting:!1,settledComplete:!1,closeTask:void 0,status:`pending`,leadDriven:this.lead.isRunning,closing:!1,deadline:void 0,controller:f,settled:new Promise(e=>{p=e}),markSettled:()=>{F(s),s.settledComplete=!0,p()},start:void 0,warnings:e,result:void 0,error:void 0,evidence:{status:`pending`,result:void 0,error:void 0}},this.workerRuntimes.set(r.name,s),this.preparing.delete(r.name);let h=D(a,f.signal);if(await E(this.team.sendMessage({from:this.leadName,target:r.name,message:r.task,delivery:`quiet`,signal:h}),h),h.throwIfAborted(),o.memory.autoCaptureObjective&&d.memory.captureOriginalObjective(n(r.task)),i.length>0&&!this.dependenciesSettled(i,r.writes)){let e=new Promise(e=>{s.start=e});this.team.markPending(r.name,e);for(let e of i)k.has(e.status)&&this.workerHasWork(e)&&this.team.whenIdle(e.request.name).then(()=>this.releaseDependents(e)).catch(()=>{});return this.workerView(s)}return await this.startWorker(s,h),this.workerView(s)}catch(e){if(s!==void 0&&this.workerRuntimes.get(r.name)===s&&!s.closing){s.status=`failed`,s.error=T(e),s.start=void 0,s.dependencies=[];try{this.team.markPending(r.name,void 0)}catch{}s.markSettled(),this.workerRuntimes.delete(r.name);try{this.team.detach(r.name)}catch{}await this.releaseDependents(s)}throw e}finally{this.preparing.delete(r.name),a()}}beginWorker(e){let t=e.request.name;if(e.status!==`pending`||e.closing||this.lifecycle.signal.aborted||this.workerRuntimes.get(t)!==e)return;e.start?.(),e.start=void 0,this.team.markPending(t,void 0),e.status=`running`;let n=AbortSignal.timeout(this.workerTimeoutMs);e.deadline=n;let r=e.session.runPending({signal:D(e.controller.signal,n),...this.options.onWorkerEvent===void 0?{}:{onEvent:e=>this.observeWorkerEvent(t,e)}});this.followWorker(e,r)}async startWorker(e,t){if(!(e.starting||e.status!==`pending`||e.closing||this.lifecycle.signal.aborted)){e.starting=!0;try{let n=this.dependencyReport(e.dependencies);if(n!==void 0){let r=D(t,e.controller.signal,this.lifecycle.signal,AbortSignal.timeout(this.spawnTimeoutMs));await E(this.team.sendMessage({from:this.leadName,target:e.request.name,message:n,delivery:`quiet`,signal:r}),r),r.throwIfAborted()}this.beginWorker(e)}catch(t){if(!e.closing&&!this.lifecycle.signal.aborted){e.status=`failed`,e.error=`dependency handoff failed: ${T(t)}`,F(e),e.start?.(),e.start=void 0;try{this.team.markPending(e.request.name,void 0),this.team.recordOutcome(e.request.name,{kind:`failed`,message:e.error})}catch{}await this.notifyLead(e,`failed: ${e.error}`),e.markSettled(),await this.releaseDependents(e)}}finally{e.dependencies=[]}}}roleSchema(){if(this.roles.size===0)return{};let e=[...this.roles.values()].map(e=>`- ${e.name}: ${e.description}`+(e.whenToUse===void 0?``:` Use when: ${e.whenToUse}`));return{role:{type:`string`,enum:[...this.roles.keys()],description:`Which kind of worker this is.\n${e.join(`
2
+ `)}`}}}requireRole(e){let t=S(e,`worker role`);if(this.roles.size===0)throw Error(`this managed team declares no roles, so spawn_agent takes no role`);if(!this.roles.has(t))throw Error(`unknown worker role '${t}'; declared roles are ${[...this.roles.keys()].join(`, `)}`);return t}resolveDependencies(e){return[...new Set(e.map(e=>{let t=x(e);if(!this.workerRuntimes.has(t))throw Error(`unknown dependency '${t}'; a worker can only depend on one that already exists`);return t}))]}checkWriteScopes(e,t){let n=this.options.writeScopePolicy??`reject`;if(n===`off`||e.writes.length===0)return[];let r=this.ancestorsOf(t),i=[],a=new Set(this.team.members().filter(e=>e.status===`running`).map(e=>e.conversationId)),o=[...[...this.workerRuntimes.values()].filter(e=>e.status===`pending`||e.status===`running`||this.workerHasWork(e,a)).filter(e=>!r.has(e)),...this.drainingWrites,...[...this.preparing.values()].filter(t=>t.request.name!==e.name)];for(let t of o){let r=e.writes.filter(e=>t.request.writes.some(t=>M(e,t)));if(r.length===0)continue;let a=`'${t.request.name}' also writes ${r.join(`, `)}`;if(n===`reject`)throw Error(`worker '${e.name}' would write files another running worker writes: ${a}. Add '${t.request.name}' to dependsOn so it runs after, or narrow the scopes — or omit writes entirely if this worker only reads.`);i.push(a)}return i}describeWorkerFailure(e,t){if(t?.deadline?.aborted===!0)return this.deadlineFailure();let n=e?.name;return n===`TimeoutError`?this.deadlineFailure():n===`AbortError`?`its work was cancelled before it finished`:T(e)}deadlineFailure(){return`it ran past its ${String(this.workerTimeoutMs)}ms deadline without finishing. Narrow the task, or split it, before delegating it again`}async awaitWorkerNews(e){let t,n,r=new Promise(e=>{n=setTimeout(e,this.holdWaitMs),n.unref?.()});try{let n=this.leadSteer.signal,i=new Promise(e=>{n.aborted?e():n.addEventListener(`abort`,r,{once:!0});function r(){e()}t=()=>n.removeEventListener(`abort`,r)});await E(Promise.race([...e.map(e=>e.settled),r,i]),D(this.lifecycle.signal,this.leadSignal))}finally{n!==void 0&&clearTimeout(n),t?.()}}ancestorsOf(e,t=new Set){for(let n of e)t.has(n)||(t.add(n),this.ancestorsOf(n.dependencies,t));return t}workerHasWork(e,t){return e.session.isRunning||this.drainingWrites.has(e)||(t===void 0?this.team.members().some(t=>t.name===e.request.name&&t.conversationId===e.session.conversationId&&t.status===`running`):t.has(e.session.conversationId))}dependenciesSettled(e,t=[]){return e.every(e=>k.has(e.status)&&!((this.options.writeScopePolicy??`reject`)===`reject`&&t.some(t=>e.request.writes.some(e=>M(t,e)))&&this.workerHasWork(e)))}async releaseDependents(e){if(this.lifecycle.signal.aborted)return;let t=[...this.workerRuntimes.values()].filter(t=>t.status===`pending`&&!t.closing&&t.dependencies.includes(e)&&this.dependenciesSettled(t.dependencies,t.request.writes));for(let e of t)await this.startWorker(e)}dependencyReport(e){let t=!1,n=e.map(e=>{let n=e.request.name;if(e.error!==void 0){let r=e.result?.text,i=r?P(r,this.maxDependencyReportBytes):void 0;return t||=i!==void 0&&i!==r,`- worker address '${n}' FAILED: ${e.error}`+(r?``:`
3
+ Result payload: absent. No result data was returned.`)+(i===void 0?``:`\nPartial findings (not a completed task): ${i}`)}if(e.result===void 0&&e.status===`closed`)return`- worker address '${n}': closed before reporting. Result payload: absent. No result data was returned.`;let r=e.result?.text??``,i=P(r,this.maxDependencyReportBytes);return t||=i!==r,`- worker address '${n}' finished. ${i===r?`Full`:`Truncated`} result payload:\n${i}`});if(n.length!==0)return[`Dependency result data: worker addresses are routing metadata. Preserve source identifiers supplied in payloads; an absent payload supplies no evidence identifiers.`,...n,...t?[`Read truncated results with read_dependency_result, the original worker address and nextOffset.`]:[]].join(`
4
+ `)}dependencyReadTool(e){let t=new Map(e.map(e=>[e.request.name,e.evidence]));return r({name:`read_dependency_result`,description:`Read a bounded page from an original dependency result, including after closure. Full handoffs already contain the same result. Use nextOffset until null; partial/failed results are not completed work.`,parameters:{type:`object`,properties:{name:{type:`string`},offset:{type:`integer`,minimum:0}},required:[`name`],additionalProperties:!1},parse(e){if(typeof e!=`object`||!e)throw TypeError(`dependency name and offset required`);let t=Reflect.get(e,`name`),n=Reflect.get(e,`offset`)??0;if(typeof t!=`string`||!Number.isSafeInteger(n)||n<0)throw TypeError(`invalid dependency name or offset`);return{name:t,offset:n}},execute:({name:e,offset:n})=>{let r=t.get(e);if(r===void 0)throw Error(`this worker was not commissioned against that dependency`);let i=r.result?.text??``;if(n>i.length||n>0&&/[\uDC00-\uDFFF]/.test(i[n]))throw RangeError(`offset must be a valid character boundary`);let a=N(i.slice(n),this.maxDependencyReportBytes),o=n+a.length;return{name:e,status:r.status,succeeded:r.result?.succeeded??!1,...r.error===void 0?{}:{error:r.error},text:a,nextOffset:o<i.length?o:null}},isConcurrencySafe:()=>!0})}async followWorker(e,t){let n=e.request.name;try{let r=await t;if(e.status!==`closed`&&!e.closing){let t=e.deadline?.aborted===!0?this.deadlineFailure():A(r,this.options.requireWorkerText===!0);t===void 0?(e.status=`completed`,e.result=Object.freeze({worker:n,agentId:e.session.definition.id,conversationId:e.session.conversationId,text:r.text,succeeded:r.outcome.completed}),F(e),this.team.recordOutcome(n,{kind:`completed`,text:r.text}),await this.notifyLead(e,`finished: ${r.text}`)):(e.status=`failed`,e.error=t,r.text.trim()!==``&&(e.result=Object.freeze({worker:n,agentId:e.session.definition.id,conversationId:e.session.conversationId,text:r.text,succeeded:!1})),F(e),this.team.recordOutcome(n,{kind:`failed`,message:t}),await this.notifyLead(e,`failed: ${t}`+(e.result===void 0?``:`\nPartial findings (not a completed task): ${e.result.text}`)))}}catch(t){if(e.status!==`closed`&&!e.closing){e.status=`failed`,e.error=this.describeWorkerFailure(t,e),F(e);try{this.team.recordOutcome(n,{kind:`failed`,message:e.error})}catch{}await this.notifyLead(e,`failed: ${e.error}`)}}finally{e.markSettled(),await this.releaseDependents(e)}}async notifyLead(e,t){let n=e.request.name;if(e.closing||this.lifecycle.signal.aborted||this.workerRuntimes.get(n)!==e)return;let r=this.deliveryFor(n);r===`quiet`&&(this.unreadReports=!0);try{let i=D(e.controller.signal,this.lifecycle.signal,AbortSignal.timeout(this.spawnTimeoutMs));await E(this.team.sendMessage({from:n,target:this.leadName,message:`Worker '${n}' ${P(t,Math.min(this.maxDependencyReportBytes,Math.max(64,Math.floor(this.team.messageByteLimit/4))))}`,delivery:r,signal:i}),i)}catch{}}deliveryFor(e){return this.options.autoLeadCoordination===!1||this.lead.isRunning||this.workerRuntimes.get(e)?.leadDriven!==!0?`quiet`:`wakeup`}unreadReports=!1;leadSteer=new AbortController;leadSignal;async whenQuiet(e){for(;;){e?.throwIfAborted();let t=[...this.workerRuntimes.values()].filter(e=>!e.settledComplete),n=[...this.preparing.values()].map(e=>e.settled);if(t.length+n.length>0&&await E(Promise.all([...t.map(e=>e.settled),...n]),e),await this.team.whenIdle(this.leadName,e),!(this.preparing.size>0||[...this.workerRuntimes.values()].some(e=>!e.settledComplete)))return}}workers(){return Object.freeze([...this.workerRuntimes.values()].map(e=>this.workerView(e)))}workerView(e){return Object.freeze({name:e.request.name,agentId:e.session.definition.id,conversationId:e.session.conversationId,task:e.request.task,status:e.status,context:e.request.context,dependsOn:e.request.dependsOn,writes:e.request.writes,...e.request.role===void 0?{}:{role:e.request.role},...e.warnings.length===0?{}:{warnings:e.warnings},...e.request.specialty===void 0?{}:{specialty:e.request.specialty},...e.result===void 0?{}:{result:e.result},...e.error===void 0?{}:{error:e.error}})}async awaitWorker(e,n={}){let r=x(e),i=this.workerRuntimes.get(r);if(i===void 0)throw Error(`unknown managed worker '${r}'`);let a=t(n.timeoutMs??3e4),o,s=new Promise(e=>{o=setTimeout(e,a)});try{await E(Promise.race([i.settled,s]),n.signal)}finally{clearTimeout(o)}return n.signal?.throwIfAborted(),i.result}async closeWorker(e,t=Error(`managed worker closed`)){let n=x(e),r=this.workerRuntimes.get(n);if(r===void 0)throw Error(`unknown managed worker '${n}'`);return r.closing=!0,r.closeTask??=Promise.resolve().then(()=>this.closeRuntime(r,t)),r.closeTask}async closeRuntime(e,t){let n=e.request.name,r=e.status;e.closing=!0,e.controller.abort(t);let i=AbortSignal.timeout(this.closeTimeoutMs);try{await E(this.team.cancel(n,t),i)}catch{}if(r===`pending`)e.status=`closed`,e.start=void 0,this.team.markPending(n,void 0),e.markSettled();else{try{await E(e.settled,i)}catch{}e.status=`closed`,e.markSettled()}if(F(e),this.workerHasWork(e)&&(e.request.writes.length>0&&this.drainingWrites.add(e),this.team.whenIdle(n).then(async()=>{this.drainingWrites.delete(e);try{this.team.members().some(t=>t.name===n&&t.conversationId===e.session.conversationId)&&this.team.detach(n)}catch{}await this.releaseDependents(e)}).catch(()=>{})),this.workerRuntimes.get(n)===e){this.workerRuntimes.delete(n);try{this.team.detach(n)}catch{}}return e.dependencies=[],await this.releaseDependents(e),r}dispose(e=Error(`managed agent team disposed`)){if(this.disposeTask!==void 0)return this.disposeTask;this.lifecycle.abort(e);let t=[...this.workerRuntimes.keys()];return this.disposeTask=Promise.allSettled([...[...this.preparing.values()].map(e=>e.settled),...t.map(t=>this.closeWorker(t,e))]).then(()=>void 0),this.disposeTask}removeWorker(e){let t=x(e),n=this.workerRuntimes.get(t);if(n===void 0)throw Error(`unknown managed worker '${t}'`);if(n.status===`pending`||n.status===`running`||!n.settledComplete||n.session.isRunning)throw Error(`cannot remove running managed worker '${t}'`);this.team.detach(t),this.workerRuntimes.delete(t)}controlTools(){return Object.freeze([r({name:`spawn_agent`,description:[`Create a managed worker for the supplied task.`,`Returns a lifecycle view after setup; a dependent may still be pending.`,`Use list_agents for retained status/results and wait_agents for bounded waits.`,`dependsOn binds already registered producer instances; writes declares relative scheduling scopes under host policy.`].join(` `),parameters:{type:`object`,properties:{name:{type:`string`,description:`Optional unique worker address; omitted generates worker_N.`},task:{type:`string`,description:`Task and any output contract assigned to the worker.`},specialty:{type:`string`,description:`Optional worker role or domain specialization.`},context:{type:`string`,enum:[`fresh`,`fork`],description:`fresh starts from the task; fork also copies the completed lead conversation.`},dependsOn:{type:`array`,items:{type:`string`},description:`Names of workers that must finish before this one starts. The worker is created now and held until they do, then given what they produced. Register the producers first; a dependency cannot name a future or still-preparing worker. Failed producers also release dependents with failure status.`},writes:{type:`array`,items:{type:`string`},description:`Workspace-relative scheduling scopes. Overlaps are rejected, warned or allowed according to host writeScopePolicy. This is not filesystem authorization. Omit when no writes are declared; placeholder paths claim real scopes.`},...this.roleSchema()},required:[`task`],additionalProperties:!1},parse:g,execute:async(e,t)=>O(await this.spawn(e,t.signal)),timeoutMs:this.spawnTimeoutMs,isConcurrencySafe:()=>!0}),r({name:`close_agent`,budgetExempt:!0,description:[`Close a worker you no longer need and free its slot.`,`A finished worker still occupies one until closed, so close it once you have read its result.`,`A running or pending worker is kept alive by default so it can finish its final report.`,this.options.allowModelWorkerCancellation===!1?`The host requires worker reports: you cannot cancel unfinished workers. Wait for their result.`:`Set cancelRunning: true only to deliberately abandon unfinished work and cancel it.`,`Returns the status it held before closing.`].join(` `),parameters:{type:`object`,properties:{name:{type:`string`,description:`Worker address returned by spawn_agent.`},cancelRunning:{type:`boolean`,description:`Explicitly cancel an unfinished worker. Defaults to false.`}},required:[`name`],additionalProperties:!1},parse:h,execute:async({name:e,cancelRunning:t})=>{let n=this.workerRuntimes.get(e);return n!==void 0&&(!t||this.options.allowModelWorkerCancellation===!1)&&(n.status===`pending`||n.status===`running`||n.session.isRunning)?O({worker:e,closed:!1,status:n.status===`pending`?`pending`:`running`,instruction:`The worker has not finished its final report. Use wait_agents and read its completed result before closing.`+(this.options.allowModelWorkerCancellation===!1?` Model cancellation is disabled by the host.`:` To deliberately abandon this work, call close_agent with cancelRunning: true.`)}):O({worker:e,closed:!0,previousStatus:await this.closeWorker(e)})},timeoutMs:this.workerTimeoutMs})])}forkLeadHistory(e){let t=y(this.lead.snapshot().history);return a.fromSnapshot({version:1,entries:t},e??{})}async workerDefinition(e){if(this.options.workerFactory!==void 0)return this.options.workerFactory(e);let t=this.options.workerTemplate??this.options.lead,n=e.role===void 0?void 0:this.roles.get(e.role),r=n===void 0?``:` You are the '${n.name}' worker. ${n.instructions??n.description}`,i=e.specialty===void 0?``:` Your specialization is: ${e.specialty}.`;return o(t,{id:e.name,name:e.name,instructions:`${t.instructions}\n\nYou are dynamically assigned worker '${e.name}'.${r}${i}`})}nextWorkerName(){for(;;){let e=`worker_${++this.workerSequence}`;if(!this.preparing.has(e)&&!this.workerRuntimes.has(e)&&!this.team.members().some(t=>t.name===e))return e}}async observeWorkerEvent(t,n){let r=Promise.resolve().then(()=>this.options.onWorkerEvent?.(t,n));await e(r,this.observerTimeoutMs)}};function p(e){return new f(e)}function m(e,t){let n=new i;if(e!==void 0){let t=`names`in e?e.names().map(t=>e.get(t)).filter(e=>e!==void 0):e;for(let e of t)n.register(e)}for(let e of t)n.register(e);return n}function h(e){let t=b(e,`close_agent arguments`);if(Object.keys(t).some(e=>e!==`name`&&e!==`cancelRunning`))throw TypeError(`close_agent arguments contain unknown fields`);if(t.cancelRunning!==void 0&&typeof t.cancelRunning!=`boolean`)throw TypeError(`close_agent cancelRunning must be a boolean`);return{name:x(t.name),cancelRunning:t.cancelRunning===!0}}function g(e){let t=b(e,`spawn_agent arguments`),n=new Set([`name`,`task`,`specialty`,`context`,`role`,`dependsOn`,`writes`]);if(Object.keys(t).some(e=>!n.has(e)))throw TypeError(`spawn_agent arguments contain unknown fields`);return{task:S(t.task,`worker task`),...t.name===void 0?{}:{name:x(t.name)},...t.specialty===void 0?{}:{specialty:S(t.specialty,`worker specialty`)},...t.context===void 0?{}:{context:v(t.context)},...t.role===void 0?{}:{role:S(t.role,`worker role`)},...t.dependsOn===void 0?{}:{dependsOn:_(t.dependsOn,`dependsOn`)},...t.writes===void 0?{}:{writes:_(t.writes,`writes`)}}}function _(e,t){if(!Array.isArray(e))throw TypeError(`${t} must be an array of strings`);return e.map(e=>S(e,`${t} entry`))}function v(e){if(e!==`fresh`&&e!==`fork`)throw TypeError(`worker context must be 'fresh' or 'fork'`);return e}function y(e){let t=new Set,n=0;return e.entries.forEach((e,r)=>{let i=e.event;if(i.kind===`tool-call`)t.add(i.callId);else if(i.kind===`tool-result`)t.delete(i.callId);else if(i.kind===`assistant`)for(let e of i.message.content)e.type===`tool-call`&&t.add(e.id);t.size===0&&(i.kind!==`assistant`||i.interrupted!==!0)&&(n=r+1)}),e.entries.slice(0,n)}function b(e,t){if(typeof e!=`object`||!e||Array.isArray(e))throw TypeError(`${t} must be an object`);return e}function x(e){let t=S(e,`managed agent name`);if(!/^[a-zA-Z][a-zA-Z0-9_-]*$/.test(t))throw TypeError(`managed agent name must start with a letter and contain only letters, digits, _ or -`);if(t.length>128)throw TypeError(`managed agent name must not exceed 128 characters`);return t}function S(e,t){if(typeof e!=`string`||e.trim().length===0)throw TypeError(`${t} must be a non-empty string`);return e}function C(e,t,n){let r=S(e,t);if(new TextEncoder().encode(r).byteLength>n)throw TypeError(`${t} exceeds the ${n}-byte limit`);return r}function w(e,t){if(!Number.isSafeInteger(e)||e<1)throw TypeError(`${t} must be a positive integer`);return e}function T(e){return e instanceof Error?e.message:String(e)}async function E(e,t){if(t===void 0)return e;if(t.aborted)throw e.catch(()=>void 0),t.reason??Error(`managed worker aborted`);return await new Promise((n,r)=>{let i=()=>{t.removeEventListener(`abort`,i),r(t.reason??Error(`managed worker aborted`))};t.addEventListener(`abort`,i,{once:!0}),e.then(e=>{t.removeEventListener(`abort`,i),n(e)},e=>{t.removeEventListener(`abort`,i),r(e)})})}function D(...e){let t=e.filter(e=>e!==void 0);return t.length===1?t[0]:AbortSignal.any(t)}function O(e){return e}const k=new Set([`completed`,`failed`,`closed`]);function A(e,t){let n=e.outcome.reason;if(n.kind===`error`)return n.failure.message;if(n.kind===`max-tokens`)return`the model stopped at its output limit`;if(n.kind===`usage-unavailable`)return`the provider reported no usage for a billed call`;if(n.kind===`aborted`)return`the run was aborted`;if(n.kind===`budget-exhausted`&&!e.outcome.completed)return`the run stopped at its ${n.budget} limit before completing the task`;if(t&&e.text.trim()===``)return`it produced no answer`}function j(e){let t=S(e,`worker write scope`).trim().split(`\\`).join(`/`);if(t.startsWith(`/`)||/^[a-zA-Z]:/.test(t))throw TypeError(`a worker write scope must be workspace-relative`);let n=[];for(let e of t.split(`/`))if(e!==``&&e!==`.`){if(e===`..`){if(n.length===0)throw TypeError(`a worker write scope must not escape the workspace`);n.pop()}else n.push(e)}if(n.length===0)throw TypeError(`a worker write scope must name a file or directory, not the whole workspace`);return n.join(`/`)}function M(e,t){return e===t||e.startsWith(`${t}/`)||t.startsWith(`${e}/`)}function N(e,t){return new TextDecoder(`utf-8`,{fatal:!1}).decode(new TextEncoder().encode(e).subarray(0,t),{stream:!0})}function P(e,t){let n=new TextEncoder().encode(e);if(n.byteLength<=t)return e;let r=`
5
+ … (truncated; read full result) …
6
+ `,i=new TextEncoder().encode(r).byteLength;if(t<=i)return N(`(truncated)`,t);let a=t-i,o=N(e,Math.ceil(a/2)),s=n.length-Math.floor(a/2);for(;s<n.length&&(n[s]&192)==128;)s++;let c=new TextDecoder().decode(n.subarray(s));return o+r+c}function F(e){e.evidence.status=e.status,e.evidence.result=e.result,e.evidence.error=e.error}export{u as DEFAULT_HOLD_WAIT_MS,c as DEFAULT_SPAWN_SETUP_TIMEOUT_MS,l as DEFAULT_WORKER_CLOSE_TIMEOUT_MS,f as ManagedAgentTeam,y as completedHistoryPrefix,p as createManagedAgentTeam};
4
7
  //# sourceMappingURL=managed.js.map