@robota-sdk/agent-subagent-runner 3.0.0-beta.83 → 3.0.0-beta.85
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 +62 -0
- package/README.md +48 -30
- package/dist/node/index.cjs +2 -2
- package/dist/node/index.d.cts +38 -2
- package/dist/node/index.d.cts.map +1 -1
- package/dist/node/index.d.ts +38 -2
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +2 -2
- package/dist/node/index.js.map +1 -1
- package/package.json +9 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,67 @@
|
|
|
1
1
|
# @robota-sdk/agent-subagent-runner
|
|
2
2
|
|
|
3
|
+
## 3.0.0-beta.85
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 2e07cad: A subagent and a fork-context skill now start in the permission mode their parent is in at that
|
|
8
|
+
moment. The runtime used to hand them the mode it was built with, so after a switch to `plan` a
|
|
9
|
+
subagent the model started, or a skill it ran in a fork, still ran in the earlier mode and could
|
|
10
|
+
edit. `IInProcessSubagentRunnerDeps` gains the optional `getParentPermissionMode`, which the session
|
|
11
|
+
wires to its live mode; the in-process and child-process runners read it at spawn and fall back to
|
|
12
|
+
`permissionMode` when it is absent.
|
|
13
|
+
|
|
14
|
+
In plan mode the model can no longer run `/workflows create` or `/workflows build`: both save to
|
|
15
|
+
the project, and `create` also runs the workflow. The user can still run them by hand.
|
|
16
|
+
|
|
17
|
+
- Updated dependencies [4e11579]
|
|
18
|
+
- Updated dependencies [41cca13]
|
|
19
|
+
- Updated dependencies [193a0bc]
|
|
20
|
+
- Updated dependencies [54e2848]
|
|
21
|
+
- Updated dependencies [3c1967f]
|
|
22
|
+
- Updated dependencies [ada3841]
|
|
23
|
+
- Updated dependencies [5093a30]
|
|
24
|
+
- Updated dependencies [5684612]
|
|
25
|
+
- Updated dependencies [6ee8725]
|
|
26
|
+
- Updated dependencies [6072e9a]
|
|
27
|
+
- Updated dependencies [94b2c87]
|
|
28
|
+
- Updated dependencies [3ab2eca]
|
|
29
|
+
- Updated dependencies [2e07cad]
|
|
30
|
+
- @robota-sdk/agent-framework@3.0.0-beta.85
|
|
31
|
+
- @robota-sdk/agent-core@3.0.0-beta.85
|
|
32
|
+
- @robota-sdk/agent-executor@3.0.0-beta.85
|
|
33
|
+
- @robota-sdk/agent-interface-execution@3.0.0-beta.85
|
|
34
|
+
- @robota-sdk/agent-process@3.0.0-beta.85
|
|
35
|
+
|
|
36
|
+
## 3.0.0-beta.84
|
|
37
|
+
|
|
38
|
+
### Patch Changes
|
|
39
|
+
|
|
40
|
+
- 9c6a8db: A background agent's tool call that needs approval now reaches a person instead of being refused
|
|
41
|
+
automatically. The child process asks the parent session's own approver, identified as a background
|
|
42
|
+
agent naming its task, and parks the call until an answer arrives; cancelling the task dismisses any
|
|
43
|
+
still-parked ask immediately rather than leaving it outstanding. A parent with no approver attached
|
|
44
|
+
(print mode, a truly headless run) still fails every such call closed, the same default as before.
|
|
45
|
+
|
|
46
|
+
An agent task's result and its background-task-workspace entry now report how many of its tool calls
|
|
47
|
+
were refused and why (denied by a person, no approver attached, the approver itself failed, or the
|
|
48
|
+
task ended before an attached approver answered) — present only when at least one call was refused, so
|
|
49
|
+
a task that finished as it always did carries no new field.
|
|
50
|
+
|
|
51
|
+
A workspace entry for a `/loop`-managed iteration now carries a stable `loopId`, so a surface can stop
|
|
52
|
+
the loop itself rather than only cancelling its disposable wake timer, and a snapshot can include a
|
|
53
|
+
self-paced loop summary for an iteration that has no background-task entry of its own yet.
|
|
54
|
+
|
|
55
|
+
- Updated dependencies [9f46375]
|
|
56
|
+
- Updated dependencies [e8d70ac]
|
|
57
|
+
- Updated dependencies [9c6a8db]
|
|
58
|
+
- Updated dependencies [9c6a8db]
|
|
59
|
+
- @robota-sdk/agent-core@3.0.0-beta.84
|
|
60
|
+
- @robota-sdk/agent-framework@3.0.0-beta.84
|
|
61
|
+
- @robota-sdk/agent-interface-execution@3.0.0-beta.84
|
|
62
|
+
- @robota-sdk/agent-executor@3.0.0-beta.84
|
|
63
|
+
- @robota-sdk/agent-process@3.0.0-beta.84
|
|
64
|
+
|
|
3
65
|
## 3.0.0-beta.83
|
|
4
66
|
|
|
5
67
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -1,26 +1,33 @@
|
|
|
1
1
|
# @robota-sdk/agent-subagent-runner
|
|
2
2
|
|
|
3
|
-
Child-process subagent runner for the Robota SDK.
|
|
3
|
+
Child-process subagent runner for the Robota SDK. It runs each subagent in its own Node.js child
|
|
4
|
+
process, talks to it over a typed IPC protocol, and can wrap each job in worktree isolation and stream
|
|
5
|
+
its logs to disk.
|
|
4
6
|
|
|
5
7
|
## Installation
|
|
6
8
|
|
|
7
9
|
```bash
|
|
8
|
-
|
|
10
|
+
npm install @robota-sdk/agent-subagent-runner
|
|
9
11
|
```
|
|
10
12
|
|
|
11
13
|
## Overview
|
|
12
14
|
|
|
13
|
-
This package is an optional add-on for `@robota-sdk/agent-framework`.
|
|
15
|
+
This package is an optional add-on for `@robota-sdk/agent-framework`. Without it, subagents run
|
|
16
|
+
in-process; with it, each subagent gets process isolation while reporting back to the parent session
|
|
17
|
+
over structured IPC.
|
|
14
18
|
|
|
15
19
|
```
|
|
16
|
-
agent-cli
|
|
20
|
+
composition root (e.g. agent-cli)
|
|
17
21
|
└── createChildProcessSubagentRunnerFactory()
|
|
18
22
|
└── ChildProcessSubagentRunner ← this package
|
|
19
|
-
├──
|
|
23
|
+
├── spawn() ← a copy of the running artifact in worker mode
|
|
20
24
|
├── IPC messages ← TSubagentWorkerParentMessage / TSubagentWorkerChildMessage
|
|
21
|
-
└── worktree isolation ← via agent-executor
|
|
25
|
+
└── worktree isolation ← via agent-executor, with an injected worktree adapter
|
|
22
26
|
```
|
|
23
27
|
|
|
28
|
+
The runner composes nothing itself. The composition root supplies how to start a copy of itself
|
|
29
|
+
(`workerEntry`), the tool factory and provider registry the child uses, and the worktree adapter.
|
|
30
|
+
|
|
24
31
|
## Usage
|
|
25
32
|
|
|
26
33
|
```typescript
|
|
@@ -40,13 +47,13 @@ declare const providerConfig: IProviderDefinitionConfig;
|
|
|
40
47
|
// The concrete worktree adapter (git/fs I/O) is owned and injected by the composition root.
|
|
41
48
|
declare const worktreeAdapter: ISubagentWorktreeAdapter;
|
|
42
49
|
|
|
43
|
-
//
|
|
44
|
-
//
|
|
50
|
+
// Your product's tool surface, built at the CHILD's execution root. This package composes nothing:
|
|
51
|
+
// there is no default tool set or provider registry to fall back to.
|
|
45
52
|
declare const createMyTools: (context: { readonly cwd: string }) => IToolWithEventService[];
|
|
46
53
|
declare const myProviderDefinitions: readonly IProviderDefinition[];
|
|
47
54
|
|
|
48
|
-
//
|
|
49
|
-
//
|
|
55
|
+
// Your entry is the worker. Dispatch before starting your app, so a subagent child re-enters here
|
|
56
|
+
// instead of booting the whole product.
|
|
50
57
|
if (isSubagentWorkerModeArgv(process.argv)) {
|
|
51
58
|
runSubagentWorkerMain({
|
|
52
59
|
createTools: createMyTools,
|
|
@@ -60,12 +67,13 @@ const factory = createChildProcessSubagentRunnerFactory({
|
|
|
60
67
|
// nothing, because `process.execPath` is the binary and re-executing it re-enters its entry.
|
|
61
68
|
workerEntry: { execPath: process.execPath, args: [process.argv[1] ?? ''] },
|
|
62
69
|
providerConfig,
|
|
70
|
+
providerDefinitions: myProviderDefinitions, // required: a job whose provider is not here is refused
|
|
63
71
|
logsDir: '.robota/logs',
|
|
64
72
|
worktreeAdapter, // required: no concrete git default — inject the port at the composition root
|
|
65
73
|
});
|
|
66
74
|
```
|
|
67
75
|
|
|
68
|
-
Pass `factory`
|
|
76
|
+
Pass `factory` as the `subagentRunnerFactory` option of `agent-framework`'s `createAgentRuntime`.
|
|
69
77
|
|
|
70
78
|
## API
|
|
71
79
|
|
|
@@ -75,7 +83,7 @@ Pass `factory` to `createAgentRuntime({ subagentRunnerFactory: factory })`.
|
|
|
75
83
|
| -------------------------------------------------- | --------------------------------------------------------------------------- |
|
|
76
84
|
| `createChildProcessSubagentRunnerFactory(options)` | Returns a `TSubagentRunnerFactory` that spawns subagents in child processes |
|
|
77
85
|
| `isSubagentWorkerModeArgv(argv)` | True when this process was started as a subagent worker |
|
|
78
|
-
| `runSubagentWorkerMain()`
|
|
86
|
+
| `runSubagentWorkerMain(composition)` | Enters worker mode; refuses loudly (exit 2) without an IPC channel |
|
|
79
87
|
|
|
80
88
|
### Classes
|
|
81
89
|
|
|
@@ -85,16 +93,27 @@ Pass `factory` to `createAgentRuntime({ subagentRunnerFactory: factory })`.
|
|
|
85
93
|
|
|
86
94
|
### Types
|
|
87
95
|
|
|
88
|
-
| Export | Description
|
|
89
|
-
| ------------------------------------ |
|
|
90
|
-
| `IChildProcessSubagentRunnerOptions` | Options for `createChildProcessSubagentRunnerFactory`
|
|
91
|
-
| `ISubagentWorkerEntry` | How to spawn a copy of the running artifact in worker mode
|
|
92
|
-
| `
|
|
93
|
-
| `
|
|
94
|
-
| `
|
|
95
|
-
| `
|
|
96
|
+
| Export | Description |
|
|
97
|
+
| ------------------------------------ | -------------------------------------------------------------------------------- |
|
|
98
|
+
| `IChildProcessSubagentRunnerOptions` | Options for `createChildProcessSubagentRunnerFactory` |
|
|
99
|
+
| `ISubagentWorkerEntry` | How to spawn a copy of the running artifact in worker mode |
|
|
100
|
+
| `ISubagentWorkerComposition` | What the product composes in the child: tools, provider registry, optional ports |
|
|
101
|
+
| `ISubagentWorkerStartPayload` | IPC payload sent from parent to worker on start |
|
|
102
|
+
| `TSubagentWorkerParentMessage` | Union of all messages the parent sends to the worker |
|
|
103
|
+
| `TSubagentWorkerChildMessage` | Union of all messages the worker sends to the parent |
|
|
104
|
+
| `TSubagentWorkerWireValue` | Serializable value type used in IPC messages |
|
|
105
|
+
|
|
106
|
+
### Type guards and wire helpers
|
|
107
|
+
|
|
108
|
+
| Export | Description |
|
|
109
|
+
| ------------------------------------------------------------------------------- | ------------------------------------------------------ |
|
|
110
|
+
| `isSubagentWorkerParentMessage` | Narrows to `TSubagentWorkerParentMessage` |
|
|
111
|
+
| `isSubagentWorkerChildMessage` | Narrows to `TSubagentWorkerChildMessage` |
|
|
112
|
+
| `SUBAGENT_WORKER_MODE_FLAG` | The argv flag that puts an entry into worker mode |
|
|
113
|
+
| `encodeAgentDefinition` / `decodeAgentDefinitionDto` / `restoreAgentDefinition` | JSON-safe wire form of the subagent's agent definition |
|
|
114
|
+
| `encodeParentContext` / `decodeParentContextDto` / `restoreParentContext` | JSON-safe wire form of the parent's loaded context |
|
|
96
115
|
|
|
97
|
-
|
|
116
|
+
## Forked session records
|
|
98
117
|
|
|
99
118
|
If a job includes `resumeSessionId`, the composition root must provide
|
|
100
119
|
`ISubagentWorkerComposition.openSessionStore`. The worker opens that store for the parent request's
|
|
@@ -102,17 +121,16 @@ If a job includes `resumeSessionId`, the composition root must provide
|
|
|
102
121
|
completed turn is persisted back into the fork record. Only the ID crosses IPC; the conversation does
|
|
103
122
|
not. Jobs without `resumeSessionId` remain transient.
|
|
104
123
|
|
|
105
|
-
### Type Guards
|
|
106
|
-
|
|
107
|
-
| Export | Description |
|
|
108
|
-
| ------------------------------- | ----------------------------------------- |
|
|
109
|
-
| `isSubagentWorkerParentMessage` | Narrows to `TSubagentWorkerParentMessage` |
|
|
110
|
-
| `isSubagentWorkerChildMessage` | Narrows to `TSubagentWorkerChildMessage` |
|
|
111
|
-
|
|
112
124
|
## Dependencies
|
|
113
125
|
|
|
114
|
-
- `@robota-sdk/agent-executor` — worktree isolation and background task primitives
|
|
115
|
-
- `@robota-sdk/agent-framework` —
|
|
126
|
+
- `@robota-sdk/agent-executor` — `ISubagentRunner`, worktree isolation, and background task primitives
|
|
127
|
+
- `@robota-sdk/agent-framework` — `TSubagentRunnerFactory` and session assembly for the worker
|
|
128
|
+
- `@robota-sdk/agent-core` — provider and tool types
|
|
129
|
+
- `@robota-sdk/agent-interface-execution` — subagent job contracts
|
|
130
|
+
- `@robota-sdk/agent-process` — process-tree termination
|
|
131
|
+
|
|
132
|
+
See [docs/SPEC.md](./docs/SPEC.md) for the package contract: required composition, IPC validation, and
|
|
133
|
+
how the provider connection is checked across the process boundary.
|
|
116
134
|
|
|
117
135
|
## License
|
|
118
136
|
|
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 ee(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 m(e,t){let n={};for(let r of Object.keys(t)){let t=e[r];t!==void 0&&(n[r]=t)}return n}function h(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(!ee(i.kind,n))return{ok:!1,reason:`${e}.${r}: expected ${i.kind}`}}return{ok:!0,value:m(t,n)}}function g(e){return m(e,l)}function _(e){return h(`agentDefinition`,e,l)}function v(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 y(e){return m(e,u)}function b(e){return h(`parentContext`,e,u)}function x(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 te(e){return e.sessionTiers===void 0?{}:{sessionTiers:e.sessionTiers}}async function ne(e){let{sandboxClient:t,sandboxType:n}=e;return t?.snapshot===void 0||n===void 0?{}:{sandboxProjection:{type:n,snapshotId:await t.snapshot()}}}function S(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=oe(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 re(e,t,n){let r=ie(e.request.agentType,t.customAgentRegistry,t.builtInAgents,t.agentDefinitions),i={taskId:e.taskId,request:e.request,...e.worktree?{worktree:e.worktree}:{},agentDefinition:g(ae(r,e)),parentConfig:s(t.getParentPermissionRules===void 0?t.config:{...t.config,permissions:t.getParentPermissionRules()}),parentContext:y(c(t.context)),...n.connection??S(e,t,n,process.env,process.env),permissionMode:t.permissionMode,...te(t),...n.parentSandboxSettings===void 0?{}:{parentSandboxSettings:n.parentSandboxSettings},...n.logsDir?{logsDir:n.logsDir}:{}};return ne(t).then(e=>({...i,...e}))}function ie(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 ae(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 C(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 oe(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=C(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 w(e){return typeof e==`object`&&!!e}function T(e){if(!w(e)||!E(e,`nonce`)||!E(e,`digest`))return!1;let t=e.names;return Array.isArray(t)&&t.every(e=>typeof e==`string`)}function E(e,t){return typeof e[t]==`string`}function D(e,t){return E(e,t)}function se(e,t){return E(e,t)}function ce(e,t){return e[t]===void 0||typeof e[t]==`string`}function le(e){if(e.usage===void 0)return!0;let t=e.usage;return w(t)?typeof t.promptTokens==`number`&&typeof t.completionTokens==`number`&&typeof t.totalTokens==`number`:!1}function ue(e){if(e.composedToolNames===void 0)return!0;let t=e.composedToolNames;return Array.isArray(t)?t.every(e=>typeof e==`string`):!1}function de(e){return!w(e)||!se(e,`taskId`)||!w(e.request)||!D(e.request,`agentType`)||!D(e.request,`prompt`)||!D(e.request,`permissionPolicy`)||!D(e.request,`cwd`)||!ce(e.request,`resumeSessionId`)||e.worktree!==void 0&&(!w(e.worktree)||!E(e.worktree,`path`))||!_(e.agentDefinition).ok||!w(e.parentConfig)||!b(e.parentContext).ok||!w(e.providerProfile)||!E(e.providerProfile,`type`)||!E(e.providerProfile,`model`)||e.parentSandboxSettings!==void 0&&!w(e.parentSandboxSettings)?!1:T(e.connectionCheck)}function O(e){if(!w(e)||!E(e,`type`))return!1;switch(e.type){case`start`:return de(e.payload);case`send`:return E(e,`prompt`);case`cancel`:return e.reason===void 0||typeof e.reason==`string`;case`sandbox_settings`:return w(e.settings);default:return!1}}function k(e){if(!w(e)||!E(e,`type`))return!1;switch(e.type){case`ready`:return ue(e);case`text_delta`:return E(e,`delta`);case`tool_start`:return E(e,`toolName`);case`tool_end`:return E(e,`toolName`)&&typeof e.success==`boolean`;case`result`:return E(e,`output`)&&le(e);case`error`:return E(e,`message`);case`cancelled`:return e.reason===void 0||typeof e.reason==`string`;default:return!1}}const A=process.platform!==`win32`;function j(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){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;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:A,preKill:async()=>{e.child.connected&&(await L(e.child,{type:`cancel`,reason:t}).catch(()=>void 0),await j(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;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=H(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(!k(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)};onError=e=>{this.rejectOnce(new r.BackgroundTaskError(`crash`,e.message))};onExit=(e,t)=>{this.settled||this.rejectOnce(new r.BackgroundTaskError(`crash`,pe(e,t,P(this.options.runtime.child))))};resolveOnce=e=>{if(this.settled)return;this.settled=!0,this.clearTimers(),this.cleanup();let{runtime:t,resolveTranscriptPath:n}=this.options;this.resolve(fe(t.job,e,n))};rejectOnce=e=>{this.settled||(this.settled=!0,this.clearTimers(),this.cleanup(),this.reject(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 H(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 fe(e,t,n){let r=n(e);return{taskId:e.taskId,output:t.output,...r?{metadata:{transcriptPath:r,logPath:r}}:{},...t.usage?{usage:t.usage}:{}}}function pe(e,t,n){return`Subagent worker exited before result: ${t===null?`exit code ${e===null?`unknown`:e}`:`signal ${t}`}${n.length>0?`: ${n}`:``}`}const U=`--__robota-subagent-worker`;function me(e){return e.includes(U)}const he=process.platform!==`win32`;function ge(e){return t=>{let n=new W(t,e);return e.worktreeIsolation===!1?n:(0,r.createWorktreeSubagentRunner)({runner:n,worktreeAdapter:e.worktreeAdapter,hooks:t.config.hooks,hookTypeExecutors:t.hookTypeExecutors})}}var W=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=S(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,U],{cwd:(0,r.subagentExecutionRoot)(t),env:i,stdio:[`ignore`,`ignore`,`pipe`,`ipc`],detached:he});N(o),this.forwardSandboxSettingChanges(o);let s={job:t,child:o,killGraceMs:this.killGraceMs},c=z({runtime:s,payload:this.createStartPayload(t,a),...this.handshakeBudgetMs===void 0?{}:{handshakeBudgetMs:this.handshakeBudgetMs},resolveTranscriptPath:e=>this.resolveTranscriptPath(e)}),l=V(t.taskId);c.catch(()=>void 0);let u=Promise.race([c,l.promise]);u.catch(()=>void 0);let d=this.resolveTranscriptPath(t);return{taskId:t.taskId,...o.pid!==void 0&&{pid:o.pid},...d!==void 0&&{transcriptPath:d,logPath:d},result:u,cancel:async e=>{l.reject(e),await R(s,e)},send:async e=>{await L(o,{type:`send`,prompt:e})},...d!==void 0&&{readLog:async e=>_e(t.taskId,d,e)}}}createStartPayload(e,t){let n=this.parentSandboxSettings?.();return re(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`)}};function _e(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 ve(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 ye(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 be(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 xe={write:()=>{},writeLine:()=>{},writeMarkdown:()=>{},writeError:()=>{},prompt:()=>Promise.resolve(``),select:()=>Promise.resolve(0),spinner:()=>({stop:()=>{},update:()=>{}})};let G=null,K=!1,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 Se(e){try{return(0,a.sumHistoryUsage)(e.getFullHistory())}catch{return}}async function $(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 be(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=ye(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;G=(0,o.createSubagentSession)({agentDefinition:v(e.agentDefinition),parentConfig:e.parentConfig,parentContext:x(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:xe,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:Ce}),ve(e,G,s);let u=await G.run(e.request.prompt);if(Y!==void 0){Q({type:`error`,message:Y},0);return}if(K){Q({type:`cancelled`,reason:`Subagent worker cancelled`},130);return}let d=Se(G);Q({type:`result`,output:u,...d?{usage:d}:{}},0)}catch(e){if(Y!==void 0){Q({type:`error`,message:Y},0);return}if(K){Q({type:`cancelled`,reason:`Subagent worker cancelled`},130);return}Q({type:`error`,message:e instanceof Error?e.message:String(e)},0)}}function Ce(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 we(e){if(G===null){Z({type:`error`,message:`Subagent worker has not started`});return}X=X.then(async()=>{try{await G?.run(e)}catch(e){Z({type:`error`,message:e instanceof Error?e.message:String(e)})}})}async function Te(e){K=!0,G?.abort(),Z({type:`cancelled`,reason:e}),await G?.shutdown({reason:`other`}).catch(()=>void 0),setTimeout(()=>process.exit(130),0)}function Ee(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 De(e){q=e;try{J?.applyParentSettings?.(e)}catch(e){Y??=e instanceof Error?e.message:String(e),G?.abort()}}function Oe(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.
|
|
2
|
-
`),process.exit(2)),process.on(`message`,t=>{if(!
|
|
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.
|
|
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
|
@@ -278,6 +278,15 @@ declare class ChildProcessSubagentRunner implements ISubagentRunner {
|
|
|
278
278
|
private createStartPayload;
|
|
279
279
|
private forwardSandboxSettingChanges;
|
|
280
280
|
private resolveTranscriptPath;
|
|
281
|
+
/**
|
|
282
|
+
* Issue #3288 §1: how this job's child gets a human's yes/no — the parent session's own approver
|
|
283
|
+
* (`deps.permissionHandler`, the exact function the in-process runner already hands its own child
|
|
284
|
+
* session), bound to a `requester` identity that names this task so a surface can say "Background
|
|
285
|
+
* agent X wants to …" instead of an unattributed prompt. `undefined` when the parent session has no
|
|
286
|
+
* approver at all (print mode / a truly headless run): the result controller then denies every
|
|
287
|
+
* request from the child immediately, the same fail-closed default the enforcer applies with none.
|
|
288
|
+
*/
|
|
289
|
+
private permissionApprover;
|
|
281
290
|
}
|
|
282
291
|
//#endregion
|
|
283
292
|
//#region src/subagent-worker-start-dto.d.ts
|
|
@@ -427,7 +436,23 @@ interface ISubagentWorkerSandboxSettingsMessage {
|
|
|
427
436
|
type: 'sandbox_settings';
|
|
428
437
|
settings: TParentSandboxSettings;
|
|
429
438
|
}
|
|
430
|
-
|
|
439
|
+
/**
|
|
440
|
+
* Issue #3288 §1: the three-way answer a permission ask can receive — the same shape
|
|
441
|
+
* `@robota-sdk/agent-session`'s `TPermissionResult` allows, inlined here so this wire module does not
|
|
442
|
+
* need that package as a dependency for one literal union.
|
|
443
|
+
*/
|
|
444
|
+
type TSubagentWorkerPermissionResult = boolean | 'allow-session' | 'allow-project';
|
|
445
|
+
/**
|
|
446
|
+
* Issue #3288 §1: the parent's answer to a `permission_request` the child raised, correlated by
|
|
447
|
+
* `requestId`. `false` when the parent has no approver attached (print mode) — the fail-closed
|
|
448
|
+
* default, not a special case the child has to know about.
|
|
449
|
+
*/
|
|
450
|
+
interface ISubagentWorkerPermissionResponseMessage {
|
|
451
|
+
type: 'permission_response';
|
|
452
|
+
requestId: string;
|
|
453
|
+
result: TSubagentWorkerPermissionResult;
|
|
454
|
+
}
|
|
455
|
+
type TSubagentWorkerParentMessage = ISubagentWorkerStartMessage | ISubagentWorkerSendMessage | ISubagentWorkerCancelMessage | ISubagentWorkerSandboxSettingsMessage | ISubagentWorkerPermissionResponseMessage;
|
|
431
456
|
interface ISubagentWorkerReadyMessage {
|
|
432
457
|
type: 'ready';
|
|
433
458
|
/**
|
|
@@ -454,6 +479,17 @@ interface ISubagentWorkerToolEndMessage {
|
|
|
454
479
|
toolName: string;
|
|
455
480
|
success: boolean;
|
|
456
481
|
}
|
|
482
|
+
/**
|
|
483
|
+
* Issue #3288 §1: a tool call inside the child needs a human's approval. `requestId` correlates this
|
|
484
|
+
* with the parent's eventual `permission_response`; the child parks the call until it arrives (or
|
|
485
|
+
* until its own turn is cancelled, which the enforcer's existing signal race already denies).
|
|
486
|
+
*/
|
|
487
|
+
interface ISubagentWorkerPermissionRequestMessage {
|
|
488
|
+
type: 'permission_request';
|
|
489
|
+
requestId: string;
|
|
490
|
+
toolName: string;
|
|
491
|
+
toolArgs?: TToolArgs;
|
|
492
|
+
}
|
|
457
493
|
interface ISubagentWorkerResultMessage {
|
|
458
494
|
type: 'result';
|
|
459
495
|
output: string;
|
|
@@ -468,7 +504,7 @@ interface ISubagentWorkerCancelledMessage {
|
|
|
468
504
|
type: 'cancelled';
|
|
469
505
|
reason?: string;
|
|
470
506
|
}
|
|
471
|
-
type TSubagentWorkerChildMessage = ISubagentWorkerReadyMessage | ISubagentWorkerTextDeltaMessage | ISubagentWorkerToolStartMessage | ISubagentWorkerToolEndMessage | ISubagentWorkerResultMessage | ISubagentWorkerErrorMessage | ISubagentWorkerCancelledMessage;
|
|
507
|
+
type TSubagentWorkerChildMessage = ISubagentWorkerReadyMessage | ISubagentWorkerTextDeltaMessage | ISubagentWorkerToolStartMessage | ISubagentWorkerToolEndMessage | ISubagentWorkerPermissionRequestMessage | ISubagentWorkerResultMessage | ISubagentWorkerErrorMessage | ISubagentWorkerCancelledMessage;
|
|
472
508
|
declare function isSubagentWorkerParentMessage(value: TSubagentWorkerWireValue): value is TSubagentWorkerParentMessage;
|
|
473
509
|
declare function isSubagentWorkerChildMessage(value: TSubagentWorkerWireValue): value is TSubagentWorkerChildMessage;
|
|
474
510
|
//#endregion
|
|
@@ -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,gCAAgC;;;;;;;;;EAShC,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;;;;
|
|
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,gCAAgC;;;;;;;;;EAShC,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;;;;UCzHM;;;;;;;EAOf,aAAa;EACb,iBAAiB;;;;;;EAMjB,8BAA8B;EAC9B;;;;;EAKA;EACA,MAAM,OAAO;EACb;EACA,iBAAiB;EACjB;;;;;;EAMA,8BAA8B;;;;;;EAM9B,8BAA8B,WAAW,UAAU;;iBAGrC,wCACd,SAAS,qCACR;cAaU,sCAAsC;mBAY9B;mBAXF;mBACA;mBACA;mBACA;mBACA;mBACA;mBACA;mBACA;mBACA;EAGE,YAAA,MAAM,8BACvB,SAAS;EAaX,MAAM,KAAK,oBAAoB;;;;;;;;;UAoGvB;UAaA;UAYA;;;;;;;;;UAaA;;;;;;;;KC3PL,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;;;;;;;;;;;;;;iBCNI,sBAAsB,aAAa"}
|
package/dist/node/index.d.ts
CHANGED
|
@@ -278,6 +278,15 @@ declare class ChildProcessSubagentRunner implements ISubagentRunner {
|
|
|
278
278
|
private createStartPayload;
|
|
279
279
|
private forwardSandboxSettingChanges;
|
|
280
280
|
private resolveTranscriptPath;
|
|
281
|
+
/**
|
|
282
|
+
* Issue #3288 §1: how this job's child gets a human's yes/no — the parent session's own approver
|
|
283
|
+
* (`deps.permissionHandler`, the exact function the in-process runner already hands its own child
|
|
284
|
+
* session), bound to a `requester` identity that names this task so a surface can say "Background
|
|
285
|
+
* agent X wants to …" instead of an unattributed prompt. `undefined` when the parent session has no
|
|
286
|
+
* approver at all (print mode / a truly headless run): the result controller then denies every
|
|
287
|
+
* request from the child immediately, the same fail-closed default the enforcer applies with none.
|
|
288
|
+
*/
|
|
289
|
+
private permissionApprover;
|
|
281
290
|
}
|
|
282
291
|
//#endregion
|
|
283
292
|
//#region src/subagent-worker-start-dto.d.ts
|
|
@@ -427,7 +436,23 @@ interface ISubagentWorkerSandboxSettingsMessage {
|
|
|
427
436
|
type: 'sandbox_settings';
|
|
428
437
|
settings: TParentSandboxSettings;
|
|
429
438
|
}
|
|
430
|
-
|
|
439
|
+
/**
|
|
440
|
+
* Issue #3288 §1: the three-way answer a permission ask can receive — the same shape
|
|
441
|
+
* `@robota-sdk/agent-session`'s `TPermissionResult` allows, inlined here so this wire module does not
|
|
442
|
+
* need that package as a dependency for one literal union.
|
|
443
|
+
*/
|
|
444
|
+
type TSubagentWorkerPermissionResult = boolean | 'allow-session' | 'allow-project';
|
|
445
|
+
/**
|
|
446
|
+
* Issue #3288 §1: the parent's answer to a `permission_request` the child raised, correlated by
|
|
447
|
+
* `requestId`. `false` when the parent has no approver attached (print mode) — the fail-closed
|
|
448
|
+
* default, not a special case the child has to know about.
|
|
449
|
+
*/
|
|
450
|
+
interface ISubagentWorkerPermissionResponseMessage {
|
|
451
|
+
type: 'permission_response';
|
|
452
|
+
requestId: string;
|
|
453
|
+
result: TSubagentWorkerPermissionResult;
|
|
454
|
+
}
|
|
455
|
+
type TSubagentWorkerParentMessage = ISubagentWorkerStartMessage | ISubagentWorkerSendMessage | ISubagentWorkerCancelMessage | ISubagentWorkerSandboxSettingsMessage | ISubagentWorkerPermissionResponseMessage;
|
|
431
456
|
interface ISubagentWorkerReadyMessage {
|
|
432
457
|
type: 'ready';
|
|
433
458
|
/**
|
|
@@ -454,6 +479,17 @@ interface ISubagentWorkerToolEndMessage {
|
|
|
454
479
|
toolName: string;
|
|
455
480
|
success: boolean;
|
|
456
481
|
}
|
|
482
|
+
/**
|
|
483
|
+
* Issue #3288 §1: a tool call inside the child needs a human's approval. `requestId` correlates this
|
|
484
|
+
* with the parent's eventual `permission_response`; the child parks the call until it arrives (or
|
|
485
|
+
* until its own turn is cancelled, which the enforcer's existing signal race already denies).
|
|
486
|
+
*/
|
|
487
|
+
interface ISubagentWorkerPermissionRequestMessage {
|
|
488
|
+
type: 'permission_request';
|
|
489
|
+
requestId: string;
|
|
490
|
+
toolName: string;
|
|
491
|
+
toolArgs?: TToolArgs;
|
|
492
|
+
}
|
|
457
493
|
interface ISubagentWorkerResultMessage {
|
|
458
494
|
type: 'result';
|
|
459
495
|
output: string;
|
|
@@ -468,7 +504,7 @@ interface ISubagentWorkerCancelledMessage {
|
|
|
468
504
|
type: 'cancelled';
|
|
469
505
|
reason?: string;
|
|
470
506
|
}
|
|
471
|
-
type TSubagentWorkerChildMessage = ISubagentWorkerReadyMessage | ISubagentWorkerTextDeltaMessage | ISubagentWorkerToolStartMessage | ISubagentWorkerToolEndMessage | ISubagentWorkerResultMessage | ISubagentWorkerErrorMessage | ISubagentWorkerCancelledMessage;
|
|
507
|
+
type TSubagentWorkerChildMessage = ISubagentWorkerReadyMessage | ISubagentWorkerTextDeltaMessage | ISubagentWorkerToolStartMessage | ISubagentWorkerToolEndMessage | ISubagentWorkerPermissionRequestMessage | ISubagentWorkerResultMessage | ISubagentWorkerErrorMessage | ISubagentWorkerCancelledMessage;
|
|
472
508
|
declare function isSubagentWorkerParentMessage(value: TSubagentWorkerWireValue): value is TSubagentWorkerParentMessage;
|
|
473
509
|
declare function isSubagentWorkerChildMessage(value: TSubagentWorkerWireValue): value is TSubagentWorkerChildMessage;
|
|
474
510
|
//#endregion
|
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,gCAAgC;;;;;;;;;EAShC,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;;;;
|
|
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,gCAAgC;;;;;;;;;EAShC,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;;;;UCzHM;;;;;;;EAOf,aAAa;EACb,iBAAiB;;;;;;EAMjB,8BAA8B;EAC9B;;;;;EAKA;EACA,MAAM,OAAO;EACb;EACA,iBAAiB;EACjB;;;;;;EAMA,8BAA8B;;;;;;EAM9B,8BAA8B,WAAW,UAAU;;iBAGrC,wCACd,SAAS,qCACR;cAaU,sCAAsC;mBAY9B;mBAXF;mBACA;mBACA;mBACA;mBACA;mBACA;mBACA;mBACA;mBACA;EAGE,YAAA,MAAM,8BACvB,SAAS;EAaX,MAAM,KAAK,oBAAoB;;;;;;;;;UAoGvB;UAaA;UAYA;;;;;;;;;UAaA;;;;;;;;KC3PL,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;;;;;;;;;;;;;;iBCNI,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 ee}from"@robota-sdk/agent-process";import{createBoundedOutput as te,findProviderDefinition as m,isModelEffort as h,sumHistoryUsage as ne}from"@robota-sdk/agent-core";import{createSubagentLogger as re,createSubagentSession as ie,restoreSessionRecordIntoSession as ae}from"@robota-sdk/agent-framework";function oe(e){return{provider:{model:e.provider.model},permissions:e.permissions,defaultTrustLevel:e.defaultTrustLevel,...e.hooks===void 0?{}:{hooks:e.hooks}}}function se(e){return{agentsMd:e.agentsMd,projectNotesMd:e.projectNotesMd}}const g={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}},_={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 v(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function ce(e){return Array.isArray(e)&&e.every(e=>typeof e==`string`)}function le(e){return v(e)&&typeof e.filePath==`string`&&typeof e.content==`string`&&typeof e.contentHash==`string`}function ue(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`&&h(t);case`string[]`:return ce(t);case`file-entry[]`:return Array.isArray(t)&&t.every(le)}}function y(e,t){let n={};for(let r of Object.keys(t)){let t=e[r];t!==void 0&&(n[r]=t)}return n}function b(e,t,n){if(!v(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(!ue(i.kind,n))return{ok:!1,reason:`${e}.${r}: expected ${i.kind}`}}return{ok:!0,value:y(t,n)}}function x(e){return y(e,g)}function S(e){return b(`agentDefinition`,e,g)}function C(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 w(e){return y(e,_)}function T(e){return b(`parentContext`,e,_)}function E(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 de(e){return e.sessionTiers===void 0?{}:{sessionTiers:e.sessionTiers}}async function D(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(m(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:x(me(r,e)),parentConfig:oe(t.getParentPermissionRules===void 0?t.config:{...t.config,permissions:t.getParentPermissionRules()}),parentContext:w(se(t.context)),...n.connection??O(e,t,n,process.env,process.env),permissionMode:t.permissionMode,...de(t),...n.parentSandboxSettings===void 0?{}:{parentSandboxSettings:n.parentSandboxSettings},...n.logsDir?{logsDir:n.logsDir}:{}};return D(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=m(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 A(e){if(!k(e)||!j(e,`nonce`)||!j(e,`digest`))return!1;let t=e.names;return Array.isArray(t)&&t.every(e=>typeof e==`string`)}function j(e,t){return typeof e[t]==`string`}function M(e,t){return j(e,t)}function N(e,t){return j(e,t)}function P(e,t){return e[t]===void 0||typeof e[t]==`string`}function F(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 I(e){if(e.composedToolNames===void 0)return!0;let t=e.composedToolNames;return Array.isArray(t)?t.every(e=>typeof e==`string`):!1}function L(e){return!k(e)||!N(e,`taskId`)||!k(e.request)||!M(e.request,`agentType`)||!M(e.request,`prompt`)||!M(e.request,`permissionPolicy`)||!M(e.request,`cwd`)||!P(e.request,`resumeSessionId`)||e.worktree!==void 0&&(!k(e.worktree)||!j(e.worktree,`path`))||!S(e.agentDefinition).ok||!k(e.parentConfig)||!T(e.parentContext).ok||!k(e.providerProfile)||!j(e.providerProfile,`type`)||!j(e.providerProfile,`model`)||e.parentSandboxSettings!==void 0&&!k(e.parentSandboxSettings)?!1:A(e.connectionCheck)}function R(e){if(!k(e)||!j(e,`type`))return!1;switch(e.type){case`start`:return L(e.payload);case`send`:return j(e,`prompt`);case`cancel`:return e.reason===void 0||typeof e.reason==`string`;case`sandbox_settings`:return k(e.settings);default:return!1}}function z(e){if(!k(e)||!j(e,`type`))return!1;switch(e.type){case`ready`:return I(e);case`text_delta`:return j(e,`delta`);case`tool_start`:return j(e,`toolName`);case`tool_end`:return j(e,`toolName`)&&typeof e.success==`boolean`;case`result`:return j(e,`output`)&&F(e);case`error`:return j(e,`message`);case`cancelled`:return e.reason===void 0||typeof e.reason==`string`;default:return!1}}const _e=process.platform!==`win32`;function ve(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 B=new WeakMap;function ye(e){let t=e.stderr;if(!t)return;let n=te({maxBytes:4096,retain:`tail`,truncationMarker:()=>``});B.set(e,n),t.on(`error`,()=>{}),t.on(`data`,e=>n.append(e))}function be(e){return(B.get(e)?.toString()??``).trim()}function xe(e,t,n,r,a){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:Se(e.toolArgs)});break;case`tool_end`:a?.({type:`background_task_tool_end`,toolName:e.toolName,success:e.success});break;default:r(new i(`runner`,`Unhandled subagent worker message`))}}function Se(e){if(!e)return;let t=Object.values(e)[0];if(t!==void 0)return typeof t==`object`?JSON.stringify(t):String(t)}function V(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 H(e,t){await ee(e.child,{graceMs:e.killGraceMs,processGroup:_e,preKill:async()=>{e.child.connected&&(await V(e.child,{type:`cancel`,reason:t}).catch(()=>void 0),await ve(e.child,e.killGraceMs))}})}function Ce(e){return new Promise((t,n)=>{new we(e,t,n).start()})}var we=class{options;resolve;reject;settled=!1;started=!1;ready=!1;timeoutTimer;handshakeTimer;handshakeBudgetMs;payload;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=Ee(this.options.runtime,e=>this.rejectOnce(e)),this.handshakeTimer=setTimeout(()=>{this.ready||this.settled||(H(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:V(e,{type:`start`,payload:t})).catch(e=>{this.rejectOnce(e instanceof Error?e:Error(String(e)))})};onMessage=e=>{if(!z(e)){this.rejectOnce(new i(`runner`,`Received malformed subagent worker message`));return}this.ready=!0,clearTimeout(this.handshakeTimer);let{job:t}=this.options.runtime;xe(e,this.startWorker,this.resolveOnce,this.rejectOnce,t.emit)};onError=e=>{this.rejectOnce(new i(`crash`,e.message))};onExit=(e,t)=>{this.settled||this.rejectOnce(new i(`crash`,Oe(e,t,be(this.options.runtime.child))))};resolveOnce=e=>{if(this.settled)return;this.settled=!0,this.clearTimers(),this.cleanup();let{runtime:t,resolveTranscriptPath:n}=this.options;this.resolve(De(t.job,e,n))};rejectOnce=e=>{this.settled||(this.settled=!0,this.clearTimers(),this.cleanup(),this.reject(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 Te(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 Ee(e,t){if(e.job.request.timeoutMs)return setTimeout(()=>{H(e,`Subagent worker timed out`),t(new i(`timeout`,`Subagent worker timed out`))},e.job.request.timeoutMs)}function De(e,t,n){let r=n(e);return{taskId:e.taskId,output:t.output,...r?{metadata:{transcriptPath:r,logPath:r}}:{},...t.usage?{usage:t.usage}:{}}}function Oe(e,t,n){return`Subagent worker exited before result: ${t===null?`exit code ${e===null?`unknown`:e}`:`signal ${t}`}${n.length>0?`: ${n}`:``}`}const U=`--__robota-subagent-worker`;function ke(e){return e.includes(U)}const Ae=process.platform!==`win32`;function je(e){return t=>{let n=new W(t,e);return e.worktreeIsolation===!1?n:c({runner:n,worktreeAdapter:e.worktreeAdapter,hooks:t.config.hooks,hookTypeExecutors:t.hookTypeExecutors})}}var W=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,U],{cwd:d(t),env:r,stdio:[`ignore`,`ignore`,`pipe`,`ipc`],detached:Ae});ye(a),this.forwardSandboxSettingChanges(a);let o={job:t,child:a,killGraceMs:this.killGraceMs},s=Ce({runtime:o,payload:this.createStartPayload(t,i),...this.handshakeBudgetMs===void 0?{}:{handshakeBudgetMs:this.handshakeBudgetMs},resolveTranscriptPath:e=>this.resolveTranscriptPath(e)}),c=Te(t.taskId);s.catch(()=>void 0);let l=Promise.race([s,c.promise]);l.catch(()=>void 0);let u=this.resolveTranscriptPath(t);return{taskId:t.taskId,...a.pid!==void 0&&{pid:a.pid},...u!==void 0&&{transcriptPath:u,logPath:u},result:l,cancel:async e=>{c.reject(e),await H(o,e)},send:async e=>{await V(a,{type:`send`,prompt:e})},...u!==void 0&&{readLog:async e=>Me(t.taskId,u,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&&V(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`)}};function Me(e,r,i){return t(r)?o(e,n(r,`utf8`).split(/\r?\n/).filter(Boolean),i):{taskId:e,cursor:i,lines:[]}}function Ne(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.`);ae(n,r,t)}}function Pe(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 Fe(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 Ie={write:()=>{},writeLine:()=>{},writeMarkdown:()=>{},writeError:()=>{},prompt:()=>Promise.resolve(``),select:()=>Promise.resolve(0),spinner:()=>({stop:()=>{},update:()=>{}})};let G=null,K=!1,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 Le(e){try{return ne(e.getFullHistory())}catch{return}}async function Re(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 Fe(e.sandboxProjection,t.sandboxFactories),r=s(e.providerProfile,e.request.model,t.providerDefinitions),i=e.logsDir?re(e.request.parentSessionId,e.taskId,e.logsDir):void 0,a=Pe(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;G=ie({agentDefinition:C(e.agentDefinition),parentConfig:e.parentConfig,parentContext:E(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:Ie,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:$}),Ne(e,G,a);let l=await G.run(e.request.prompt);if(Y!==void 0){Q({type:`error`,message:Y},0);return}if(K){Q({type:`cancelled`,reason:`Subagent worker cancelled`},130);return}let u=Le(G);Q({type:`result`,output:l,...u?{usage:u}:{}},0)}catch(e){if(Y!==void 0){Q({type:`error`,message:Y},0);return}if(K){Q({type:`cancelled`,reason:`Subagent worker cancelled`},130);return}Q({type:`error`,message:e instanceof Error?e.message:String(e)},0)}}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 ze(e){if(G===null){Z({type:`error`,message:`Subagent worker has not started`});return}X=X.then(async()=>{try{await G?.run(e)}catch(e){Z({type:`error`,message:e instanceof Error?e.message:String(e)})}})}async function Be(e){K=!0,G?.abort(),Z({type:`cancelled`,reason:e}),await G?.shutdown({reason:`other`}).catch(()=>void 0),setTimeout(()=>process.exit(130),0)}function Ve(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 He(e){q=e;try{J?.applyParentSettings?.(e)}catch(e){Y??=e instanceof Error?e.message:String(e),G?.abort()}}function Ue(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.
|
|
2
|
-
`),process.exit(2)),process.on(`message`,t=>{if(!
|
|
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.
|
|
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
|