@robota-sdk/agent-subagent-runner 3.0.0-beta.86 → 3.0.0-beta.87
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -7
- package/README.md +3 -3
- package/dist/node/index.cjs +1 -1
- package/dist/node/index.d.cts +13 -4
- package/dist/node/index.d.cts.map +1 -1
- package/dist/node/index.d.ts +13 -4
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +1 -1
- package/dist/node/index.js.map +1 -1
- package/package.json +14 -15
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
# @robota-sdk/agent-subagent-runner
|
|
2
2
|
|
|
3
|
+
## 3.0.0-beta.87
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Release the migrated Robota product with its public SDK namespace, robota command, compatible SDK exports, internal product configuration, and verified CLI startup and delivery corrections.
|
|
8
|
+
- 7d9cc66: Pass the child execution root and restored sandbox to hook composition. The stock CLI explicitly refuses command and HTTP hooks for separate task workers whose hook capabilities are unavailable, instead of executing those hooks on the host.
|
|
9
|
+
- Updated dependencies
|
|
10
|
+
- Updated dependencies [66af868]
|
|
11
|
+
- Updated dependencies [7d9cc66]
|
|
12
|
+
- Updated dependencies [7d9cc66]
|
|
13
|
+
- Updated dependencies [7d9cc66]
|
|
14
|
+
- Updated dependencies [7d9cc66]
|
|
15
|
+
- Updated dependencies [7d9cc66]
|
|
16
|
+
- Updated dependencies [7d9cc66]
|
|
17
|
+
- Updated dependencies [7d9cc66]
|
|
18
|
+
- Updated dependencies [7d9cc66]
|
|
19
|
+
- Updated dependencies [7d9cc66]
|
|
20
|
+
- Updated dependencies [7d9cc66]
|
|
21
|
+
- Updated dependencies [7d9cc66]
|
|
22
|
+
- Updated dependencies [7d9cc66]
|
|
23
|
+
- Updated dependencies [7d9cc66]
|
|
24
|
+
- Updated dependencies [7d9cc66]
|
|
25
|
+
- Updated dependencies [7d9cc66]
|
|
26
|
+
- Updated dependencies [7d9cc66]
|
|
27
|
+
- Updated dependencies [7d9cc66]
|
|
28
|
+
- Updated dependencies [7d9cc66]
|
|
29
|
+
- Updated dependencies [7d9cc66]
|
|
30
|
+
- @robota-sdk/agent-core@3.0.0-beta.87
|
|
31
|
+
- @robota-sdk/agent-executor@3.0.0-beta.87
|
|
32
|
+
- @robota-sdk/agent-framework@3.0.0-beta.87
|
|
33
|
+
- @robota-sdk/agent-interface-execution@3.0.0-beta.87
|
|
34
|
+
- @robota-sdk/agent-process@3.0.0-beta.87
|
|
35
|
+
|
|
3
36
|
## 3.0.0-beta.86
|
|
4
37
|
|
|
5
38
|
### Patch Changes
|
|
@@ -88,7 +121,7 @@
|
|
|
88
121
|
under. `sandboxApprovalFor` is exported.
|
|
89
122
|
- `agent-subagent-runner` (minor): `ISubagentWorkerComposition` takes an optional `createSandbox`. The
|
|
90
123
|
worker builds that sandbox once and hands the same instance to `createTools` and to the session.
|
|
91
|
-
- `agent-cli` (patch):
|
|
124
|
+
- `agent-cli` (patch): Robota's worker composition builds the OS sandbox through `createSandbox`, so
|
|
92
125
|
a child-process subagent approves what its parent approves.
|
|
93
126
|
|
|
94
127
|
- 122e82b: A child-process subagent confines and approves commands with its parent's sandbox settings as they
|
|
@@ -99,7 +132,7 @@
|
|
|
99
132
|
- `agent-subagent-runner` (minor): the runner factory takes `parentSandboxSettings`, read at each
|
|
100
133
|
spawn. The start payload carries it, the IPC guard checks it is a record, and the worker hands it to
|
|
101
134
|
`createSandbox` as `parentSettings`.
|
|
102
|
-
- `agent-cli` (patch):
|
|
135
|
+
- `agent-cli` (patch): Robota sends its live sandbox's settings, and a child builds its sandbox from
|
|
103
136
|
them. It refuses settings it cannot read rather than falling back to the files.
|
|
104
137
|
|
|
105
138
|
- 0368058: A running child-process subagent follows a `/sandbox` change made in its parent session. Before, it
|
|
@@ -114,7 +147,7 @@
|
|
|
114
147
|
exits or fails to start. A composed sandbox may define `applyParentSettings`. The worker applies
|
|
115
148
|
each change through it. On settings it cannot take, it aborts the run, lets a running command
|
|
116
149
|
finish, and ends the run with that error.
|
|
117
|
-
- `agent-cli` (patch):
|
|
150
|
+
- `agent-cli` (patch): Robota watches its live sandbox, and a child applies each change to the
|
|
118
151
|
instance its tools and approval read.
|
|
119
152
|
|
|
120
153
|
### Patch Changes
|
|
@@ -241,7 +274,7 @@
|
|
|
241
274
|
|
|
242
275
|
- 0c07176: **BREAKING — ARCH-021: child-process subagents compose the PRODUCT's surface, not imported defaults.**
|
|
243
276
|
|
|
244
|
-
The child-process worker built its surface from `createDefaultProviderDefinitions()` and `createDefaultTools()` — a fixed six-vendor registry and the framework's default tool tier — while the composition root had already handed the runner the fully composed surface and the runner dropped it. So a product's custom providers and pack-contributed tools reached an **in-process** subagent and not a **child-process** one, and ARCH-006's landed invariant "every tool
|
|
277
|
+
The child-process worker built its surface from `createDefaultProviderDefinitions()` and `createDefaultTools()` — a fixed six-vendor registry and the framework's default tool tier — while the composition root had already handed the runner the fully composed surface and the runner dropped it. So a product's custom providers and pack-contributed tools reached an **in-process** subagent and not a **child-process** one, and ARCH-006's landed invariant "every tool Robota runs comes from a pack" was **false in the child**: dropping a pack did not drop its tools.
|
|
245
278
|
|
|
246
279
|
This is the second finding at that line. ARCH-010 — judged BLOCKER, a subagent `Read` returning `/etc/hostname` — patched one argument there and left the reconstruction standing.
|
|
247
280
|
|
|
@@ -345,7 +378,7 @@
|
|
|
345
378
|
}
|
|
346
379
|
```
|
|
347
380
|
|
|
348
|
-
`IChildProcessSubagentRunnerOptions.workerPath` → **`workerEntry`**, and the runner `spawn`s `execPath args… --
|
|
381
|
+
`IChildProcessSubagentRunnerOptions.workerPath` → **`workerEntry`**, and the runner `spawn`s `execPath args… --__agent-subagent-worker` instead of forking a module path. `robota`'s own entry enters worker mode through the new `runSubagentWorkerMain()`, so **there is no second artifact and no path to get wrong**. The one seam satisfies all three shapes: a bundled Node build names the file it is executing, a `tsx` source run names the same and adds `--import tsx`, and a compiled binary names _nothing_ — `process.execPath` is the binary, and re-executing it re-enters its embedded entry.
|
|
349
382
|
|
|
350
383
|
**Per package, classified against each barrel:**
|
|
351
384
|
|
|
@@ -442,8 +475,8 @@
|
|
|
442
475
|
construction alongside `allow` and `deny`.
|
|
443
476
|
- **Never auto-approved, bypass included:** removing a critical path with `rm`/`rmdir` (the root, a
|
|
444
477
|
top-level directory, home, the working directory or a parent), and a modify-class write into
|
|
445
|
-
`.git`, `.
|
|
446
|
-
Files inside an isolated worktree (
|
|
478
|
+
`.git`, `.Robota`, `.claude`, `.agents`, `.mcp.json`, `.gitconfig`, `.npmrc` or a shell rc file.
|
|
479
|
+
Files inside an isolated worktree (`$PRODUCT_PROJECT_STATE_DIR/worktrees/<name>/…`) are ordinary files. With no
|
|
447
480
|
approver attached, an ask is a denial.
|
|
448
481
|
- **A ceiling is checked before bypass and before any ask.** A subagent's `inherit-allowlist` ceiling
|
|
449
482
|
is now the parent's _effective_ rules, read live at spawn: settings, preset lists and command
|
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@ composition root (e.g. agent-cli)
|
|
|
22
22
|
└── ChildProcessSubagentRunner ← this package
|
|
23
23
|
├── spawn() ← a copy of the running artifact in worker mode
|
|
24
24
|
├── IPC messages ← TSubagentWorkerParentMessage / TSubagentWorkerChildMessage
|
|
25
|
-
└── worktree isolation ←
|
|
25
|
+
└── worktree isolation ← vian agent-executor, with an injected worktree adapter
|
|
26
26
|
```
|
|
27
27
|
|
|
28
28
|
The runner composes nothing itself. The composition root supplies how to start a copy of itself
|
|
@@ -68,7 +68,7 @@ const factory = createChildProcessSubagentRunnerFactory({
|
|
|
68
68
|
workerEntry: { execPath: process.execPath, args: [process.argv[1] ?? ''] },
|
|
69
69
|
providerConfig,
|
|
70
70
|
providerDefinitions: myProviderDefinitions, // required: a job whose provider is not here is refused
|
|
71
|
-
logsDir:
|
|
71
|
+
logsDir: hostSelectedLogDirectory,
|
|
72
72
|
worktreeAdapter, // required: no concrete git default — inject the port at the composition root
|
|
73
73
|
});
|
|
74
74
|
```
|
|
@@ -134,4 +134,4 @@ how the provider connection is checked across the process boundary.
|
|
|
134
134
|
|
|
135
135
|
## License
|
|
136
136
|
|
|
137
|
-
|
|
137
|
+
This package is dual-licensed under the [GNU AGPL-3.0](../../LICENSE) or a [commercial license](../../COMMERCIAL.md). See [LICENSING.md](../../LICENSING.md).
|
package/dist/node/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("node:child_process"),t=require("node:fs"),n=require("node:path"),r=require("@robota-sdk/agent-executor"),i=require("@robota-sdk/agent-process"),a=require("@robota-sdk/agent-core"),o=require("@robota-sdk/agent-framework");function s(e){return{provider:{model:e.provider.model},permissions:e.permissions,defaultTrustLevel:e.defaultTrustLevel,...e.hooks===void 0?{}:{hooks:e.hooks}}}function c(e){return{agentsMd:e.agentsMd,projectNotesMd:e.projectNotesMd}}const l={name:{kind:`string`,required:!0},description:{kind:`string`,required:!0},systemPrompt:{kind:`string`,required:!0},model:{kind:`string`,required:!1},effort:{kind:`effort`,required:!1},role:{kind:`string`,required:!1},maxTurns:{kind:`number`,required:!1},tools:{kind:`string[]`,required:!1},disallowedTools:{kind:`string[]`,required:!1}},u={agentsMd:{kind:`string`,required:!0},projectNotesMd:{kind:`string`,required:!0},memoryMd:{kind:`string`,required:!1},taskContext:{kind:`string`,required:!1},compactInstructions:{kind:`string`,required:!1},agentsFileEntries:{kind:`file-entry[]`,required:!1},projectNotesFileEntries:{kind:`file-entry[]`,required:!1}};function d(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function f(e){return Array.isArray(e)&&e.every(e=>typeof e==`string`)}function p(e){return d(e)&&typeof e.filePath==`string`&&typeof e.content==`string`&&typeof e.contentHash==`string`}function m(e,t){switch(e){case`string`:return typeof t==`string`;case`number`:return typeof t==`number`&&Number.isFinite(t);case`effort`:return typeof t==`string`&&(0,a.isModelEffort)(t);case`string[]`:return f(t);case`file-entry[]`:return Array.isArray(t)&&t.every(p)}}function h(e,t){let n={};for(let r of Object.keys(t)){let t=e[r];t!==void 0&&(n[r]=t)}return n}function g(e,t,n){if(!d(t))return{ok:!1,reason:`${e}: expected an object`};for(let[r,i]of Object.entries(n)){let n=t[r];if(n===void 0){if(i.required)return{ok:!1,reason:`${e}.${r}: required`};continue}if(!m(i.kind,n))return{ok:!1,reason:`${e}.${r}: expected ${i.kind}`}}return{ok:!0,value:h(t,n)}}function _(e){return h(e,l)}function v(e){return g(`agentDefinition`,e,l)}function y(e){let t={name:e.name,description:e.description,systemPrompt:e.systemPrompt};return e.model!==void 0&&(t.model=e.model),e.effort!==void 0&&(t.effort=e.effort),e.role!==void 0&&(t.role=e.role),e.maxTurns!==void 0&&(t.maxTurns=e.maxTurns),e.tools!==void 0&&(t.tools=[...e.tools]),e.disallowedTools!==void 0&&(t.disallowedTools=[...e.disallowedTools]),t}function b(e){return h(e,u)}function x(e){return g(`parentContext`,e,u)}function S(e){let t={agentsMd:e.agentsMd,projectNotesMd:e.projectNotesMd};return e.memoryMd!==void 0&&(t.memoryMd=e.memoryMd),e.taskContext!==void 0&&(t.taskContext=e.taskContext),e.compactInstructions!==void 0&&(t.compactInstructions=e.compactInstructions),e.agentsFileEntries!==void 0&&(t.agentsFileEntries=e.agentsFileEntries.map(e=>({...e}))),e.projectNotesFileEntries!==void 0&&(t.projectNotesFileEntries=e.projectNotesFileEntries.map(e=>({...e}))),t}function ee(e){return e.sessionTiers===void 0?{}:{sessionTiers:e.sessionTiers}}async function C(e){let{sandboxClient:t,sandboxType:n}=e;return t?.snapshot===void 0||n===void 0?{}:{sandboxProjection:{type:n,snapshotId:await t.snapshot()}}}function w(e,t,n,i,o){let s=n.providerDefinitions,c=(n.providerConfig??t.config.provider).name;if((0,a.findProviderDefinition)(s,c)===void 0)throw new r.BackgroundTaskError(`validation`,`No provider definition for "${c}" was given to the subagent runner, so the connection a child would make cannot be checked; the subagent was not started.`);let l=E(n.providerConfig,t,e,s),u=(0,r.connectionEnvironmentNames)(l,s),d=(0,r.findConnectionEnvironmentDivergence)(u,i,o);if(d!==void 0)throw new r.BackgroundTaskError(`validation`,`The subagent's environment sets ${d} differently from this session, which would change where its provider connects or which credential it sends; the subagent was not started.`);return{providerProfile:l,connectionCheck:(0,r.sealConnectionEnvironment)(u,o)}}function te(e,t,n){let r=ne(e.request.agentType,t.customAgentRegistry,t.builtInAgents,t.agentDefinitions),i={taskId:e.taskId,request:e.request,...e.worktree?{worktree:e.worktree}:{},agentDefinition:_(re(r,e)),parentConfig:s(t.getParentPermissionRules===void 0?t.config:{...t.config,permissions:t.getParentPermissionRules()}),parentContext:b(c(t.context)),...n.connection??w(e,t,n,process.env,process.env),permissionMode:t.getParentPermissionMode?.()??t.permissionMode,...ee(t),...n.parentSandboxSettings===void 0?{}:{parentSandboxSettings:n.parentSandboxSettings},...n.logsDir?{logsDir:n.logsDir}:{}};return C(t).then(e=>({...i,...e}))}function ne(e,t,n,i){let a=t?.(e)??n?.find(t=>t.name===e)??i?.find(t=>t.name===e);if(!a)throw new r.BackgroundTaskError(`validation`,`Unknown agent type: ${e}`);return a}function re(e,t){return{...e,...t.request.model?{model:t.request.model}:{},...t.request.effort===void 0?{}:{effort:t.request.effort},...t.request.allowedTools?{tools:t.request.allowedTools}:{},...t.request.disallowedTools?{disallowedTools:t.request.disallowedTools}:{}}}function T(e,t){return e.apiKeyEnv===void 0?e.apiKey===void 0?t===void 0?{}:t.startsWith(`$ENV:`)?{apiKeyEnv:t.slice(5)}:{apiKey:t}:{apiKey:e.apiKey}:{apiKeyEnv:e.apiKeyEnv}}function E(e,t,n,r){let i=e??t.config.provider,o=(0,a.findProviderDefinition)(r,i.name)?.defaults??{},s=i.baseURL??o.baseURL,c=i.options??o.options,l=T(i,o.apiKey);return{...e===void 0&&t.config.currentProvider!==void 0?{profileName:t.config.currentProvider}:{},type:i.name,model:n.request.model??i.model,...l,...s===void 0?{}:{baseURL:s},...i.timeout===void 0?{}:{timeout:i.timeout},...c===void 0?{}:{options:c}}}function D(e){return typeof e==`object`&&!!e}function ie(e){if(!D(e)||!O(e,`nonce`)||!O(e,`digest`))return!1;let t=e.names;return Array.isArray(t)&&t.every(e=>typeof e==`string`)}function O(e,t){return typeof e[t]==`string`}function k(e,t){return O(e,t)}function ae(e,t){return O(e,t)}function oe(e,t){return e[t]===void 0||typeof e[t]==`string`}function se(e){if(e.usage===void 0)return!0;let t=e.usage;return D(t)?typeof t.promptTokens==`number`&&typeof t.completionTokens==`number`&&typeof t.totalTokens==`number`:!1}function ce(e){if(e.composedToolNames===void 0)return!0;let t=e.composedToolNames;return Array.isArray(t)?t.every(e=>typeof e==`string`):!1}function le(e){return!D(e)||!ae(e,`taskId`)||!D(e.request)||!k(e.request,`agentType`)||!k(e.request,`prompt`)||!k(e.request,`permissionPolicy`)||!k(e.request,`cwd`)||!oe(e.request,`resumeSessionId`)||e.worktree!==void 0&&(!D(e.worktree)||!O(e.worktree,`path`))||!v(e.agentDefinition).ok||!D(e.parentConfig)||!x(e.parentContext).ok||!D(e.providerProfile)||!O(e.providerProfile,`type`)||!O(e.providerProfile,`model`)||e.parentSandboxSettings!==void 0&&!D(e.parentSandboxSettings)?!1:ie(e.connectionCheck)}function A(e){if(!D(e)||!O(e,`type`))return!1;switch(e.type){case`start`:return le(e.payload);case`send`:return O(e,`prompt`);case`cancel`:return e.reason===void 0||typeof e.reason==`string`;case`sandbox_settings`:return D(e.settings);case`permission_response`:return O(e,`requestId`)&&ue(e.result);default:return!1}}function ue(e){return typeof e==`boolean`||e===`allow-session`||e===`allow-project`}function j(e){if(!D(e)||!O(e,`type`))return!1;switch(e.type){case`ready`:return ce(e);case`text_delta`:return O(e,`delta`);case`tool_start`:return O(e,`toolName`);case`tool_end`:return O(e,`toolName`)&&typeof e.success==`boolean`;case`permission_request`:return O(e,`requestId`)&&O(e,`toolName`);case`result`:return O(e,`output`)&&se(e);case`error`:return O(e,`message`);case`cancelled`:return e.reason===void 0||typeof e.reason==`string`;default:return!1}}const de=process.platform!==`win32`;function fe(e,t){return new Promise(n=>{if(e.exitCode!==null||e.signalCode!==null){n();return}let r=setTimeout(()=>{e.removeListener(`exit`,i),n()},t);r.unref?.();let i=()=>{clearTimeout(r),n()};e.once(`exit`,i)})}const M=new WeakMap;function N(e){let t=e.stderr;if(!t)return;let n=(0,a.createBoundedOutput)({maxBytes:4096,retain:`tail`,truncationMarker:()=>``});M.set(e,n),t.on(`error`,()=>{}),t.on(`data`,e=>n.append(e))}function P(e){return(M.get(e)?.toString()??``).trim()}function F(e,t,n,i,a,o){switch(e.type){case`ready`:t();break;case`result`:n(e);break;case`error`:i(new r.BackgroundTaskError(`runner`,e.message));break;case`cancelled`:i(new r.BackgroundTaskError(`runner`,e.reason??`Subagent worker cancelled`));break;case`text_delta`:a?.({type:`background_task_text_delta`,delta:e.delta});break;case`tool_start`:a?.({type:`background_task_tool_start`,toolName:e.toolName,firstArg:I(e.toolArgs)});break;case`tool_end`:a?.({type:`background_task_tool_end`,toolName:e.toolName,success:e.success});break;case`permission_request`:o?.(e);break;default:i(new r.BackgroundTaskError(`runner`,`Unhandled subagent worker message`))}}function I(e){if(!e)return;let t=Object.values(e)[0];if(t!==void 0)return typeof t==`object`?JSON.stringify(t):String(t)}function L(e,t){return new Promise((n,i)=>{if(!e.connected){i(new r.BackgroundTaskError(`crash`,`Subagent worker IPC channel is closed`));return}e.send(t,e=>{if(e){i(e);return}n()})})}async function R(e,t){await(0,i.killProcessTree)(e.child,{graceMs:e.killGraceMs,processGroup:de,preKill:async()=>{e.child.connected&&(await L(e.child,{type:`cancel`,reason:t}).catch(()=>void 0),await fe(e.child,e.killGraceMs))}})}function z(e){return new Promise((t,n)=>{new B(e,t,n).start()})}var B=class{options;resolve;reject;settled=!1;started=!1;ready=!1;timeoutTimer;handshakeTimer;handshakeBudgetMs;payload;deniedToolCallCounts={"no-approver":0,"denied-by-person":0,"approver-error":0,cancelled:0};pendingPermissionRequests=new Map;constructor(e,t,n){this.options=e,this.resolve=t,this.reject=n;let i=e.handshakeBudgetMs;this.handshakeBudgetMs=i!==void 0&&i>0?i:3e4,this.payload=e.payload.catch(e=>{this.rejectOnce(e instanceof Error?e:Error(String(e)))}),this.timeoutTimer=pe(this.options.runtime,e=>this.rejectOnce(e)),this.handshakeTimer=setTimeout(()=>{this.ready||this.settled||(R(this.options.runtime,`Subagent worker never signalled ready`),this.rejectOnce(new r.BackgroundTaskError(`runner`,`Subagent worker never signalled ready within ${this.handshakeBudgetMs}ms. Its entry must dispatch worker mode before starting the host application.`)))},this.handshakeBudgetMs),this.handshakeTimer.unref?.()}start(){let{child:e}=this.options.runtime;e.on(`message`,this.onMessage),e.on(`error`,this.onError),e.on(`exit`,this.onExit),e.once(`spawn`,()=>{setImmediate(this.startWorker)})}startWorker=()=>{if(this.started)return;this.started=!0;let{child:e}=this.options.runtime;this.payload.then(t=>t===void 0?void 0:L(e,{type:`start`,payload:t})).catch(e=>{this.rejectOnce(e instanceof Error?e:Error(String(e)))})};onMessage=e=>{if(!j(e)){this.rejectOnce(new r.BackgroundTaskError(`runner`,`Received malformed subagent worker message`));return}this.ready=!0,clearTimeout(this.handshakeTimer);let{job:t}=this.options.runtime;F(e,this.startWorker,this.resolveOnce,this.rejectOnce,t.emit,this.onPermissionRequest)};onPermissionRequest=e=>{let t=this.answerPermissionRequest(e).finally(()=>{this.pendingPermissionRequests.delete(e.requestId)});this.pendingPermissionRequests.set(e.requestId,t)};async answerPermissionRequest(e){let{reason:t,result:n}=await this.askApprover(e);t!==void 0&&(this.deniedToolCallCounts[t]+=1);let{child:r}=this.options.runtime;r.connected&&await L(r,{type:`permission_response`,requestId:e.requestId,result:n}).catch(()=>void 0)}async askApprover(e){let t=this.options.permissionApprover;if(t===void 0)return{reason:`no-approver`,result:!1};try{let n=await t(e.toolName,e.toolArgs??{},this.options.permissionAbort.signal);return n===!1?this.options.permissionAbort.signal.aborted?{reason:`cancelled`,result:!1}:{reason:`denied-by-person`,result:!1}:{result:n}}catch{return{reason:`approver-error`,result:!1}}}onError=e=>{this.rejectOnce(new r.BackgroundTaskError(`crash`,e.message))};onExit=(e,t)=>{this.settled||this.rejectOnce(new r.BackgroundTaskError(`crash`,ge(e,t,P(this.options.runtime.child))))};resolveOnce=e=>{this.settled||(this.settled=!0,this.settleAfterPendingPermissionRequests(()=>{let{runtime:t,resolveTranscriptPath:n}=this.options;this.resolve(me(t.job,e,n,this.deniedToolCallCounts))}))};rejectOnce=e=>{this.settled||(this.settled=!0,this.settleAfterPendingPermissionRequests(()=>this.reject(e)))};async settleAfterPendingPermissionRequests(e){this.options.permissionAbort.abort(),this.clearTimers(),this.cleanup(),await Promise.all(this.pendingPermissionRequests.values()),e()}clearTimers(){this.timeoutTimer&&clearTimeout(this.timeoutTimer),clearTimeout(this.handshakeTimer)}cleanup(){let{child:e}=this.options.runtime;e.off(`message`,this.onMessage),e.off(`error`,this.onError),e.off(`exit`,this.onExit)}};function V(e){let t=!1,n=()=>{};return{promise:new Promise((e,t)=>{n=t}),reject(i){t||(t=!0,n(new r.BackgroundTaskError(`runner`,i??`Subagent job cancelled: ${e}`)))}}}function pe(e,t){if(e.job.request.timeoutMs)return setTimeout(()=>{R(e,`Subagent worker timed out`),t(new r.BackgroundTaskError(`timeout`,`Subagent worker timed out`))},e.job.request.timeoutMs)}function me(e,t,n,r){let i=n(e),a=he(r);return{taskId:e.taskId,output:t.output,...i?{metadata:{transcriptPath:i,logPath:i}}:{},...t.usage?{usage:t.usage}:{},...a?{deniedToolCalls:a}:{}}}function he(e){let t=Object.values(e).reduce((e,t)=>e+t,0);return t===0?void 0:{total:t,byReason:{...e}}}function ge(e,t,n){return`Subagent worker exited before result: ${t===null?`exit code ${e===null?`unknown`:e}`:`signal ${t}`}${n.length>0?`: ${n}`:``}`}const H=`--__robota-subagent-worker`;function _e(e){return e.includes(H)}const ve=process.platform!==`win32`;function ye(e){return t=>{let n=new U(t,e);return e.worktreeIsolation===!1?n:(0,r.createWorktreeSubagentRunner)({runner:n,worktreeAdapter:e.worktreeAdapter,hooks:t.config.hooks,hookTypeExecutors:t.hookTypeExecutors})}}var U=class{deps;workerEntry;killGraceMs;handshakeBudgetMs;providerConfig;providerDefinitions;env;logsDir;parentSandboxSettings;watchParentSandboxSettings;constructor(e,t){this.deps=e,this.workerEntry=t.workerEntry,this.killGraceMs=t.killGraceMs??i.DEFAULT_KILL_GRACE_MS,this.handshakeBudgetMs=t.handshakeBudgetMs,this.providerConfig=t.providerConfig,this.providerDefinitions=t.providerDefinitions,this.env=t.env,this.logsDir=t.logsDir,this.parentSandboxSettings=t.parentSandboxSettings,this.watchParentSandboxSettings=t.watchParentSandboxSettings}start(t){let n=this.workerEntry,i={...process.env,...this.env??{}},a=w(t,this.deps,{...this.providerConfig===void 0?{}:{providerConfig:this.providerConfig},providerDefinitions:this.providerDefinitions},process.env,i),o=(0,e.spawn)(n.execPath,[...n.execArgv??[],...n.args,H],{cwd:(0,r.subagentExecutionRoot)(t),env:i,stdio:[`ignore`,`ignore`,`pipe`,`ipc`],detached:ve});N(o),this.forwardSandboxSettingChanges(o);let s={job:t,child:o,killGraceMs:this.killGraceMs},c=this.createStartPayload(t,a),l=new AbortController,u=this.permissionApprover(t),d=z({runtime:s,payload:c,...this.handshakeBudgetMs===void 0?{}:{handshakeBudgetMs:this.handshakeBudgetMs},resolveTranscriptPath:e=>this.resolveTranscriptPath(e),permissionAbort:l,...u===void 0?{}:{permissionApprover:u}}),f=V(t.taskId);d.catch(()=>void 0);let p=Promise.race([d,f.promise]);p.catch(()=>void 0);let m=this.resolveTranscriptPath(t);return{taskId:t.taskId,...o.pid!==void 0&&{pid:o.pid},...m!==void 0&&{transcriptPath:m,logPath:m},result:p,cancel:async e=>{l.abort(e),f.reject(e),await R(s,e)},send:async e=>{await L(o,{type:`send`,prompt:e})},...m!==void 0&&{readLog:async e=>be(t.taskId,m,e)}}}createStartPayload(e,t){let n=this.parentSandboxSettings?.();return te(e,this.deps,{connection:t,providerDefinitions:this.providerDefinitions,...this.logsDir===void 0?{}:{logsDir:this.logsDir},...n===void 0?{}:{parentSandboxSettings:n}})}forwardSandboxSettingChanges(e){let t=this.watchParentSandboxSettings?.(t=>{e.connected&&L(e,{type:`sandbox_settings`,settings:t}).catch(()=>void 0)});t!==void 0&&(e.once(`exit`,t),e.once(`error`,t))}resolveTranscriptPath(e){if(this.logsDir)return(0,n.join)(this.logsDir,e.request.parentSessionId,`subagents`,`${e.taskId}.jsonl`)}permissionApprover(e){let t=this.deps.permissionHandler;if(t===void 0)return;let n={kind:`background-agent`,label:e.request.agentType,taskId:e.taskId};return(e,r,i)=>t(e,r,{requester:n,signal:i})}};function be(e,n,i){return(0,t.existsSync)(n)?(0,r.createBackgroundTaskLogPage)(e,(0,t.readFileSync)(n,`utf8`).split(/\r?\n/).filter(Boolean),i):{taskId:e,cursor:i,lines:[]}}function xe(e,t,n){let r=e.request.resumeSessionId;if(r!==void 0){if(n===void 0)throw Error(`subagent worker: job ${e.taskId} asks to resume session ${r}, but this composition opens no session store. Register ISubagentWorkerComposition.openSessionStore at the composition root — the same place providerDefinitions is registered.`);(0,o.restoreSessionRecordIntoSession)(n,r,t)}}function Se(e,t){let n=e.request.resumeSessionId;if(n!==void 0){if(t.openSessionStore===void 0)throw Error(`subagent worker: job ${e.taskId} asks to resume session ${n}, but this composition opens no session store. Register ISubagentWorkerComposition.openSessionStore at the composition root — the same place providerDefinitions is registered.`);return t.openSessionStore({cwd:e.request.cwd})}}async function Ce(e,t){if(e===void 0)return;let n=t?.[e.type];if(n===void 0)throw Error(`subagent worker: sandbox type "${e.type}" is not registered in the worker composition. The parent is sandboxed and passed a snapshot reference, but this child cannot construct that client type. Register it in ISubagentWorkerComposition.sandboxFactories at the composition root — the same place providerDefinitions is registered, and for the same reason.`);return n(e.snapshotId)}const we={write:()=>{},writeLine:()=>{},writeMarkdown:()=>{},writeError:()=>{},prompt:()=>Promise.resolve(``),select:()=>Promise.resolve(0),spinner:()=>({stop:()=>{},update:()=>{}})};let W=null,G=!1;const K=new Map;let Te=0,q,J,Y,X=Promise.resolve();function Z(e){process.send&&process.send(e)}function Q(e,t){let n=!1,r=()=>{n||(n=!0,process.exit(t))};if(process.send){let t=setTimeout(r,2e3);t.unref?.(),process.send(e,void 0,void 0,()=>{clearTimeout(t),r()})}else r()}function Ee(e){try{return(0,a.sumHistoryUsage)(e.getFullHistory())}catch{return}}async function De(e,t){try{if(!(0,r.verifyConnectionEnvironment)(e.connectionCheck,process.env))throw Error(`The provider connection environment changed after the parent checked it; the subagent was not started.`);let n=await Ce(e.sandboxProjection,t.sandboxFactories),i=(0,r.createProviderFromExactProfile)(e.providerProfile,e.request.model,t.providerDefinitions),a=e.logsDir?(0,o.createSubagentLogger)(e.request.parentSessionId,e.taskId,e.logsDir):void 0,s=Se(e,t),c=q??e.parentSandboxSettings;J=n===void 0?t.createSandbox?.({cwd:(0,r.subagentExecutionRoot)(e),...c===void 0?{}:{parentSettings:c}}):void 0;let l=n??J?.client;W=(0,o.createSubagentSession)({agentDefinition:y(e.agentDefinition),parentConfig:e.parentConfig,parentContext:S(e.parentContext),parentTools:t.createTools({cwd:(0,r.subagentExecutionRoot)(e),...l===void 0?{}:{sandboxClient:l},...e.sessionTiers===void 0?{}:{sessionTiers:e.sessionTiers}}),cwd:(0,r.subagentExecutionRoot)(e),provider:i,terminal:we,sessionId:e.request.resumeSessionId??e.taskId,...s===void 0?{}:{sessionStore:s},...a?{sessionLogger:a}:{},permissionMode:e.permissionMode,...J?.commandSandbox===void 0?{}:{commandSandbox:J.commandSandbox},...e.request.permissionPolicy===void 0?{}:{permissionPolicy:e.request.permissionPolicy},...e.request.allowedTools===void 0?{}:{taskAllowedTools:e.request.allowedTools},...e.request.disallowedTools===void 0?{}:{taskDisallowedTools:e.request.disallowedTools},hooks:e.parentConfig.hooks,...t.createHookTypeExecutors===void 0?{}:{hookTypeExecutors:t.createHookTypeExecutors()},onTextDelta:e=>Z({type:`text_delta`,delta:e}),onToolExecution:Ae,permissionHandler:Oe}),xe(e,W,s);let u=await W.run(e.request.prompt);if(Y!==void 0){Q({type:`error`,message:Y},0);return}if(G){Q({type:`cancelled`,reason:`Subagent worker cancelled`},130);return}let d=Ee(W);Q({type:`result`,output:u,...d?{usage:d}:{}},0)}catch(e){if(Y!==void 0){Q({type:`error`,message:Y},0);return}if(G){Q({type:`cancelled`,reason:`Subagent worker cancelled`},130);return}Q({type:`error`,message:e instanceof Error?e.message:String(e)},0)}}function Oe(e,t){let n=`perm_${++Te}`;return new Promise(r=>{K.set(n,r),Z({type:`permission_request`,requestId:n,toolName:e,toolArgs:t})})}function ke(e,t){let n=K.get(e);n!==void 0&&(K.delete(e),n(t))}function Ae(e){if(e.type===`start`){Z({type:`tool_start`,toolName:e.toolName,toolArgs:e.toolArgs});return}Z({type:`tool_end`,toolName:e.toolName,success:e.success??!0})}function $(e){if(W===null){Z({type:`error`,message:`Subagent worker has not started`});return}X=X.then(async()=>{try{await W?.run(e)}catch(e){Z({type:`error`,message:e instanceof Error?e.message:String(e)})}})}async function je(e){G=!0,W?.abort(),Z({type:`cancelled`,reason:e}),await W?.shutdown({reason:`other`}).catch(()=>void 0),setTimeout(()=>process.exit(130),0)}function Me(e){try{return e.createTools({cwd:process.cwd()}).map(e=>e.getName())}catch(e){process.stderr.write(`robota: could not enumerate the composed tool surface: ${e instanceof Error?e.message:String(e)}\n`);return}}function Ne(e){q=e;try{J?.applyParentSettings?.(e)}catch(e){Y??=e instanceof Error?e.message:String(e),W?.abort()}}function Pe(e){process.send===void 0&&(process.stderr.write(`robota: subagent worker mode requires an IPC channel; it is started by the agent runtime, not by hand.
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("node:child_process"),t=require("node:fs"),n=require("node:path"),r=require("@robota-sdk/agent-executor"),i=require("@robota-sdk/agent-process"),a=require("@robota-sdk/agent-core"),o=require("@robota-sdk/agent-framework");function s(e){return{provider:{model:e.provider.model},permissions:e.permissions,defaultTrustLevel:e.defaultTrustLevel,...e.hooks===void 0?{}:{hooks:e.hooks}}}function c(e){return{agentsMd:e.agentsMd,projectNotesMd:e.projectNotesMd}}const l={name:{kind:`string`,required:!0},description:{kind:`string`,required:!0},systemPrompt:{kind:`string`,required:!0},model:{kind:`string`,required:!1},effort:{kind:`effort`,required:!1},role:{kind:`string`,required:!1},maxTurns:{kind:`number`,required:!1},tools:{kind:`string[]`,required:!1},disallowedTools:{kind:`string[]`,required:!1}},u={agentsMd:{kind:`string`,required:!0},projectNotesMd:{kind:`string`,required:!0},memoryMd:{kind:`string`,required:!1},taskContext:{kind:`string`,required:!1},compactInstructions:{kind:`string`,required:!1},agentsFileEntries:{kind:`file-entry[]`,required:!1},projectNotesFileEntries:{kind:`file-entry[]`,required:!1}};function d(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function f(e){return Array.isArray(e)&&e.every(e=>typeof e==`string`)}function p(e){return d(e)&&typeof e.filePath==`string`&&typeof e.content==`string`&&typeof e.contentHash==`string`}function m(e,t){switch(e){case`string`:return typeof t==`string`;case`number`:return typeof t==`number`&&Number.isFinite(t);case`effort`:return typeof t==`string`&&(0,a.isModelEffort)(t);case`string[]`:return f(t);case`file-entry[]`:return Array.isArray(t)&&t.every(p)}}function h(e,t){let n={};for(let r of Object.keys(t)){let t=e[r];t!==void 0&&(n[r]=t)}return n}function g(e,t,n){if(!d(t))return{ok:!1,reason:`${e}: expected an object`};for(let[r,i]of Object.entries(n)){let n=t[r];if(n===void 0){if(i.required)return{ok:!1,reason:`${e}.${r}: required`};continue}if(!m(i.kind,n))return{ok:!1,reason:`${e}.${r}: expected ${i.kind}`}}return{ok:!0,value:h(t,n)}}function _(e){return h(e,l)}function v(e){return g(`agentDefinition`,e,l)}function y(e){let t={name:e.name,description:e.description,systemPrompt:e.systemPrompt};return e.model!==void 0&&(t.model=e.model),e.effort!==void 0&&(t.effort=e.effort),e.role!==void 0&&(t.role=e.role),e.maxTurns!==void 0&&(t.maxTurns=e.maxTurns),e.tools!==void 0&&(t.tools=[...e.tools]),e.disallowedTools!==void 0&&(t.disallowedTools=[...e.disallowedTools]),t}function b(e){return h(e,u)}function x(e){return g(`parentContext`,e,u)}function S(e){let t={agentsMd:e.agentsMd,projectNotesMd:e.projectNotesMd};return e.memoryMd!==void 0&&(t.memoryMd=e.memoryMd),e.taskContext!==void 0&&(t.taskContext=e.taskContext),e.compactInstructions!==void 0&&(t.compactInstructions=e.compactInstructions),e.agentsFileEntries!==void 0&&(t.agentsFileEntries=e.agentsFileEntries.map(e=>({...e}))),e.projectNotesFileEntries!==void 0&&(t.projectNotesFileEntries=e.projectNotesFileEntries.map(e=>({...e}))),t}function ee(e){return e.sessionTiers===void 0?{}:{sessionTiers:e.sessionTiers}}async function C(e){let{sandboxClient:t,sandboxType:n}=e;return t?.snapshot===void 0||n===void 0?{}:{sandboxProjection:{type:n,snapshotId:await t.snapshot()}}}function w(e,t,n,i,o){let s=n.providerDefinitions,c=(n.providerConfig??t.config.provider).name;if((0,a.findProviderDefinition)(s,c)===void 0)throw new r.BackgroundTaskError(`validation`,`No provider definition for "${c}" was given to the subagent runner, so the connection a child would make cannot be checked; the subagent was not started.`);let l=E(n.providerConfig,t,e,s),u=(0,r.connectionEnvironmentNames)(l,s),d=(0,r.findConnectionEnvironmentDivergence)(u,i,o);if(d!==void 0)throw new r.BackgroundTaskError(`validation`,`The subagent's environment sets ${d} differently from this session, which would change where its provider connects or which credential it sends; the subagent was not started.`);return{providerProfile:l,connectionCheck:(0,r.sealConnectionEnvironment)(u,o)}}function te(e,t,n){let r=ne(e.request.agentType,t.customAgentRegistry,t.builtInAgents,t.agentDefinitions),i={taskId:e.taskId,request:e.request,...e.worktree?{worktree:e.worktree}:{},agentDefinition:_(re(r,e)),parentConfig:s(t.getParentPermissionRules===void 0?t.config:{...t.config,permissions:t.getParentPermissionRules()}),parentContext:b(c(t.context)),...n.connection??w(e,t,n,process.env,process.env),permissionMode:t.getParentPermissionMode?.()??t.permissionMode,...ee(t),...n.parentSandboxSettings===void 0?{}:{parentSandboxSettings:n.parentSandboxSettings},...n.logsDir?{logsDir:n.logsDir}:{}};return C(t).then(e=>({...i,...e}))}function ne(e,t,n,i){let a=t?.(e)??n?.find(t=>t.name===e)??i?.find(t=>t.name===e);if(!a)throw new r.BackgroundTaskError(`validation`,`Unknown agent type: ${e}`);return a}function re(e,t){return{...e,...t.request.model?{model:t.request.model}:{},...t.request.effort===void 0?{}:{effort:t.request.effort},...t.request.allowedTools?{tools:t.request.allowedTools}:{},...t.request.disallowedTools?{disallowedTools:t.request.disallowedTools}:{}}}function T(e,t){return e.apiKeyEnv===void 0?e.apiKey===void 0?t===void 0?{}:t.startsWith(`$ENV:`)?{apiKeyEnv:t.slice(5)}:{apiKey:t}:{apiKey:e.apiKey}:{apiKeyEnv:e.apiKeyEnv}}function E(e,t,n,r){let i=e??t.config.provider,o=(0,a.findProviderDefinition)(r,i.name)?.defaults??{},s=i.baseURL??o.baseURL,c=i.options??o.options,l=T(i,o.apiKey);return{...e===void 0&&t.config.currentProvider!==void 0?{profileName:t.config.currentProvider}:{},type:i.name,model:n.request.model??i.model,...l,...s===void 0?{}:{baseURL:s},...i.timeout===void 0?{}:{timeout:i.timeout},...c===void 0?{}:{options:c}}}function D(e){return typeof e==`object`&&!!e}function ie(e){if(!D(e)||!O(e,`nonce`)||!O(e,`digest`))return!1;let t=e.names;return Array.isArray(t)&&t.every(e=>typeof e==`string`)}function O(e,t){return typeof e[t]==`string`}function k(e,t){return O(e,t)}function ae(e,t){return O(e,t)}function oe(e,t){return e[t]===void 0||typeof e[t]==`string`}function se(e){if(e.usage===void 0)return!0;let t=e.usage;return D(t)?typeof t.promptTokens==`number`&&typeof t.completionTokens==`number`&&typeof t.totalTokens==`number`:!1}function ce(e){if(e.composedToolNames===void 0)return!0;let t=e.composedToolNames;return Array.isArray(t)?t.every(e=>typeof e==`string`):!1}function le(e){return!D(e)||!ae(e,`taskId`)||!D(e.request)||!k(e.request,`agentType`)||!k(e.request,`prompt`)||!k(e.request,`permissionPolicy`)||!k(e.request,`cwd`)||!oe(e.request,`resumeSessionId`)||e.worktree!==void 0&&(!D(e.worktree)||!O(e.worktree,`path`))||!v(e.agentDefinition).ok||!D(e.parentConfig)||!x(e.parentContext).ok||!D(e.providerProfile)||!O(e.providerProfile,`type`)||!O(e.providerProfile,`model`)||e.parentSandboxSettings!==void 0&&!D(e.parentSandboxSettings)?!1:ie(e.connectionCheck)}function A(e){if(!D(e)||!O(e,`type`))return!1;switch(e.type){case`start`:return le(e.payload);case`send`:return O(e,`prompt`);case`cancel`:return e.reason===void 0||typeof e.reason==`string`;case`sandbox_settings`:return D(e.settings);case`permission_response`:return O(e,`requestId`)&&ue(e.result);default:return!1}}function ue(e){return typeof e==`boolean`||e===`allow-session`||e===`allow-project`}function j(e){if(!D(e)||!O(e,`type`))return!1;switch(e.type){case`ready`:return ce(e);case`text_delta`:return O(e,`delta`);case`tool_start`:return O(e,`toolName`);case`tool_end`:return O(e,`toolName`)&&typeof e.success==`boolean`;case`permission_request`:return O(e,`requestId`)&&O(e,`toolName`);case`result`:return O(e,`output`)&&se(e);case`error`:return O(e,`message`);case`cancelled`:return e.reason===void 0||typeof e.reason==`string`;default:return!1}}const de=process.platform!==`win32`;function fe(e,t){return new Promise(n=>{if(e.exitCode!==null||e.signalCode!==null){n();return}let r=setTimeout(()=>{e.removeListener(`exit`,i),n()},t);r.unref?.();let i=()=>{clearTimeout(r),n()};e.once(`exit`,i)})}const M=new WeakMap;function N(e){let t=e.stderr;if(!t)return;let n=(0,a.createBoundedOutput)({maxBytes:4096,retain:`tail`,truncationMarker:()=>``});M.set(e,n),t.on(`error`,()=>{}),t.on(`data`,e=>n.append(e))}function P(e){return(M.get(e)?.toString()??``).trim()}function F(e,t,n,i,a,o){switch(e.type){case`ready`:t();break;case`result`:n(e);break;case`error`:i(new r.BackgroundTaskError(`runner`,e.message));break;case`cancelled`:i(new r.BackgroundTaskError(`runner`,e.reason??`Subagent worker cancelled`));break;case`text_delta`:a?.({type:`background_task_text_delta`,delta:e.delta});break;case`tool_start`:a?.({type:`background_task_tool_start`,toolName:e.toolName,firstArg:I(e.toolArgs)});break;case`tool_end`:a?.({type:`background_task_tool_end`,toolName:e.toolName,success:e.success});break;case`permission_request`:o?.(e);break;default:i(new r.BackgroundTaskError(`runner`,`Unhandled subagent worker message`))}}function I(e){if(!e)return;let t=Object.values(e)[0];if(t!==void 0)return typeof t==`object`?JSON.stringify(t):String(t)}function L(e,t){return new Promise((n,i)=>{if(!e.connected){i(new r.BackgroundTaskError(`crash`,`Subagent worker IPC channel is closed`));return}e.send(t,e=>{if(e){i(e);return}n()})})}async function R(e,t){await(0,i.killProcessTree)(e.child,{graceMs:e.killGraceMs,processGroup:de,preKill:async()=>{e.child.connected&&(await L(e.child,{type:`cancel`,reason:t}).catch(()=>void 0),await fe(e.child,e.killGraceMs))}})}function z(e){return new Promise((t,n)=>{new B(e,t,n).start()})}var B=class{options;resolve;reject;settled=!1;started=!1;ready=!1;timeoutTimer;handshakeTimer;handshakeBudgetMs;payload;deniedToolCallCounts={"no-approver":0,"denied-by-person":0,"approver-error":0,cancelled:0};pendingPermissionRequests=new Map;constructor(e,t,n){this.options=e,this.resolve=t,this.reject=n;let i=e.handshakeBudgetMs;this.handshakeBudgetMs=i!==void 0&&i>0?i:3e4,this.payload=e.payload.catch(e=>{this.rejectOnce(e instanceof Error?e:Error(String(e)))}),this.timeoutTimer=pe(this.options.runtime,e=>this.rejectOnce(e)),this.handshakeTimer=setTimeout(()=>{this.ready||this.settled||(R(this.options.runtime,`Subagent worker never signalled ready`),this.rejectOnce(new r.BackgroundTaskError(`runner`,`Subagent worker never signalled ready within ${this.handshakeBudgetMs}ms. Its entry must dispatch worker mode before starting the host application.`)))},this.handshakeBudgetMs),this.handshakeTimer.unref?.()}start(){let{child:e}=this.options.runtime;e.on(`message`,this.onMessage),e.on(`error`,this.onError),e.on(`exit`,this.onExit),e.once(`spawn`,()=>{setImmediate(this.startWorker)})}startWorker=()=>{if(this.started)return;this.started=!0;let{child:e}=this.options.runtime;this.payload.then(t=>t===void 0?void 0:L(e,{type:`start`,payload:t})).catch(e=>{this.rejectOnce(e instanceof Error?e:Error(String(e)))})};onMessage=e=>{if(!j(e)){this.rejectOnce(new r.BackgroundTaskError(`runner`,`Received malformed subagent worker message`));return}this.ready=!0,clearTimeout(this.handshakeTimer);let{job:t}=this.options.runtime;F(e,this.startWorker,this.resolveOnce,this.rejectOnce,t.emit,this.onPermissionRequest)};onPermissionRequest=e=>{let t=this.answerPermissionRequest(e).finally(()=>{this.pendingPermissionRequests.delete(e.requestId)});this.pendingPermissionRequests.set(e.requestId,t)};async answerPermissionRequest(e){let{reason:t,result:n}=await this.askApprover(e);t!==void 0&&(this.deniedToolCallCounts[t]+=1);let{child:r}=this.options.runtime;r.connected&&await L(r,{type:`permission_response`,requestId:e.requestId,result:n}).catch(()=>void 0)}async askApprover(e){let t=this.options.permissionApprover;if(t===void 0)return{reason:`no-approver`,result:!1};try{let n=await t(e.toolName,e.toolArgs??{},this.options.permissionAbort.signal);return n===!1?this.options.permissionAbort.signal.aborted?{reason:`cancelled`,result:!1}:{reason:`denied-by-person`,result:!1}:{result:n}}catch{return{reason:`approver-error`,result:!1}}}onError=e=>{this.rejectOnce(new r.BackgroundTaskError(`crash`,e.message))};onExit=(e,t)=>{this.settled||this.rejectOnce(new r.BackgroundTaskError(`crash`,ge(e,t,P(this.options.runtime.child))))};resolveOnce=e=>{this.settled||(this.settled=!0,this.settleAfterPendingPermissionRequests(()=>{let{runtime:t,resolveTranscriptPath:n}=this.options;this.resolve(me(t.job,e,n,this.deniedToolCallCounts))}))};rejectOnce=e=>{this.settled||(this.settled=!0,this.settleAfterPendingPermissionRequests(()=>this.reject(e)))};async settleAfterPendingPermissionRequests(e){this.options.permissionAbort.abort(),this.clearTimers(),this.cleanup(),await Promise.all(this.pendingPermissionRequests.values()),e()}clearTimers(){this.timeoutTimer&&clearTimeout(this.timeoutTimer),clearTimeout(this.handshakeTimer)}cleanup(){let{child:e}=this.options.runtime;e.off(`message`,this.onMessage),e.off(`error`,this.onError),e.off(`exit`,this.onExit)}};function V(e){let t=!1,n=()=>{};return{promise:new Promise((e,t)=>{n=t}),reject(i){t||(t=!0,n(new r.BackgroundTaskError(`runner`,i??`Subagent job cancelled: ${e}`)))}}}function pe(e,t){if(e.job.request.timeoutMs)return setTimeout(()=>{R(e,`Subagent worker timed out`),t(new r.BackgroundTaskError(`timeout`,`Subagent worker timed out`))},e.job.request.timeoutMs)}function me(e,t,n,r){let i=n(e),a=he(r);return{taskId:e.taskId,output:t.output,...i?{metadata:{transcriptPath:i,logPath:i}}:{},...t.usage?{usage:t.usage}:{},...a?{deniedToolCalls:a}:{}}}function he(e){let t=Object.values(e).reduce((e,t)=>e+t,0);return t===0?void 0:{total:t,byReason:{...e}}}function ge(e,t,n){return`Subagent worker exited before result: ${t===null?`exit code ${e===null?`unknown`:e}`:`signal ${t}`}${n.length>0?`: ${n}`:``}`}const H=`--__agent-subagent-worker`;function _e(e){return e.includes(H)}const ve=process.platform!==`win32`;function ye(e){return t=>{let n=new U(t,e);return e.worktreeIsolation===!1?n:(0,r.createWorktreeSubagentRunner)({runner:n,worktreeAdapter:e.worktreeAdapter,hooks:t.config.hooks,hookTypeExecutors:t.hookTypeExecutors})}}var U=class{deps;workerEntry;killGraceMs;handshakeBudgetMs;providerConfig;providerDefinitions;env;expectedEnvironment;inheritEnvironment;logsDir;parentSandboxSettings;watchParentSandboxSettings;constructor(e,t){if(this.deps=e,this.workerEntry=t.workerEntry,this.killGraceMs=t.killGraceMs??i.DEFAULT_KILL_GRACE_MS,this.handshakeBudgetMs=t.handshakeBudgetMs,this.providerConfig=t.providerConfig,this.providerDefinitions=t.providerDefinitions,this.env=t.env,this.expectedEnvironment=t.expectedEnvironment,this.inheritEnvironment=t.inheritEnvironment!==!1,!this.inheritEnvironment&&this.expectedEnvironment===void 0)throw Error(`An explicit expected environment is required when child inheritance is disabled.`);this.logsDir=t.logsDir,this.parentSandboxSettings=t.parentSandboxSettings,this.watchParentSandboxSettings=t.watchParentSandboxSettings}start(t){let n=this.workerEntry,i=this.inheritEnvironment?{...process.env,...this.env??{}}:{...this.env??{}},a=w(t,this.deps,{...this.providerConfig===void 0?{}:{providerConfig:this.providerConfig},providerDefinitions:this.providerDefinitions},this.expectedEnvironment??process.env,i),o=(0,e.spawn)(n.execPath,[...n.execArgv??[],...n.args,H],{cwd:(0,r.subagentExecutionRoot)(t),env:i,stdio:[`ignore`,`ignore`,`pipe`,`ipc`],detached:ve});N(o),this.forwardSandboxSettingChanges(o);let s={job:t,child:o,killGraceMs:this.killGraceMs},c=this.createStartPayload(t,a),l=new AbortController,u=this.permissionApprover(t),d=z({runtime:s,payload:c,...this.handshakeBudgetMs===void 0?{}:{handshakeBudgetMs:this.handshakeBudgetMs},resolveTranscriptPath:e=>this.resolveTranscriptPath(e),permissionAbort:l,...u===void 0?{}:{permissionApprover:u}}),f=V(t.taskId);d.catch(()=>void 0);let p=Promise.race([d,f.promise]);p.catch(()=>void 0);let m=this.resolveTranscriptPath(t);return{taskId:t.taskId,...o.pid!==void 0&&{pid:o.pid},...m!==void 0&&{transcriptPath:m,logPath:m},result:p,cancel:async e=>{l.abort(e),f.reject(e),await R(s,e)},send:async e=>{await L(o,{type:`send`,prompt:e})},...m!==void 0&&{readLog:async e=>be(t.taskId,m,e)}}}createStartPayload(e,t){let n=this.parentSandboxSettings?.();return te(e,this.deps,{connection:t,providerDefinitions:this.providerDefinitions,...this.logsDir===void 0?{}:{logsDir:this.logsDir},...n===void 0?{}:{parentSandboxSettings:n}})}forwardSandboxSettingChanges(e){let t=this.watchParentSandboxSettings?.(t=>{e.connected&&L(e,{type:`sandbox_settings`,settings:t}).catch(()=>void 0)});t!==void 0&&(e.once(`exit`,t),e.once(`error`,t))}resolveTranscriptPath(e){if(this.logsDir)return(0,n.join)(this.logsDir,e.request.parentSessionId,`subagents`,`${e.taskId}.jsonl`)}permissionApprover(e){let t=this.deps.permissionHandler;if(t===void 0)return;let n={kind:`background-agent`,label:e.request.agentType,taskId:e.taskId};return(e,r,i)=>t(e,r,{requester:n,signal:i})}};function be(e,n,i){return(0,t.existsSync)(n)?(0,r.createBackgroundTaskLogPage)(e,(0,t.readFileSync)(n,`utf8`).split(/\r?\n/).filter(Boolean),i):{taskId:e,cursor:i,lines:[]}}function xe(e,t,n){let r=e.request.resumeSessionId;if(r!==void 0){if(n===void 0)throw Error(`subagent worker: job ${e.taskId} asks to resume session ${r}, but this composition opens no session store. Register ISubagentWorkerComposition.openSessionStore at the composition root — the same place providerDefinitions is registered.`);(0,o.restoreSessionRecordIntoSession)(n,r,t)}}function Se(e,t){let n=e.request.resumeSessionId;if(n!==void 0){if(t.openSessionStore===void 0)throw Error(`subagent worker: job ${e.taskId} asks to resume session ${n}, but this composition opens no session store. Register ISubagentWorkerComposition.openSessionStore at the composition root — the same place providerDefinitions is registered.`);return t.openSessionStore({cwd:e.request.cwd})}}async function Ce(e,t){if(e===void 0)return;let n=t?.[e.type];if(n===void 0)throw Error(`subagent worker: sandbox type "${e.type}" is not registered in the worker composition. The parent is sandboxed and passed a snapshot reference, but this child cannot construct that client type. Register it in ISubagentWorkerComposition.sandboxFactories at the composition root — the same place providerDefinitions is registered, and for the same reason.`);return n(e.snapshotId)}const we={write:()=>{},writeLine:()=>{},writeMarkdown:()=>{},writeError:()=>{},prompt:()=>Promise.resolve(``),select:()=>Promise.resolve(0),spinner:()=>({stop:()=>{},update:()=>{}})};let W=null,G=!1;const K=new Map;let Te=0,q,J,Y,X=Promise.resolve();function Z(e){process.send&&process.send(e)}function Q(e,t){let n=!1,r=()=>{n||(n=!0,process.exit(t))};if(process.send){let t=setTimeout(r,2e3);t.unref?.(),process.send(e,void 0,void 0,()=>{clearTimeout(t),r()})}else r()}function Ee(e){try{return(0,a.sumHistoryUsage)(e.getFullHistory())}catch{return}}async function De(e,t){try{if(!(0,r.verifyConnectionEnvironment)(e.connectionCheck,process.env))throw Error(`The provider connection environment changed after the parent checked it; the subagent was not started.`);let n=await Ce(e.sandboxProjection,t.sandboxFactories),i=(0,r.createProviderFromExactProfile)(e.providerProfile,e.request.model,t.providerDefinitions),a=e.logsDir?(0,o.createSubagentLogger)(e.request.parentSessionId,e.taskId,e.logsDir):void 0,s=Se(e,t),c=q??e.parentSandboxSettings;J=n===void 0?t.createSandbox?.({cwd:(0,r.subagentExecutionRoot)(e),...c===void 0?{}:{parentSettings:c}}):void 0;let l=n??J?.client;W=(0,o.createSubagentSession)({agentDefinition:y(e.agentDefinition),parentConfig:e.parentConfig,parentContext:S(e.parentContext),parentTools:t.createTools({cwd:(0,r.subagentExecutionRoot)(e),...l===void 0?{}:{sandboxClient:l},...e.sessionTiers===void 0?{}:{sessionTiers:e.sessionTiers}}),cwd:(0,r.subagentExecutionRoot)(e),provider:i,terminal:we,sessionId:e.request.resumeSessionId??e.taskId,...s===void 0?{}:{sessionStore:s},...a?{sessionLogger:a}:{},permissionMode:e.permissionMode,...J?.commandSandbox===void 0?{}:{commandSandbox:J.commandSandbox},...e.request.permissionPolicy===void 0?{}:{permissionPolicy:e.request.permissionPolicy},...e.request.allowedTools===void 0?{}:{taskAllowedTools:e.request.allowedTools},...e.request.disallowedTools===void 0?{}:{taskDisallowedTools:e.request.disallowedTools},hooks:e.parentConfig.hooks,...t.createHookTypeExecutors===void 0?{}:{hookTypeExecutors:t.createHookTypeExecutors({cwd:(0,r.subagentExecutionRoot)(e),...l===void 0?{}:{sandboxClient:l}})},onTextDelta:e=>Z({type:`text_delta`,delta:e}),onToolExecution:Ae,permissionHandler:Oe}),xe(e,W,s);let u=await W.run(e.request.prompt);if(Y!==void 0){Q({type:`error`,message:Y},0);return}if(G){Q({type:`cancelled`,reason:`Subagent worker cancelled`},130);return}let d=Ee(W);Q({type:`result`,output:u,...d?{usage:d}:{}},0)}catch(e){if(Y!==void 0){Q({type:`error`,message:Y},0);return}if(G){Q({type:`cancelled`,reason:`Subagent worker cancelled`},130);return}Q({type:`error`,message:e instanceof Error?e.message:String(e)},0)}}function Oe(e,t){let n=`perm_${++Te}`;return new Promise(r=>{K.set(n,r),Z({type:`permission_request`,requestId:n,toolName:e,toolArgs:t})})}function ke(e,t){let n=K.get(e);n!==void 0&&(K.delete(e),n(t))}function Ae(e){if(e.type===`start`){Z({type:`tool_start`,toolName:e.toolName,toolArgs:e.toolArgs});return}Z({type:`tool_end`,toolName:e.toolName,success:e.success??!0})}function $(e){if(W===null){Z({type:`error`,message:`Subagent worker has not started`});return}X=X.then(async()=>{try{await W?.run(e)}catch(e){Z({type:`error`,message:e instanceof Error?e.message:String(e)})}})}async function je(e){G=!0,W?.abort(),Z({type:`cancelled`,reason:e}),await W?.shutdown({reason:`other`}).catch(()=>void 0),setTimeout(()=>process.exit(130),0)}function Me(e){try{return e.createTools({cwd:process.cwd()}).map(e=>e.getName())}catch(e){process.stderr.write(`agent: could not enumerate the composed tool surface: ${e instanceof Error?e.message:String(e)}\n`);return}}function Ne(e){q=e;try{J?.applyParentSettings?.(e)}catch(e){Y??=e instanceof Error?e.message:String(e),W?.abort()}}function Pe(e){process.send===void 0&&(process.stderr.write(`agent: subagent worker mode requires an IPC channel; it is started by the agent runtime, not by hand.
|
|
2
2
|
`),process.exit(2)),process.on(`message`,t=>{if(!A(t)){Z({type:`error`,message:`Malformed subagent worker parent message`});return}switch(t.type){case`start`:X=X.then(()=>De(t.payload,e));break;case`send`:$(t.prompt);break;case`cancel`:je(t.reason);break;case`sandbox_settings`:Ne(t.settings);break;case`permission_response`:ke(t.requestId,t.result);break;default:Z({type:`error`,message:`Unhandled subagent worker parent message`})}}),process.on(`disconnect`,()=>{G=!0,W?.abort(),W?.shutdown({reason:`other`}).catch(()=>void 0)});let t=Me(e);Z({type:`ready`,...t?{composedToolNames:t}:{}})}exports.ChildProcessSubagentRunner=U,exports.SUBAGENT_WORKER_MODE_FLAG=H,exports.createChildProcessSubagentRunnerFactory=ye,exports.decodeAgentDefinitionDto=v,exports.decodeParentContextDto=x,exports.encodeAgentDefinition=_,exports.encodeParentContext=b,exports.isSubagentWorkerChildMessage=j,exports.isSubagentWorkerModeArgv=_e,exports.isSubagentWorkerParentMessage=A,exports.restoreAgentDefinition=y,exports.restoreParentContext=S,exports.runSubagentWorkerMain=Pe;
|
package/dist/node/index.d.cts
CHANGED
|
@@ -21,7 +21,7 @@ import { ISerializableProviderProfile, ISubagentSpawnRequest } from "@robota-sdk
|
|
|
21
21
|
* Deliberately not a plausible user flag: it is part of an internal process contract, and a user
|
|
22
22
|
* who types it gets a loud refusal rather than a half-started worker.
|
|
23
23
|
*/
|
|
24
|
-
declare const SUBAGENT_WORKER_MODE_FLAG = "--
|
|
24
|
+
declare const SUBAGENT_WORKER_MODE_FLAG = "--__agent-subagent-worker";
|
|
25
25
|
/**
|
|
26
26
|
* How to spawn a copy of the running artifact in subagent-worker mode.
|
|
27
27
|
*
|
|
@@ -61,7 +61,7 @@ type TResumeSessionStore = Parameters<typeof restoreSessionRecordIntoSession>[0]
|
|
|
61
61
|
* `createDefaultProviderDefinitions()` and building the child's surface from them, while the
|
|
62
62
|
* composition root had already handed the runner the fully composed surface. So a product's custom
|
|
63
63
|
* providers and pack-owned tools reached an in-process subagent and not a child-process one, and
|
|
64
|
-
* ARCH-006's invariant — every tool
|
|
64
|
+
* ARCH-006's invariant — every tool agent runs comes from a pack — was false in the child.
|
|
65
65
|
*
|
|
66
66
|
* **Why a recipe rather than the instances.** A composition cannot be projected across a process
|
|
67
67
|
* boundary, because it is code: `createProvider` is a function and a tool carries `execute`. The two
|
|
@@ -72,8 +72,11 @@ type TResumeSessionStore = Parameters<typeof restoreSessionRecordIntoSession>[0]
|
|
|
72
72
|
* comparable product does.
|
|
73
73
|
*/
|
|
74
74
|
interface ISubagentWorkerComposition {
|
|
75
|
-
/** Product-selected
|
|
76
|
-
createHookTypeExecutors?: (
|
|
75
|
+
/** Product-selected hooks receive the same execution boundary as the child tools. */
|
|
76
|
+
createHookTypeExecutors?: (context: {
|
|
77
|
+
readonly cwd: string;
|
|
78
|
+
readonly sandboxClient?: TProjectedSandboxClient;
|
|
79
|
+
}) => IHookTypeExecutor[];
|
|
77
80
|
/**
|
|
78
81
|
* The product's tool surface for THIS subagent's execution root.
|
|
79
82
|
*
|
|
@@ -237,6 +240,10 @@ interface IChildProcessSubagentRunnerOptions {
|
|
|
237
240
|
*/
|
|
238
241
|
handshakeBudgetMs?: number;
|
|
239
242
|
env?: NodeJS.ProcessEnv;
|
|
243
|
+
/** Explicit host snapshot used to resolve this provider; defaults to the live process environment. */
|
|
244
|
+
expectedEnvironment?: NodeJS.ProcessEnv;
|
|
245
|
+
/** A host can supply a curated child environment without inheriting unrelated process secrets. */
|
|
246
|
+
inheritEnvironment?: boolean;
|
|
240
247
|
worktreeIsolation?: boolean;
|
|
241
248
|
worktreeAdapter: ISubagentWorktreeAdapter;
|
|
242
249
|
logsDir?: string;
|
|
@@ -262,6 +269,8 @@ declare class ChildProcessSubagentRunner implements ISubagentRunner {
|
|
|
262
269
|
private readonly providerConfig?;
|
|
263
270
|
private readonly providerDefinitions;
|
|
264
271
|
private readonly env?;
|
|
272
|
+
private readonly expectedEnvironment?;
|
|
273
|
+
private readonly inheritEnvironment;
|
|
265
274
|
private readonly logsDir?;
|
|
266
275
|
private readonly parentSandboxSettings?;
|
|
267
276
|
private readonly watchParentSandboxSettings?;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/worker-entry.ts","../../src/worker-composition.ts","../../src/child-process-subagent-runner.ts","../../src/subagent-worker-start-dto.ts","../../src/child-process-subagent-ipc.ts","../../src/child-process-subagent-worker.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;cAmBa;;;;;;;;;;UAWI;;WAEN;;WAEA;;WAEA;;;iBAIK,yBAAyB;;;;;;;;;KC3B7B,sBAAsB,kBAAkB;;;;;;;;;;;;;;;;;;;;;;UAuBnC;;EAEf,
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/worker-entry.ts","../../src/worker-composition.ts","../../src/child-process-subagent-runner.ts","../../src/subagent-worker-start-dto.ts","../../src/child-process-subagent-ipc.ts","../../src/child-process-subagent-worker.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;cAmBa;;;;;;;;;;UAWI;;WAEN;;WAEA;;WAEA;;;iBAIK,yBAAyB;;;;;;;;;KC3B7B,sBAAsB,kBAAkB;;;;;;;;;;;;;;;;;;;;;;UAuBnC;;EAEf,2BAA2B;aAChB;aACA,gBAAgB;QACrB;;;;;;;;;EASN,YAAY;aACD;;;;;;;;;;;;;;aAcA;;eAEE;;;;;;;;;;aAUF,gBAAgB;MACvB;;;;;;WAOK,8BAA8B;;;;;;;;;;;;;;;;;;;;;WAsB9B,mBAAmB,SAAS,eAAe;;;;;;;;;;;;;;WAe3C,oBAAoB;aAAoB;QAAkB;;;;;;;;;;WAW1D,iBAAiB;aACf;;aAEA,iBAAiB;QACtB;;;KAII,yBAAyB,SAAS;;UAG7B;WACN,QAAQ;WACR,iBAAiB;;;;;;;WAOjB,uBAAuB,UAAU;;;;;;;;KAShC,yBAAyB,uBAAuB,QAAQ;;;;;;;;;;;;;KAcxD;;;;;;;UAQK;WACN;WACA;;;;UC5HM;;;;;;;EAOf,aAAa;EACb,iBAAiB;;;;;;EAMjB,8BAA8B;EAC9B;;;;;EAKA;EACA,MAAM,OAAO;;EAEb,sBAAsB,OAAO;;EAE7B;EACA;EACA,iBAAiB;EACjB;;;;;;EAMA,8BAA8B;;;;;;EAM9B,8BAA8B,WAAW,UAAU;;iBAGrC,wCACd,SAAS,qCACR;cAaU,sCAAsC;mBAc9B;mBAbF;mBACA;mBACA;mBACA;mBACA;mBACA;mBACA;mBACA;mBACA;mBACA;mBACA;EAGE,YAAA,MAAM,8BACvB,SAAS;EAkBX,MAAM,KAAK,oBAAoB;;;;;;;;;UAoGvB;UAaA;UAYA;;;;;;;;;UAaA;;;;;;;;KCtQL,sBAAsB;UAEV;WACN;WACA;WACA;WACA;WACA,SAAS;WACT;WACA;WACA;WACA;;UAGM;WACN;WACA;WACA;;UAGM;WACN;WACA;WACA;WACA;WACA;WACA,6BAA6B;WAC7B,mCAAmC;;KAmClC,iBAAiB;WAChB;WAAmB,OAAO;;WAAoB;WAAoB;;iBAmE/D,sBACd,YAAY,mBACX;iBAOa,yBACd,iBACC,iBAAiB;;iBASJ,uBAAuB,KAAK,oCAAoC;;iBAgBhE,oBACd,SAAS,yBACR;iBAOa,uBACd,iBACC,iBAAiB;iBAIJ,qBAAqB,KAAK,kCAAkC;;;KClMhE;;UAKK;WACN;aAAqB;;WACrB,aAAa;WACb,mBAAmB;WACnB,QAAQ;;UAGF;EACf;EACA,SAAS;;;;;;;;;;EAUT;aAAsB;aAAuB;;;EAE7C,iBAAiB;;;;;;;;;;;EAWjB,cAAc;;;;;;;EAOd,eAAe;EACf,iBAAiB;;;;;EAKjB,iBAAiB;;;;;;;;;;;;EAYjB,oBAAoB;;;;;;;EAOpB;aAA0B;;;;;;;EAM1B,wBAAwB;EACxB,iBAAiB;EACjB;;UAGe;EACf;EACA,SAAS;;UAGM;EACf;EACA;;UAGe;EACf;EACA;;;UAIe;EACf;EACA,UAAU;;;;;;;KAQA;;;;;;UAOK;EACf;EACA;EACA,QAAQ;;KAGE,+BACR,8BACA,6BACA,+BACA,wCACA;UAEa;EACf;;;;;;;;;EASA;;UAGe;EACf;EACA;;UAGe;EACf;EACA;EACA,WAAW;;UAGI;EACf;EACA;EACA;;;;;;;UAQe;EACf;EACA;EACA;EACA,WAAW;;UAGI;EACf;EACA;;EAEA,QAAQ;;UAGO;EACf;EACA;;UAGe;EACf;EACA;;KAGU,8BACR,8BACA,kCACA,kCACA,gCACA,0CACA,+BACA,8BACA;iBAkHY,8BACd,OAAO,2BACN,SAAS;iBAuBI,6BACd,OAAO,2BACN,SAAS;;;;;;;;;;;;;;iBCDI,sBAAsB,aAAa"}
|
package/dist/node/index.d.ts
CHANGED
|
@@ -21,7 +21,7 @@ import { ISerializableProviderProfile, ISubagentSpawnRequest } from "@robota-sdk
|
|
|
21
21
|
* Deliberately not a plausible user flag: it is part of an internal process contract, and a user
|
|
22
22
|
* who types it gets a loud refusal rather than a half-started worker.
|
|
23
23
|
*/
|
|
24
|
-
declare const SUBAGENT_WORKER_MODE_FLAG = "--
|
|
24
|
+
declare const SUBAGENT_WORKER_MODE_FLAG = "--__agent-subagent-worker";
|
|
25
25
|
/**
|
|
26
26
|
* How to spawn a copy of the running artifact in subagent-worker mode.
|
|
27
27
|
*
|
|
@@ -61,7 +61,7 @@ type TResumeSessionStore = Parameters<typeof restoreSessionRecordIntoSession>[0]
|
|
|
61
61
|
* `createDefaultProviderDefinitions()` and building the child's surface from them, while the
|
|
62
62
|
* composition root had already handed the runner the fully composed surface. So a product's custom
|
|
63
63
|
* providers and pack-owned tools reached an in-process subagent and not a child-process one, and
|
|
64
|
-
* ARCH-006's invariant — every tool
|
|
64
|
+
* ARCH-006's invariant — every tool agent runs comes from a pack — was false in the child.
|
|
65
65
|
*
|
|
66
66
|
* **Why a recipe rather than the instances.** A composition cannot be projected across a process
|
|
67
67
|
* boundary, because it is code: `createProvider` is a function and a tool carries `execute`. The two
|
|
@@ -72,8 +72,11 @@ type TResumeSessionStore = Parameters<typeof restoreSessionRecordIntoSession>[0]
|
|
|
72
72
|
* comparable product does.
|
|
73
73
|
*/
|
|
74
74
|
interface ISubagentWorkerComposition {
|
|
75
|
-
/** Product-selected
|
|
76
|
-
createHookTypeExecutors?: (
|
|
75
|
+
/** Product-selected hooks receive the same execution boundary as the child tools. */
|
|
76
|
+
createHookTypeExecutors?: (context: {
|
|
77
|
+
readonly cwd: string;
|
|
78
|
+
readonly sandboxClient?: TProjectedSandboxClient;
|
|
79
|
+
}) => IHookTypeExecutor[];
|
|
77
80
|
/**
|
|
78
81
|
* The product's tool surface for THIS subagent's execution root.
|
|
79
82
|
*
|
|
@@ -237,6 +240,10 @@ interface IChildProcessSubagentRunnerOptions {
|
|
|
237
240
|
*/
|
|
238
241
|
handshakeBudgetMs?: number;
|
|
239
242
|
env?: NodeJS.ProcessEnv;
|
|
243
|
+
/** Explicit host snapshot used to resolve this provider; defaults to the live process environment. */
|
|
244
|
+
expectedEnvironment?: NodeJS.ProcessEnv;
|
|
245
|
+
/** A host can supply a curated child environment without inheriting unrelated process secrets. */
|
|
246
|
+
inheritEnvironment?: boolean;
|
|
240
247
|
worktreeIsolation?: boolean;
|
|
241
248
|
worktreeAdapter: ISubagentWorktreeAdapter;
|
|
242
249
|
logsDir?: string;
|
|
@@ -262,6 +269,8 @@ declare class ChildProcessSubagentRunner implements ISubagentRunner {
|
|
|
262
269
|
private readonly providerConfig?;
|
|
263
270
|
private readonly providerDefinitions;
|
|
264
271
|
private readonly env?;
|
|
272
|
+
private readonly expectedEnvironment?;
|
|
273
|
+
private readonly inheritEnvironment;
|
|
265
274
|
private readonly logsDir?;
|
|
266
275
|
private readonly parentSandboxSettings?;
|
|
267
276
|
private readonly watchParentSandboxSettings?;
|
package/dist/node/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/worker-entry.ts","../../src/worker-composition.ts","../../src/child-process-subagent-runner.ts","../../src/subagent-worker-start-dto.ts","../../src/child-process-subagent-ipc.ts","../../src/child-process-subagent-worker.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;cAmBa;;;;;;;;;;UAWI;;WAEN;;WAEA;;WAEA;;;iBAIK,yBAAyB;;;;;;;;;KC3B7B,sBAAsB,kBAAkB;;;;;;;;;;;;;;;;;;;;;;UAuBnC;;EAEf,
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/worker-entry.ts","../../src/worker-composition.ts","../../src/child-process-subagent-runner.ts","../../src/subagent-worker-start-dto.ts","../../src/child-process-subagent-ipc.ts","../../src/child-process-subagent-worker.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;cAmBa;;;;;;;;;;UAWI;;WAEN;;WAEA;;WAEA;;;iBAIK,yBAAyB;;;;;;;;;KC3B7B,sBAAsB,kBAAkB;;;;;;;;;;;;;;;;;;;;;;UAuBnC;;EAEf,2BAA2B;aAChB;aACA,gBAAgB;QACrB;;;;;;;;;EASN,YAAY;aACD;;;;;;;;;;;;;;aAcA;;eAEE;;;;;;;;;;aAUF,gBAAgB;MACvB;;;;;;WAOK,8BAA8B;;;;;;;;;;;;;;;;;;;;;WAsB9B,mBAAmB,SAAS,eAAe;;;;;;;;;;;;;;WAe3C,oBAAoB;aAAoB;QAAkB;;;;;;;;;;WAW1D,iBAAiB;aACf;;aAEA,iBAAiB;QACtB;;;KAII,yBAAyB,SAAS;;UAG7B;WACN,QAAQ;WACR,iBAAiB;;;;;;;WAOjB,uBAAuB,UAAU;;;;;;;;KAShC,yBAAyB,uBAAuB,QAAQ;;;;;;;;;;;;;KAcxD;;;;;;;UAQK;WACN;WACA;;;;UC5HM;;;;;;;EAOf,aAAa;EACb,iBAAiB;;;;;;EAMjB,8BAA8B;EAC9B;;;;;EAKA;EACA,MAAM,OAAO;;EAEb,sBAAsB,OAAO;;EAE7B;EACA;EACA,iBAAiB;EACjB;;;;;;EAMA,8BAA8B;;;;;;EAM9B,8BAA8B,WAAW,UAAU;;iBAGrC,wCACd,SAAS,qCACR;cAaU,sCAAsC;mBAc9B;mBAbF;mBACA;mBACA;mBACA;mBACA;mBACA;mBACA;mBACA;mBACA;mBACA;mBACA;EAGE,YAAA,MAAM,8BACvB,SAAS;EAkBX,MAAM,KAAK,oBAAoB;;;;;;;;;UAoGvB;UAaA;UAYA;;;;;;;;;UAaA;;;;;;;;KCtQL,sBAAsB;UAEV;WACN;WACA;WACA;WACA;WACA,SAAS;WACT;WACA;WACA;WACA;;UAGM;WACN;WACA;WACA;;UAGM;WACN;WACA;WACA;WACA;WACA;WACA,6BAA6B;WAC7B,mCAAmC;;KAmClC,iBAAiB;WAChB;WAAmB,OAAO;;WAAoB;WAAoB;;iBAmE/D,sBACd,YAAY,mBACX;iBAOa,yBACd,iBACC,iBAAiB;;iBASJ,uBAAuB,KAAK,oCAAoC;;iBAgBhE,oBACd,SAAS,yBACR;iBAOa,uBACd,iBACC,iBAAiB;iBAIJ,qBAAqB,KAAK,kCAAkC;;;KClMhE;;UAKK;WACN;aAAqB;;WACrB,aAAa;WACb,mBAAmB;WACnB,QAAQ;;UAGF;EACf;EACA,SAAS;;;;;;;;;;EAUT;aAAsB;aAAuB;;;EAE7C,iBAAiB;;;;;;;;;;;EAWjB,cAAc;;;;;;;EAOd,eAAe;EACf,iBAAiB;;;;;EAKjB,iBAAiB;;;;;;;;;;;;EAYjB,oBAAoB;;;;;;;EAOpB;aAA0B;;;;;;;EAM1B,wBAAwB;EACxB,iBAAiB;EACjB;;UAGe;EACf;EACA,SAAS;;UAGM;EACf;EACA;;UAGe;EACf;EACA;;;UAIe;EACf;EACA,UAAU;;;;;;;KAQA;;;;;;UAOK;EACf;EACA;EACA,QAAQ;;KAGE,+BACR,8BACA,6BACA,+BACA,wCACA;UAEa;EACf;;;;;;;;;EASA;;UAGe;EACf;EACA;;UAGe;EACf;EACA;EACA,WAAW;;UAGI;EACf;EACA;EACA;;;;;;;UAQe;EACf;EACA;EACA;EACA,WAAW;;UAGI;EACf;EACA;;EAEA,QAAQ;;UAGO;EACf;EACA;;UAGe;EACf;EACA;;KAGU,8BACR,8BACA,kCACA,kCACA,gCACA,0CACA,+BACA,8BACA;iBAkHY,8BACd,OAAO,2BACN,SAAS;iBAuBI,6BACd,OAAO,2BACN,SAAS;;;;;;;;;;;;;;iBCDI,sBAAsB,aAAa"}
|
package/dist/node/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{spawn as e}from"node:child_process";import{existsSync as t,readFileSync as n}from"node:fs";import{join as r}from"node:path";import{BackgroundTaskError as i,connectionEnvironmentNames as a,createBackgroundTaskLogPage as o,createProviderFromExactProfile as s,createWorktreeSubagentRunner as c,findConnectionEnvironmentDivergence as l,sealConnectionEnvironment as u,subagentExecutionRoot as d,verifyConnectionEnvironment as f}from"@robota-sdk/agent-executor";import{DEFAULT_KILL_GRACE_MS as p,killProcessTree as m}from"@robota-sdk/agent-process";import{createBoundedOutput as ee,findProviderDefinition as h,isModelEffort as te,sumHistoryUsage as ne}from"@robota-sdk/agent-core";import{createSubagentLogger as g,createSubagentSession as re,restoreSessionRecordIntoSession as ie}from"@robota-sdk/agent-framework";function ae(e){return{provider:{model:e.provider.model},permissions:e.permissions,defaultTrustLevel:e.defaultTrustLevel,...e.hooks===void 0?{}:{hooks:e.hooks}}}function oe(e){return{agentsMd:e.agentsMd,projectNotesMd:e.projectNotesMd}}const _={name:{kind:`string`,required:!0},description:{kind:`string`,required:!0},systemPrompt:{kind:`string`,required:!0},model:{kind:`string`,required:!1},effort:{kind:`effort`,required:!1},role:{kind:`string`,required:!1},maxTurns:{kind:`number`,required:!1},tools:{kind:`string[]`,required:!1},disallowedTools:{kind:`string[]`,required:!1}},v={agentsMd:{kind:`string`,required:!0},projectNotesMd:{kind:`string`,required:!0},memoryMd:{kind:`string`,required:!1},taskContext:{kind:`string`,required:!1},compactInstructions:{kind:`string`,required:!1},agentsFileEntries:{kind:`file-entry[]`,required:!1},projectNotesFileEntries:{kind:`file-entry[]`,required:!1}};function y(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function se(e){return Array.isArray(e)&&e.every(e=>typeof e==`string`)}function ce(e){return y(e)&&typeof e.filePath==`string`&&typeof e.content==`string`&&typeof e.contentHash==`string`}function le(e,t){switch(e){case`string`:return typeof t==`string`;case`number`:return typeof t==`number`&&Number.isFinite(t);case`effort`:return typeof t==`string`&&te(t);case`string[]`:return se(t);case`file-entry[]`:return Array.isArray(t)&&t.every(ce)}}function b(e,t){let n={};for(let r of Object.keys(t)){let t=e[r];t!==void 0&&(n[r]=t)}return n}function x(e,t,n){if(!y(t))return{ok:!1,reason:`${e}: expected an object`};for(let[r,i]of Object.entries(n)){let n=t[r];if(n===void 0){if(i.required)return{ok:!1,reason:`${e}.${r}: required`};continue}if(!le(i.kind,n))return{ok:!1,reason:`${e}.${r}: expected ${i.kind}`}}return{ok:!0,value:b(t,n)}}function S(e){return b(e,_)}function C(e){return x(`agentDefinition`,e,_)}function w(e){let t={name:e.name,description:e.description,systemPrompt:e.systemPrompt};return e.model!==void 0&&(t.model=e.model),e.effort!==void 0&&(t.effort=e.effort),e.role!==void 0&&(t.role=e.role),e.maxTurns!==void 0&&(t.maxTurns=e.maxTurns),e.tools!==void 0&&(t.tools=[...e.tools]),e.disallowedTools!==void 0&&(t.disallowedTools=[...e.disallowedTools]),t}function T(e){return b(e,v)}function E(e){return x(`parentContext`,e,v)}function D(e){let t={agentsMd:e.agentsMd,projectNotesMd:e.projectNotesMd};return e.memoryMd!==void 0&&(t.memoryMd=e.memoryMd),e.taskContext!==void 0&&(t.taskContext=e.taskContext),e.compactInstructions!==void 0&&(t.compactInstructions=e.compactInstructions),e.agentsFileEntries!==void 0&&(t.agentsFileEntries=e.agentsFileEntries.map(e=>({...e}))),e.projectNotesFileEntries!==void 0&&(t.projectNotesFileEntries=e.projectNotesFileEntries.map(e=>({...e}))),t}function ue(e){return e.sessionTiers===void 0?{}:{sessionTiers:e.sessionTiers}}async function de(e){let{sandboxClient:t,sandboxType:n}=e;return t?.snapshot===void 0||n===void 0?{}:{sandboxProjection:{type:n,snapshotId:await t.snapshot()}}}function O(e,t,n,r,o){let s=n.providerDefinitions,c=(n.providerConfig??t.config.provider).name;if(h(s,c)===void 0)throw new i(`validation`,`No provider definition for "${c}" was given to the subagent runner, so the connection a child would make cannot be checked; the subagent was not started.`);let d=ge(n.providerConfig,t,e,s),f=a(d,s),p=l(f,r,o);if(p!==void 0)throw new i(`validation`,`The subagent's environment sets ${p} differently from this session, which would change where its provider connects or which credential it sends; the subagent was not started.`);return{providerProfile:d,connectionCheck:u(f,o)}}function fe(e,t,n){let r=pe(e.request.agentType,t.customAgentRegistry,t.builtInAgents,t.agentDefinitions),i={taskId:e.taskId,request:e.request,...e.worktree?{worktree:e.worktree}:{},agentDefinition:S(me(r,e)),parentConfig:ae(t.getParentPermissionRules===void 0?t.config:{...t.config,permissions:t.getParentPermissionRules()}),parentContext:T(oe(t.context)),...n.connection??O(e,t,n,process.env,process.env),permissionMode:t.getParentPermissionMode?.()??t.permissionMode,...ue(t),...n.parentSandboxSettings===void 0?{}:{parentSandboxSettings:n.parentSandboxSettings},...n.logsDir?{logsDir:n.logsDir}:{}};return de(t).then(e=>({...i,...e}))}function pe(e,t,n,r){let a=t?.(e)??n?.find(t=>t.name===e)??r?.find(t=>t.name===e);if(!a)throw new i(`validation`,`Unknown agent type: ${e}`);return a}function me(e,t){return{...e,...t.request.model?{model:t.request.model}:{},...t.request.effort===void 0?{}:{effort:t.request.effort},...t.request.allowedTools?{tools:t.request.allowedTools}:{},...t.request.disallowedTools?{disallowedTools:t.request.disallowedTools}:{}}}function he(e,t){return e.apiKeyEnv===void 0?e.apiKey===void 0?t===void 0?{}:t.startsWith(`$ENV:`)?{apiKeyEnv:t.slice(5)}:{apiKey:t}:{apiKey:e.apiKey}:{apiKeyEnv:e.apiKeyEnv}}function ge(e,t,n,r){let i=e??t.config.provider,a=h(r,i.name)?.defaults??{},o=i.baseURL??a.baseURL,s=i.options??a.options,c=he(i,a.apiKey);return{...e===void 0&&t.config.currentProvider!==void 0?{profileName:t.config.currentProvider}:{},type:i.name,model:n.request.model??i.model,...c,...o===void 0?{}:{baseURL:o},...i.timeout===void 0?{}:{timeout:i.timeout},...s===void 0?{}:{options:s}}}function k(e){return typeof e==`object`&&!!e}function _e(e){if(!k(e)||!A(e,`nonce`)||!A(e,`digest`))return!1;let t=e.names;return Array.isArray(t)&&t.every(e=>typeof e==`string`)}function A(e,t){return typeof e[t]==`string`}function j(e,t){return A(e,t)}function M(e,t){return A(e,t)}function N(e,t){return e[t]===void 0||typeof e[t]==`string`}function P(e){if(e.usage===void 0)return!0;let t=e.usage;return k(t)?typeof t.promptTokens==`number`&&typeof t.completionTokens==`number`&&typeof t.totalTokens==`number`:!1}function F(e){if(e.composedToolNames===void 0)return!0;let t=e.composedToolNames;return Array.isArray(t)?t.every(e=>typeof e==`string`):!1}function I(e){return!k(e)||!M(e,`taskId`)||!k(e.request)||!j(e.request,`agentType`)||!j(e.request,`prompt`)||!j(e.request,`permissionPolicy`)||!j(e.request,`cwd`)||!N(e.request,`resumeSessionId`)||e.worktree!==void 0&&(!k(e.worktree)||!A(e.worktree,`path`))||!C(e.agentDefinition).ok||!k(e.parentConfig)||!E(e.parentContext).ok||!k(e.providerProfile)||!A(e.providerProfile,`type`)||!A(e.providerProfile,`model`)||e.parentSandboxSettings!==void 0&&!k(e.parentSandboxSettings)?!1:_e(e.connectionCheck)}function L(e){if(!k(e)||!A(e,`type`))return!1;switch(e.type){case`start`:return I(e.payload);case`send`:return A(e,`prompt`);case`cancel`:return e.reason===void 0||typeof e.reason==`string`;case`sandbox_settings`:return k(e.settings);case`permission_response`:return A(e,`requestId`)&&ve(e.result);default:return!1}}function ve(e){return typeof e==`boolean`||e===`allow-session`||e===`allow-project`}function R(e){if(!k(e)||!A(e,`type`))return!1;switch(e.type){case`ready`:return F(e);case`text_delta`:return A(e,`delta`);case`tool_start`:return A(e,`toolName`);case`tool_end`:return A(e,`toolName`)&&typeof e.success==`boolean`;case`permission_request`:return A(e,`requestId`)&&A(e,`toolName`);case`result`:return A(e,`output`)&&P(e);case`error`:return A(e,`message`);case`cancelled`:return e.reason===void 0||typeof e.reason==`string`;default:return!1}}const ye=process.platform!==`win32`;function be(e,t){return new Promise(n=>{if(e.exitCode!==null||e.signalCode!==null){n();return}let r=setTimeout(()=>{e.removeListener(`exit`,i),n()},t);r.unref?.();let i=()=>{clearTimeout(r),n()};e.once(`exit`,i)})}const z=new WeakMap;function xe(e){let t=e.stderr;if(!t)return;let n=ee({maxBytes:4096,retain:`tail`,truncationMarker:()=>``});z.set(e,n),t.on(`error`,()=>{}),t.on(`data`,e=>n.append(e))}function Se(e){return(z.get(e)?.toString()??``).trim()}function Ce(e,t,n,r,a,o){switch(e.type){case`ready`:t();break;case`result`:n(e);break;case`error`:r(new i(`runner`,e.message));break;case`cancelled`:r(new i(`runner`,e.reason??`Subagent worker cancelled`));break;case`text_delta`:a?.({type:`background_task_text_delta`,delta:e.delta});break;case`tool_start`:a?.({type:`background_task_tool_start`,toolName:e.toolName,firstArg:we(e.toolArgs)});break;case`tool_end`:a?.({type:`background_task_tool_end`,toolName:e.toolName,success:e.success});break;case`permission_request`:o?.(e);break;default:r(new i(`runner`,`Unhandled subagent worker message`))}}function we(e){if(!e)return;let t=Object.values(e)[0];if(t!==void 0)return typeof t==`object`?JSON.stringify(t):String(t)}function B(e,t){return new Promise((n,r)=>{if(!e.connected){r(new i(`crash`,`Subagent worker IPC channel is closed`));return}e.send(t,e=>{if(e){r(e);return}n()})})}async function V(e,t){await m(e.child,{graceMs:e.killGraceMs,processGroup:ye,preKill:async()=>{e.child.connected&&(await B(e.child,{type:`cancel`,reason:t}).catch(()=>void 0),await be(e.child,e.killGraceMs))}})}function Te(e){return new Promise((t,n)=>{new Ee(e,t,n).start()})}var Ee=class{options;resolve;reject;settled=!1;started=!1;ready=!1;timeoutTimer;handshakeTimer;handshakeBudgetMs;payload;deniedToolCallCounts={"no-approver":0,"denied-by-person":0,"approver-error":0,cancelled:0};pendingPermissionRequests=new Map;constructor(e,t,n){this.options=e,this.resolve=t,this.reject=n;let r=e.handshakeBudgetMs;this.handshakeBudgetMs=r!==void 0&&r>0?r:3e4,this.payload=e.payload.catch(e=>{this.rejectOnce(e instanceof Error?e:Error(String(e)))}),this.timeoutTimer=Oe(this.options.runtime,e=>this.rejectOnce(e)),this.handshakeTimer=setTimeout(()=>{this.ready||this.settled||(V(this.options.runtime,`Subagent worker never signalled ready`),this.rejectOnce(new i(`runner`,`Subagent worker never signalled ready within ${this.handshakeBudgetMs}ms. Its entry must dispatch worker mode before starting the host application.`)))},this.handshakeBudgetMs),this.handshakeTimer.unref?.()}start(){let{child:e}=this.options.runtime;e.on(`message`,this.onMessage),e.on(`error`,this.onError),e.on(`exit`,this.onExit),e.once(`spawn`,()=>{setImmediate(this.startWorker)})}startWorker=()=>{if(this.started)return;this.started=!0;let{child:e}=this.options.runtime;this.payload.then(t=>t===void 0?void 0:B(e,{type:`start`,payload:t})).catch(e=>{this.rejectOnce(e instanceof Error?e:Error(String(e)))})};onMessage=e=>{if(!R(e)){this.rejectOnce(new i(`runner`,`Received malformed subagent worker message`));return}this.ready=!0,clearTimeout(this.handshakeTimer);let{job:t}=this.options.runtime;Ce(e,this.startWorker,this.resolveOnce,this.rejectOnce,t.emit,this.onPermissionRequest)};onPermissionRequest=e=>{let t=this.answerPermissionRequest(e).finally(()=>{this.pendingPermissionRequests.delete(e.requestId)});this.pendingPermissionRequests.set(e.requestId,t)};async answerPermissionRequest(e){let{reason:t,result:n}=await this.askApprover(e);t!==void 0&&(this.deniedToolCallCounts[t]+=1);let{child:r}=this.options.runtime;r.connected&&await B(r,{type:`permission_response`,requestId:e.requestId,result:n}).catch(()=>void 0)}async askApprover(e){let t=this.options.permissionApprover;if(t===void 0)return{reason:`no-approver`,result:!1};try{let n=await t(e.toolName,e.toolArgs??{},this.options.permissionAbort.signal);return n===!1?this.options.permissionAbort.signal.aborted?{reason:`cancelled`,result:!1}:{reason:`denied-by-person`,result:!1}:{result:n}}catch{return{reason:`approver-error`,result:!1}}}onError=e=>{this.rejectOnce(new i(`crash`,e.message))};onExit=(e,t)=>{this.settled||this.rejectOnce(new i(`crash`,je(e,t,Se(this.options.runtime.child))))};resolveOnce=e=>{this.settled||(this.settled=!0,this.settleAfterPendingPermissionRequests(()=>{let{runtime:t,resolveTranscriptPath:n}=this.options;this.resolve(ke(t.job,e,n,this.deniedToolCallCounts))}))};rejectOnce=e=>{this.settled||(this.settled=!0,this.settleAfterPendingPermissionRequests(()=>this.reject(e)))};async settleAfterPendingPermissionRequests(e){this.options.permissionAbort.abort(),this.clearTimers(),this.cleanup(),await Promise.all(this.pendingPermissionRequests.values()),e()}clearTimers(){this.timeoutTimer&&clearTimeout(this.timeoutTimer),clearTimeout(this.handshakeTimer)}cleanup(){let{child:e}=this.options.runtime;e.off(`message`,this.onMessage),e.off(`error`,this.onError),e.off(`exit`,this.onExit)}};function De(e){let t=!1,n=()=>{};return{promise:new Promise((e,t)=>{n=t}),reject(r){t||(t=!0,n(new i(`runner`,r??`Subagent job cancelled: ${e}`)))}}}function Oe(e,t){if(e.job.request.timeoutMs)return setTimeout(()=>{V(e,`Subagent worker timed out`),t(new i(`timeout`,`Subagent worker timed out`))},e.job.request.timeoutMs)}function ke(e,t,n,r){let i=n(e),a=Ae(r);return{taskId:e.taskId,output:t.output,...i?{metadata:{transcriptPath:i,logPath:i}}:{},...t.usage?{usage:t.usage}:{},...a?{deniedToolCalls:a}:{}}}function Ae(e){let t=Object.values(e).reduce((e,t)=>e+t,0);return t===0?void 0:{total:t,byReason:{...e}}}function je(e,t,n){return`Subagent worker exited before result: ${t===null?`exit code ${e===null?`unknown`:e}`:`signal ${t}`}${n.length>0?`: ${n}`:``}`}const H=`--__robota-subagent-worker`;function Me(e){return e.includes(H)}const Ne=process.platform!==`win32`;function Pe(e){return t=>{let n=new U(t,e);return e.worktreeIsolation===!1?n:c({runner:n,worktreeAdapter:e.worktreeAdapter,hooks:t.config.hooks,hookTypeExecutors:t.hookTypeExecutors})}}var U=class{deps;workerEntry;killGraceMs;handshakeBudgetMs;providerConfig;providerDefinitions;env;logsDir;parentSandboxSettings;watchParentSandboxSettings;constructor(e,t){this.deps=e,this.workerEntry=t.workerEntry,this.killGraceMs=t.killGraceMs??p,this.handshakeBudgetMs=t.handshakeBudgetMs,this.providerConfig=t.providerConfig,this.providerDefinitions=t.providerDefinitions,this.env=t.env,this.logsDir=t.logsDir,this.parentSandboxSettings=t.parentSandboxSettings,this.watchParentSandboxSettings=t.watchParentSandboxSettings}start(t){let n=this.workerEntry,r={...process.env,...this.env??{}},i=O(t,this.deps,{...this.providerConfig===void 0?{}:{providerConfig:this.providerConfig},providerDefinitions:this.providerDefinitions},process.env,r),a=e(n.execPath,[...n.execArgv??[],...n.args,H],{cwd:d(t),env:r,stdio:[`ignore`,`ignore`,`pipe`,`ipc`],detached:Ne});xe(a),this.forwardSandboxSettingChanges(a);let o={job:t,child:a,killGraceMs:this.killGraceMs},s=this.createStartPayload(t,i),c=new AbortController,l=this.permissionApprover(t),u=Te({runtime:o,payload:s,...this.handshakeBudgetMs===void 0?{}:{handshakeBudgetMs:this.handshakeBudgetMs},resolveTranscriptPath:e=>this.resolveTranscriptPath(e),permissionAbort:c,...l===void 0?{}:{permissionApprover:l}}),f=De(t.taskId);u.catch(()=>void 0);let p=Promise.race([u,f.promise]);p.catch(()=>void 0);let m=this.resolveTranscriptPath(t);return{taskId:t.taskId,...a.pid!==void 0&&{pid:a.pid},...m!==void 0&&{transcriptPath:m,logPath:m},result:p,cancel:async e=>{c.abort(e),f.reject(e),await V(o,e)},send:async e=>{await B(a,{type:`send`,prompt:e})},...m!==void 0&&{readLog:async e=>Fe(t.taskId,m,e)}}}createStartPayload(e,t){let n=this.parentSandboxSettings?.();return fe(e,this.deps,{connection:t,providerDefinitions:this.providerDefinitions,...this.logsDir===void 0?{}:{logsDir:this.logsDir},...n===void 0?{}:{parentSandboxSettings:n}})}forwardSandboxSettingChanges(e){let t=this.watchParentSandboxSettings?.(t=>{e.connected&&B(e,{type:`sandbox_settings`,settings:t}).catch(()=>void 0)});t!==void 0&&(e.once(`exit`,t),e.once(`error`,t))}resolveTranscriptPath(e){if(this.logsDir)return r(this.logsDir,e.request.parentSessionId,`subagents`,`${e.taskId}.jsonl`)}permissionApprover(e){let t=this.deps.permissionHandler;if(t===void 0)return;let n={kind:`background-agent`,label:e.request.agentType,taskId:e.taskId};return(e,r,i)=>t(e,r,{requester:n,signal:i})}};function Fe(e,r,i){return t(r)?o(e,n(r,`utf8`).split(/\r?\n/).filter(Boolean),i):{taskId:e,cursor:i,lines:[]}}function Ie(e,t,n){let r=e.request.resumeSessionId;if(r!==void 0){if(n===void 0)throw Error(`subagent worker: job ${e.taskId} asks to resume session ${r}, but this composition opens no session store. Register ISubagentWorkerComposition.openSessionStore at the composition root — the same place providerDefinitions is registered.`);ie(n,r,t)}}function Le(e,t){let n=e.request.resumeSessionId;if(n!==void 0){if(t.openSessionStore===void 0)throw Error(`subagent worker: job ${e.taskId} asks to resume session ${n}, but this composition opens no session store. Register ISubagentWorkerComposition.openSessionStore at the composition root — the same place providerDefinitions is registered.`);return t.openSessionStore({cwd:e.request.cwd})}}async function Re(e,t){if(e===void 0)return;let n=t?.[e.type];if(n===void 0)throw Error(`subagent worker: sandbox type "${e.type}" is not registered in the worker composition. The parent is sandboxed and passed a snapshot reference, but this child cannot construct that client type. Register it in ISubagentWorkerComposition.sandboxFactories at the composition root — the same place providerDefinitions is registered, and for the same reason.`);return n(e.snapshotId)}const ze={write:()=>{},writeLine:()=>{},writeMarkdown:()=>{},writeError:()=>{},prompt:()=>Promise.resolve(``),select:()=>Promise.resolve(0),spinner:()=>({stop:()=>{},update:()=>{}})};let W=null,G=!1;const K=new Map;let Be=0,q,J,Y,X=Promise.resolve();function Z(e){process.send&&process.send(e)}function Q(e,t){let n=!1,r=()=>{n||(n=!0,process.exit(t))};if(process.send){let t=setTimeout(r,2e3);t.unref?.(),process.send(e,void 0,void 0,()=>{clearTimeout(t),r()})}else r()}function Ve(e){try{return ne(e.getFullHistory())}catch{return}}async function He(e,t){try{if(!f(e.connectionCheck,process.env))throw Error(`The provider connection environment changed after the parent checked it; the subagent was not started.`);let n=await Re(e.sandboxProjection,t.sandboxFactories),r=s(e.providerProfile,e.request.model,t.providerDefinitions),i=e.logsDir?g(e.request.parentSessionId,e.taskId,e.logsDir):void 0,a=Le(e,t),o=q??e.parentSandboxSettings;J=n===void 0?t.createSandbox?.({cwd:d(e),...o===void 0?{}:{parentSettings:o}}):void 0;let c=n??J?.client;W=re({agentDefinition:w(e.agentDefinition),parentConfig:e.parentConfig,parentContext:D(e.parentContext),parentTools:t.createTools({cwd:d(e),...c===void 0?{}:{sandboxClient:c},...e.sessionTiers===void 0?{}:{sessionTiers:e.sessionTiers}}),cwd:d(e),provider:r,terminal:ze,sessionId:e.request.resumeSessionId??e.taskId,...a===void 0?{}:{sessionStore:a},...i?{sessionLogger:i}:{},permissionMode:e.permissionMode,...J?.commandSandbox===void 0?{}:{commandSandbox:J.commandSandbox},...e.request.permissionPolicy===void 0?{}:{permissionPolicy:e.request.permissionPolicy},...e.request.allowedTools===void 0?{}:{taskAllowedTools:e.request.allowedTools},...e.request.disallowedTools===void 0?{}:{taskDisallowedTools:e.request.disallowedTools},hooks:e.parentConfig.hooks,...t.createHookTypeExecutors===void 0?{}:{hookTypeExecutors:t.createHookTypeExecutors()},onTextDelta:e=>Z({type:`text_delta`,delta:e}),onToolExecution:$,permissionHandler:Ue}),Ie(e,W,a);let l=await W.run(e.request.prompt);if(Y!==void 0){Q({type:`error`,message:Y},0);return}if(G){Q({type:`cancelled`,reason:`Subagent worker cancelled`},130);return}let u=Ve(W);Q({type:`result`,output:l,...u?{usage:u}:{}},0)}catch(e){if(Y!==void 0){Q({type:`error`,message:Y},0);return}if(G){Q({type:`cancelled`,reason:`Subagent worker cancelled`},130);return}Q({type:`error`,message:e instanceof Error?e.message:String(e)},0)}}function Ue(e,t){let n=`perm_${++Be}`;return new Promise(r=>{K.set(n,r),Z({type:`permission_request`,requestId:n,toolName:e,toolArgs:t})})}function We(e,t){let n=K.get(e);n!==void 0&&(K.delete(e),n(t))}function $(e){if(e.type===`start`){Z({type:`tool_start`,toolName:e.toolName,toolArgs:e.toolArgs});return}Z({type:`tool_end`,toolName:e.toolName,success:e.success??!0})}function Ge(e){if(W===null){Z({type:`error`,message:`Subagent worker has not started`});return}X=X.then(async()=>{try{await W?.run(e)}catch(e){Z({type:`error`,message:e instanceof Error?e.message:String(e)})}})}async function Ke(e){G=!0,W?.abort(),Z({type:`cancelled`,reason:e}),await W?.shutdown({reason:`other`}).catch(()=>void 0),setTimeout(()=>process.exit(130),0)}function qe(e){try{return e.createTools({cwd:process.cwd()}).map(e=>e.getName())}catch(e){process.stderr.write(`robota: could not enumerate the composed tool surface: ${e instanceof Error?e.message:String(e)}\n`);return}}function Je(e){q=e;try{J?.applyParentSettings?.(e)}catch(e){Y??=e instanceof Error?e.message:String(e),W?.abort()}}function Ye(e){process.send===void 0&&(process.stderr.write(`robota: subagent worker mode requires an IPC channel; it is started by the agent runtime, not by hand.
|
|
1
|
+
import{spawn as e}from"node:child_process";import{existsSync as t,readFileSync as n}from"node:fs";import{join as r}from"node:path";import{BackgroundTaskError as i,connectionEnvironmentNames as a,createBackgroundTaskLogPage as o,createProviderFromExactProfile as s,createWorktreeSubagentRunner as c,findConnectionEnvironmentDivergence as l,sealConnectionEnvironment as u,subagentExecutionRoot as d,verifyConnectionEnvironment as f}from"@robota-sdk/agent-executor";import{DEFAULT_KILL_GRACE_MS as p,killProcessTree as m}from"@robota-sdk/agent-process";import{createBoundedOutput as ee,findProviderDefinition as h,isModelEffort as te,sumHistoryUsage as ne}from"@robota-sdk/agent-core";import{createSubagentLogger as g,createSubagentSession as re,restoreSessionRecordIntoSession as ie}from"@robota-sdk/agent-framework";function ae(e){return{provider:{model:e.provider.model},permissions:e.permissions,defaultTrustLevel:e.defaultTrustLevel,...e.hooks===void 0?{}:{hooks:e.hooks}}}function oe(e){return{agentsMd:e.agentsMd,projectNotesMd:e.projectNotesMd}}const _={name:{kind:`string`,required:!0},description:{kind:`string`,required:!0},systemPrompt:{kind:`string`,required:!0},model:{kind:`string`,required:!1},effort:{kind:`effort`,required:!1},role:{kind:`string`,required:!1},maxTurns:{kind:`number`,required:!1},tools:{kind:`string[]`,required:!1},disallowedTools:{kind:`string[]`,required:!1}},v={agentsMd:{kind:`string`,required:!0},projectNotesMd:{kind:`string`,required:!0},memoryMd:{kind:`string`,required:!1},taskContext:{kind:`string`,required:!1},compactInstructions:{kind:`string`,required:!1},agentsFileEntries:{kind:`file-entry[]`,required:!1},projectNotesFileEntries:{kind:`file-entry[]`,required:!1}};function y(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function se(e){return Array.isArray(e)&&e.every(e=>typeof e==`string`)}function ce(e){return y(e)&&typeof e.filePath==`string`&&typeof e.content==`string`&&typeof e.contentHash==`string`}function le(e,t){switch(e){case`string`:return typeof t==`string`;case`number`:return typeof t==`number`&&Number.isFinite(t);case`effort`:return typeof t==`string`&&te(t);case`string[]`:return se(t);case`file-entry[]`:return Array.isArray(t)&&t.every(ce)}}function b(e,t){let n={};for(let r of Object.keys(t)){let t=e[r];t!==void 0&&(n[r]=t)}return n}function x(e,t,n){if(!y(t))return{ok:!1,reason:`${e}: expected an object`};for(let[r,i]of Object.entries(n)){let n=t[r];if(n===void 0){if(i.required)return{ok:!1,reason:`${e}.${r}: required`};continue}if(!le(i.kind,n))return{ok:!1,reason:`${e}.${r}: expected ${i.kind}`}}return{ok:!0,value:b(t,n)}}function S(e){return b(e,_)}function C(e){return x(`agentDefinition`,e,_)}function w(e){let t={name:e.name,description:e.description,systemPrompt:e.systemPrompt};return e.model!==void 0&&(t.model=e.model),e.effort!==void 0&&(t.effort=e.effort),e.role!==void 0&&(t.role=e.role),e.maxTurns!==void 0&&(t.maxTurns=e.maxTurns),e.tools!==void 0&&(t.tools=[...e.tools]),e.disallowedTools!==void 0&&(t.disallowedTools=[...e.disallowedTools]),t}function T(e){return b(e,v)}function E(e){return x(`parentContext`,e,v)}function D(e){let t={agentsMd:e.agentsMd,projectNotesMd:e.projectNotesMd};return e.memoryMd!==void 0&&(t.memoryMd=e.memoryMd),e.taskContext!==void 0&&(t.taskContext=e.taskContext),e.compactInstructions!==void 0&&(t.compactInstructions=e.compactInstructions),e.agentsFileEntries!==void 0&&(t.agentsFileEntries=e.agentsFileEntries.map(e=>({...e}))),e.projectNotesFileEntries!==void 0&&(t.projectNotesFileEntries=e.projectNotesFileEntries.map(e=>({...e}))),t}function ue(e){return e.sessionTiers===void 0?{}:{sessionTiers:e.sessionTiers}}async function de(e){let{sandboxClient:t,sandboxType:n}=e;return t?.snapshot===void 0||n===void 0?{}:{sandboxProjection:{type:n,snapshotId:await t.snapshot()}}}function O(e,t,n,r,o){let s=n.providerDefinitions,c=(n.providerConfig??t.config.provider).name;if(h(s,c)===void 0)throw new i(`validation`,`No provider definition for "${c}" was given to the subagent runner, so the connection a child would make cannot be checked; the subagent was not started.`);let d=ge(n.providerConfig,t,e,s),f=a(d,s),p=l(f,r,o);if(p!==void 0)throw new i(`validation`,`The subagent's environment sets ${p} differently from this session, which would change where its provider connects or which credential it sends; the subagent was not started.`);return{providerProfile:d,connectionCheck:u(f,o)}}function fe(e,t,n){let r=pe(e.request.agentType,t.customAgentRegistry,t.builtInAgents,t.agentDefinitions),i={taskId:e.taskId,request:e.request,...e.worktree?{worktree:e.worktree}:{},agentDefinition:S(me(r,e)),parentConfig:ae(t.getParentPermissionRules===void 0?t.config:{...t.config,permissions:t.getParentPermissionRules()}),parentContext:T(oe(t.context)),...n.connection??O(e,t,n,process.env,process.env),permissionMode:t.getParentPermissionMode?.()??t.permissionMode,...ue(t),...n.parentSandboxSettings===void 0?{}:{parentSandboxSettings:n.parentSandboxSettings},...n.logsDir?{logsDir:n.logsDir}:{}};return de(t).then(e=>({...i,...e}))}function pe(e,t,n,r){let a=t?.(e)??n?.find(t=>t.name===e)??r?.find(t=>t.name===e);if(!a)throw new i(`validation`,`Unknown agent type: ${e}`);return a}function me(e,t){return{...e,...t.request.model?{model:t.request.model}:{},...t.request.effort===void 0?{}:{effort:t.request.effort},...t.request.allowedTools?{tools:t.request.allowedTools}:{},...t.request.disallowedTools?{disallowedTools:t.request.disallowedTools}:{}}}function he(e,t){return e.apiKeyEnv===void 0?e.apiKey===void 0?t===void 0?{}:t.startsWith(`$ENV:`)?{apiKeyEnv:t.slice(5)}:{apiKey:t}:{apiKey:e.apiKey}:{apiKeyEnv:e.apiKeyEnv}}function ge(e,t,n,r){let i=e??t.config.provider,a=h(r,i.name)?.defaults??{},o=i.baseURL??a.baseURL,s=i.options??a.options,c=he(i,a.apiKey);return{...e===void 0&&t.config.currentProvider!==void 0?{profileName:t.config.currentProvider}:{},type:i.name,model:n.request.model??i.model,...c,...o===void 0?{}:{baseURL:o},...i.timeout===void 0?{}:{timeout:i.timeout},...s===void 0?{}:{options:s}}}function k(e){return typeof e==`object`&&!!e}function _e(e){if(!k(e)||!A(e,`nonce`)||!A(e,`digest`))return!1;let t=e.names;return Array.isArray(t)&&t.every(e=>typeof e==`string`)}function A(e,t){return typeof e[t]==`string`}function j(e,t){return A(e,t)}function M(e,t){return A(e,t)}function N(e,t){return e[t]===void 0||typeof e[t]==`string`}function P(e){if(e.usage===void 0)return!0;let t=e.usage;return k(t)?typeof t.promptTokens==`number`&&typeof t.completionTokens==`number`&&typeof t.totalTokens==`number`:!1}function F(e){if(e.composedToolNames===void 0)return!0;let t=e.composedToolNames;return Array.isArray(t)?t.every(e=>typeof e==`string`):!1}function I(e){return!k(e)||!M(e,`taskId`)||!k(e.request)||!j(e.request,`agentType`)||!j(e.request,`prompt`)||!j(e.request,`permissionPolicy`)||!j(e.request,`cwd`)||!N(e.request,`resumeSessionId`)||e.worktree!==void 0&&(!k(e.worktree)||!A(e.worktree,`path`))||!C(e.agentDefinition).ok||!k(e.parentConfig)||!E(e.parentContext).ok||!k(e.providerProfile)||!A(e.providerProfile,`type`)||!A(e.providerProfile,`model`)||e.parentSandboxSettings!==void 0&&!k(e.parentSandboxSettings)?!1:_e(e.connectionCheck)}function L(e){if(!k(e)||!A(e,`type`))return!1;switch(e.type){case`start`:return I(e.payload);case`send`:return A(e,`prompt`);case`cancel`:return e.reason===void 0||typeof e.reason==`string`;case`sandbox_settings`:return k(e.settings);case`permission_response`:return A(e,`requestId`)&&ve(e.result);default:return!1}}function ve(e){return typeof e==`boolean`||e===`allow-session`||e===`allow-project`}function R(e){if(!k(e)||!A(e,`type`))return!1;switch(e.type){case`ready`:return F(e);case`text_delta`:return A(e,`delta`);case`tool_start`:return A(e,`toolName`);case`tool_end`:return A(e,`toolName`)&&typeof e.success==`boolean`;case`permission_request`:return A(e,`requestId`)&&A(e,`toolName`);case`result`:return A(e,`output`)&&P(e);case`error`:return A(e,`message`);case`cancelled`:return e.reason===void 0||typeof e.reason==`string`;default:return!1}}const ye=process.platform!==`win32`;function be(e,t){return new Promise(n=>{if(e.exitCode!==null||e.signalCode!==null){n();return}let r=setTimeout(()=>{e.removeListener(`exit`,i),n()},t);r.unref?.();let i=()=>{clearTimeout(r),n()};e.once(`exit`,i)})}const z=new WeakMap;function xe(e){let t=e.stderr;if(!t)return;let n=ee({maxBytes:4096,retain:`tail`,truncationMarker:()=>``});z.set(e,n),t.on(`error`,()=>{}),t.on(`data`,e=>n.append(e))}function Se(e){return(z.get(e)?.toString()??``).trim()}function Ce(e,t,n,r,a,o){switch(e.type){case`ready`:t();break;case`result`:n(e);break;case`error`:r(new i(`runner`,e.message));break;case`cancelled`:r(new i(`runner`,e.reason??`Subagent worker cancelled`));break;case`text_delta`:a?.({type:`background_task_text_delta`,delta:e.delta});break;case`tool_start`:a?.({type:`background_task_tool_start`,toolName:e.toolName,firstArg:we(e.toolArgs)});break;case`tool_end`:a?.({type:`background_task_tool_end`,toolName:e.toolName,success:e.success});break;case`permission_request`:o?.(e);break;default:r(new i(`runner`,`Unhandled subagent worker message`))}}function we(e){if(!e)return;let t=Object.values(e)[0];if(t!==void 0)return typeof t==`object`?JSON.stringify(t):String(t)}function B(e,t){return new Promise((n,r)=>{if(!e.connected){r(new i(`crash`,`Subagent worker IPC channel is closed`));return}e.send(t,e=>{if(e){r(e);return}n()})})}async function V(e,t){await m(e.child,{graceMs:e.killGraceMs,processGroup:ye,preKill:async()=>{e.child.connected&&(await B(e.child,{type:`cancel`,reason:t}).catch(()=>void 0),await be(e.child,e.killGraceMs))}})}function Te(e){return new Promise((t,n)=>{new Ee(e,t,n).start()})}var Ee=class{options;resolve;reject;settled=!1;started=!1;ready=!1;timeoutTimer;handshakeTimer;handshakeBudgetMs;payload;deniedToolCallCounts={"no-approver":0,"denied-by-person":0,"approver-error":0,cancelled:0};pendingPermissionRequests=new Map;constructor(e,t,n){this.options=e,this.resolve=t,this.reject=n;let r=e.handshakeBudgetMs;this.handshakeBudgetMs=r!==void 0&&r>0?r:3e4,this.payload=e.payload.catch(e=>{this.rejectOnce(e instanceof Error?e:Error(String(e)))}),this.timeoutTimer=Oe(this.options.runtime,e=>this.rejectOnce(e)),this.handshakeTimer=setTimeout(()=>{this.ready||this.settled||(V(this.options.runtime,`Subagent worker never signalled ready`),this.rejectOnce(new i(`runner`,`Subagent worker never signalled ready within ${this.handshakeBudgetMs}ms. Its entry must dispatch worker mode before starting the host application.`)))},this.handshakeBudgetMs),this.handshakeTimer.unref?.()}start(){let{child:e}=this.options.runtime;e.on(`message`,this.onMessage),e.on(`error`,this.onError),e.on(`exit`,this.onExit),e.once(`spawn`,()=>{setImmediate(this.startWorker)})}startWorker=()=>{if(this.started)return;this.started=!0;let{child:e}=this.options.runtime;this.payload.then(t=>t===void 0?void 0:B(e,{type:`start`,payload:t})).catch(e=>{this.rejectOnce(e instanceof Error?e:Error(String(e)))})};onMessage=e=>{if(!R(e)){this.rejectOnce(new i(`runner`,`Received malformed subagent worker message`));return}this.ready=!0,clearTimeout(this.handshakeTimer);let{job:t}=this.options.runtime;Ce(e,this.startWorker,this.resolveOnce,this.rejectOnce,t.emit,this.onPermissionRequest)};onPermissionRequest=e=>{let t=this.answerPermissionRequest(e).finally(()=>{this.pendingPermissionRequests.delete(e.requestId)});this.pendingPermissionRequests.set(e.requestId,t)};async answerPermissionRequest(e){let{reason:t,result:n}=await this.askApprover(e);t!==void 0&&(this.deniedToolCallCounts[t]+=1);let{child:r}=this.options.runtime;r.connected&&await B(r,{type:`permission_response`,requestId:e.requestId,result:n}).catch(()=>void 0)}async askApprover(e){let t=this.options.permissionApprover;if(t===void 0)return{reason:`no-approver`,result:!1};try{let n=await t(e.toolName,e.toolArgs??{},this.options.permissionAbort.signal);return n===!1?this.options.permissionAbort.signal.aborted?{reason:`cancelled`,result:!1}:{reason:`denied-by-person`,result:!1}:{result:n}}catch{return{reason:`approver-error`,result:!1}}}onError=e=>{this.rejectOnce(new i(`crash`,e.message))};onExit=(e,t)=>{this.settled||this.rejectOnce(new i(`crash`,je(e,t,Se(this.options.runtime.child))))};resolveOnce=e=>{this.settled||(this.settled=!0,this.settleAfterPendingPermissionRequests(()=>{let{runtime:t,resolveTranscriptPath:n}=this.options;this.resolve(ke(t.job,e,n,this.deniedToolCallCounts))}))};rejectOnce=e=>{this.settled||(this.settled=!0,this.settleAfterPendingPermissionRequests(()=>this.reject(e)))};async settleAfterPendingPermissionRequests(e){this.options.permissionAbort.abort(),this.clearTimers(),this.cleanup(),await Promise.all(this.pendingPermissionRequests.values()),e()}clearTimers(){this.timeoutTimer&&clearTimeout(this.timeoutTimer),clearTimeout(this.handshakeTimer)}cleanup(){let{child:e}=this.options.runtime;e.off(`message`,this.onMessage),e.off(`error`,this.onError),e.off(`exit`,this.onExit)}};function De(e){let t=!1,n=()=>{};return{promise:new Promise((e,t)=>{n=t}),reject(r){t||(t=!0,n(new i(`runner`,r??`Subagent job cancelled: ${e}`)))}}}function Oe(e,t){if(e.job.request.timeoutMs)return setTimeout(()=>{V(e,`Subagent worker timed out`),t(new i(`timeout`,`Subagent worker timed out`))},e.job.request.timeoutMs)}function ke(e,t,n,r){let i=n(e),a=Ae(r);return{taskId:e.taskId,output:t.output,...i?{metadata:{transcriptPath:i,logPath:i}}:{},...t.usage?{usage:t.usage}:{},...a?{deniedToolCalls:a}:{}}}function Ae(e){let t=Object.values(e).reduce((e,t)=>e+t,0);return t===0?void 0:{total:t,byReason:{...e}}}function je(e,t,n){return`Subagent worker exited before result: ${t===null?`exit code ${e===null?`unknown`:e}`:`signal ${t}`}${n.length>0?`: ${n}`:``}`}const H=`--__agent-subagent-worker`;function Me(e){return e.includes(H)}const Ne=process.platform!==`win32`;function Pe(e){return t=>{let n=new U(t,e);return e.worktreeIsolation===!1?n:c({runner:n,worktreeAdapter:e.worktreeAdapter,hooks:t.config.hooks,hookTypeExecutors:t.hookTypeExecutors})}}var U=class{deps;workerEntry;killGraceMs;handshakeBudgetMs;providerConfig;providerDefinitions;env;expectedEnvironment;inheritEnvironment;logsDir;parentSandboxSettings;watchParentSandboxSettings;constructor(e,t){if(this.deps=e,this.workerEntry=t.workerEntry,this.killGraceMs=t.killGraceMs??p,this.handshakeBudgetMs=t.handshakeBudgetMs,this.providerConfig=t.providerConfig,this.providerDefinitions=t.providerDefinitions,this.env=t.env,this.expectedEnvironment=t.expectedEnvironment,this.inheritEnvironment=t.inheritEnvironment!==!1,!this.inheritEnvironment&&this.expectedEnvironment===void 0)throw Error(`An explicit expected environment is required when child inheritance is disabled.`);this.logsDir=t.logsDir,this.parentSandboxSettings=t.parentSandboxSettings,this.watchParentSandboxSettings=t.watchParentSandboxSettings}start(t){let n=this.workerEntry,r=this.inheritEnvironment?{...process.env,...this.env??{}}:{...this.env??{}},i=O(t,this.deps,{...this.providerConfig===void 0?{}:{providerConfig:this.providerConfig},providerDefinitions:this.providerDefinitions},this.expectedEnvironment??process.env,r),a=e(n.execPath,[...n.execArgv??[],...n.args,H],{cwd:d(t),env:r,stdio:[`ignore`,`ignore`,`pipe`,`ipc`],detached:Ne});xe(a),this.forwardSandboxSettingChanges(a);let o={job:t,child:a,killGraceMs:this.killGraceMs},s=this.createStartPayload(t,i),c=new AbortController,l=this.permissionApprover(t),u=Te({runtime:o,payload:s,...this.handshakeBudgetMs===void 0?{}:{handshakeBudgetMs:this.handshakeBudgetMs},resolveTranscriptPath:e=>this.resolveTranscriptPath(e),permissionAbort:c,...l===void 0?{}:{permissionApprover:l}}),f=De(t.taskId);u.catch(()=>void 0);let p=Promise.race([u,f.promise]);p.catch(()=>void 0);let m=this.resolveTranscriptPath(t);return{taskId:t.taskId,...a.pid!==void 0&&{pid:a.pid},...m!==void 0&&{transcriptPath:m,logPath:m},result:p,cancel:async e=>{c.abort(e),f.reject(e),await V(o,e)},send:async e=>{await B(a,{type:`send`,prompt:e})},...m!==void 0&&{readLog:async e=>Fe(t.taskId,m,e)}}}createStartPayload(e,t){let n=this.parentSandboxSettings?.();return fe(e,this.deps,{connection:t,providerDefinitions:this.providerDefinitions,...this.logsDir===void 0?{}:{logsDir:this.logsDir},...n===void 0?{}:{parentSandboxSettings:n}})}forwardSandboxSettingChanges(e){let t=this.watchParentSandboxSettings?.(t=>{e.connected&&B(e,{type:`sandbox_settings`,settings:t}).catch(()=>void 0)});t!==void 0&&(e.once(`exit`,t),e.once(`error`,t))}resolveTranscriptPath(e){if(this.logsDir)return r(this.logsDir,e.request.parentSessionId,`subagents`,`${e.taskId}.jsonl`)}permissionApprover(e){let t=this.deps.permissionHandler;if(t===void 0)return;let n={kind:`background-agent`,label:e.request.agentType,taskId:e.taskId};return(e,r,i)=>t(e,r,{requester:n,signal:i})}};function Fe(e,r,i){return t(r)?o(e,n(r,`utf8`).split(/\r?\n/).filter(Boolean),i):{taskId:e,cursor:i,lines:[]}}function Ie(e,t,n){let r=e.request.resumeSessionId;if(r!==void 0){if(n===void 0)throw Error(`subagent worker: job ${e.taskId} asks to resume session ${r}, but this composition opens no session store. Register ISubagentWorkerComposition.openSessionStore at the composition root — the same place providerDefinitions is registered.`);ie(n,r,t)}}function Le(e,t){let n=e.request.resumeSessionId;if(n!==void 0){if(t.openSessionStore===void 0)throw Error(`subagent worker: job ${e.taskId} asks to resume session ${n}, but this composition opens no session store. Register ISubagentWorkerComposition.openSessionStore at the composition root — the same place providerDefinitions is registered.`);return t.openSessionStore({cwd:e.request.cwd})}}async function Re(e,t){if(e===void 0)return;let n=t?.[e.type];if(n===void 0)throw Error(`subagent worker: sandbox type "${e.type}" is not registered in the worker composition. The parent is sandboxed and passed a snapshot reference, but this child cannot construct that client type. Register it in ISubagentWorkerComposition.sandboxFactories at the composition root — the same place providerDefinitions is registered, and for the same reason.`);return n(e.snapshotId)}const ze={write:()=>{},writeLine:()=>{},writeMarkdown:()=>{},writeError:()=>{},prompt:()=>Promise.resolve(``),select:()=>Promise.resolve(0),spinner:()=>({stop:()=>{},update:()=>{}})};let W=null,G=!1;const K=new Map;let Be=0,q,J,Y,X=Promise.resolve();function Z(e){process.send&&process.send(e)}function Q(e,t){let n=!1,r=()=>{n||(n=!0,process.exit(t))};if(process.send){let t=setTimeout(r,2e3);t.unref?.(),process.send(e,void 0,void 0,()=>{clearTimeout(t),r()})}else r()}function Ve(e){try{return ne(e.getFullHistory())}catch{return}}async function He(e,t){try{if(!f(e.connectionCheck,process.env))throw Error(`The provider connection environment changed after the parent checked it; the subagent was not started.`);let n=await Re(e.sandboxProjection,t.sandboxFactories),r=s(e.providerProfile,e.request.model,t.providerDefinitions),i=e.logsDir?g(e.request.parentSessionId,e.taskId,e.logsDir):void 0,a=Le(e,t),o=q??e.parentSandboxSettings;J=n===void 0?t.createSandbox?.({cwd:d(e),...o===void 0?{}:{parentSettings:o}}):void 0;let c=n??J?.client;W=re({agentDefinition:w(e.agentDefinition),parentConfig:e.parentConfig,parentContext:D(e.parentContext),parentTools:t.createTools({cwd:d(e),...c===void 0?{}:{sandboxClient:c},...e.sessionTiers===void 0?{}:{sessionTiers:e.sessionTiers}}),cwd:d(e),provider:r,terminal:ze,sessionId:e.request.resumeSessionId??e.taskId,...a===void 0?{}:{sessionStore:a},...i?{sessionLogger:i}:{},permissionMode:e.permissionMode,...J?.commandSandbox===void 0?{}:{commandSandbox:J.commandSandbox},...e.request.permissionPolicy===void 0?{}:{permissionPolicy:e.request.permissionPolicy},...e.request.allowedTools===void 0?{}:{taskAllowedTools:e.request.allowedTools},...e.request.disallowedTools===void 0?{}:{taskDisallowedTools:e.request.disallowedTools},hooks:e.parentConfig.hooks,...t.createHookTypeExecutors===void 0?{}:{hookTypeExecutors:t.createHookTypeExecutors({cwd:d(e),...c===void 0?{}:{sandboxClient:c}})},onTextDelta:e=>Z({type:`text_delta`,delta:e}),onToolExecution:$,permissionHandler:Ue}),Ie(e,W,a);let l=await W.run(e.request.prompt);if(Y!==void 0){Q({type:`error`,message:Y},0);return}if(G){Q({type:`cancelled`,reason:`Subagent worker cancelled`},130);return}let u=Ve(W);Q({type:`result`,output:l,...u?{usage:u}:{}},0)}catch(e){if(Y!==void 0){Q({type:`error`,message:Y},0);return}if(G){Q({type:`cancelled`,reason:`Subagent worker cancelled`},130);return}Q({type:`error`,message:e instanceof Error?e.message:String(e)},0)}}function Ue(e,t){let n=`perm_${++Be}`;return new Promise(r=>{K.set(n,r),Z({type:`permission_request`,requestId:n,toolName:e,toolArgs:t})})}function We(e,t){let n=K.get(e);n!==void 0&&(K.delete(e),n(t))}function $(e){if(e.type===`start`){Z({type:`tool_start`,toolName:e.toolName,toolArgs:e.toolArgs});return}Z({type:`tool_end`,toolName:e.toolName,success:e.success??!0})}function Ge(e){if(W===null){Z({type:`error`,message:`Subagent worker has not started`});return}X=X.then(async()=>{try{await W?.run(e)}catch(e){Z({type:`error`,message:e instanceof Error?e.message:String(e)})}})}async function Ke(e){G=!0,W?.abort(),Z({type:`cancelled`,reason:e}),await W?.shutdown({reason:`other`}).catch(()=>void 0),setTimeout(()=>process.exit(130),0)}function qe(e){try{return e.createTools({cwd:process.cwd()}).map(e=>e.getName())}catch(e){process.stderr.write(`agent: could not enumerate the composed tool surface: ${e instanceof Error?e.message:String(e)}\n`);return}}function Je(e){q=e;try{J?.applyParentSettings?.(e)}catch(e){Y??=e instanceof Error?e.message:String(e),W?.abort()}}function Ye(e){process.send===void 0&&(process.stderr.write(`agent: subagent worker mode requires an IPC channel; it is started by the agent runtime, not by hand.
|
|
2
2
|
`),process.exit(2)),process.on(`message`,t=>{if(!L(t)){Z({type:`error`,message:`Malformed subagent worker parent message`});return}switch(t.type){case`start`:X=X.then(()=>He(t.payload,e));break;case`send`:Ge(t.prompt);break;case`cancel`:Ke(t.reason);break;case`sandbox_settings`:Je(t.settings);break;case`permission_response`:We(t.requestId,t.result);break;default:Z({type:`error`,message:`Unhandled subagent worker parent message`})}}),process.on(`disconnect`,()=>{G=!0,W?.abort(),W?.shutdown({reason:`other`}).catch(()=>void 0)});let t=qe(e);Z({type:`ready`,...t?{composedToolNames:t}:{}})}export{U as ChildProcessSubagentRunner,H as SUBAGENT_WORKER_MODE_FLAG,Pe as createChildProcessSubagentRunnerFactory,C as decodeAgentDefinitionDto,E as decodeParentContextDto,S as encodeAgentDefinition,T as encodeParentContext,R as isSubagentWorkerChildMessage,Me as isSubagentWorkerModeArgv,L as isSubagentWorkerParentMessage,w as restoreAgentDefinition,D as restoreParentContext,Ye as runSubagentWorkerMain};
|
|
3
3
|
//# sourceMappingURL=index.js.map
|