@oai404iao/pi-subagent 0.2.0 → 0.4.0-alpha.0
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/README.md +266 -75
- package/agents/worker.md +1 -1
- package/config.example.json +4 -1
- package/config.schema.json +29 -4
- package/package.json +9 -6
- package/src/agent-state.ts +125 -0
- package/src/agent-sync.ts +64 -53
- package/src/agents.ts +3 -22
- package/src/catalog.ts +59 -7
- package/src/completion-mailbox.ts +656 -0
- package/src/config.ts +57 -6
- package/src/coordinator.ts +2476 -205
- package/src/descriptor.ts +118 -12
- package/src/index.ts +177 -27
- package/src/mailbox.ts +451 -0
- package/src/providers.ts +223 -28
- package/src/render.ts +25 -8
- package/src/scheduler.ts +173 -0
- package/src/schemas.ts +114 -11
- package/src/task-path.ts +188 -0
- package/src/types.ts +74 -15
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ The design independently adapts the
|
|
|
5
5
|
[DeepSeek Harness subagent seam](https://github.com/deepseek-ai/deepseek-harness/tree/4d03472cd098dc48a630e526ca620f4f37f18a0e/docs/subsystems)
|
|
6
6
|
to Pi's extension and SDK APIs.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Peer floor: Pi 0.84.2; tested against 0.84.2 and 0.85.1.
|
|
9
9
|
|
|
10
10
|
> npm identity: `@oai404iao/pi-subagent`. Once the selected version is
|
|
11
11
|
> available on npm, install it from npm; use a local checkout before its
|
|
@@ -15,21 +15,29 @@ Compatibility: Pi 0.84.2 or newer; tested against 0.84.2.
|
|
|
15
15
|
|
|
16
16
|
- **Named providers**
|
|
17
17
|
- `spawn`: fresh child with no parent conversation
|
|
18
|
-
- `fork`:
|
|
18
|
+
- `fork`: child seeded through the parent's latest completed turn
|
|
19
|
+
- **Readable task paths** such as `/root/review/auth`, with relative addressing
|
|
20
|
+
- **Explicit context inheritance**: `fresh`, `all_completed`, or
|
|
21
|
+
`last_n_completed`
|
|
19
22
|
- **Two lifecycles**
|
|
20
23
|
- foreground one-shot runs return the child's final answer
|
|
21
|
-
- background continuable runs return a
|
|
24
|
+
- background continuable runs return a readable path and stable agent id at
|
|
25
|
+
prompt acceptance
|
|
22
26
|
- **Foreground-only policy** that removes background scheduling and lifecycle controls
|
|
23
27
|
- **Independent context and session** for every child
|
|
24
|
-
- **
|
|
25
|
-
|
|
28
|
+
- **User-owned agent catalog** with bundled templates used only for
|
|
29
|
+
first-install and package-version initialization
|
|
26
30
|
- **Durable descriptors and lineage** stored in child JSONL sessions
|
|
27
|
-
- **
|
|
31
|
+
- **Two background protocols**: compatible immediate follow-ups or an opt-in
|
|
32
|
+
durable mailbox with explicit turn starts
|
|
33
|
+
- **Quiet durable completion updates** with event-driven `wait_agent`
|
|
28
34
|
- **Control plane** with listing and interruption
|
|
29
35
|
- **Child-to-parent `report` channel** for continuable children
|
|
30
36
|
- **Nested delegation** with an absolute persisted depth limit
|
|
31
37
|
- **Dynamic agent-name enums** generated from the effective user/project catalog
|
|
32
38
|
- **Parallel-safe delegation**: multiple `subagent` calls in one assistant message may overlap
|
|
39
|
+
- **Bounded background execution** with per-agent cold-resume serialization
|
|
40
|
+
- **Optional idle runtime LRU** with transparent cold resume
|
|
33
41
|
- **Composable tool ceilings** that preserve model/extension tool decisions
|
|
34
42
|
- **Usage accounting, streaming progress, output caps, and custom TUI rendering**
|
|
35
43
|
|
|
@@ -57,17 +65,19 @@ For a temporary test:
|
|
|
57
65
|
pi -e /absolute/path/to/pi-extensions/pi-subagent
|
|
58
66
|
```
|
|
59
67
|
|
|
60
|
-
|
|
68
|
+
Development is pinned to Pi `0.85.1`; full compatibility checks retain the `0.84.2` floor.
|
|
61
69
|
|
|
62
70
|
## Model-facing tools
|
|
63
71
|
|
|
64
72
|
| Tool | Behavior |
|
|
65
73
|
| --- | --- |
|
|
66
|
-
| `subagent` | Starts a
|
|
67
|
-
| `subagent_fork` | Starts a
|
|
68
|
-
| `send_message` |
|
|
69
|
-
| `
|
|
70
|
-
| `
|
|
74
|
+
| `subagent` | Starts a named child with selectable context inheritance. Background continuable mode is the default unless configured otherwise; foreground-only mode always waits for the answer. |
|
|
75
|
+
| `subagent_fork` | Starts a child with all completed parent turns. It remains foreground by default; `run_in_background: true` creates a continuable fork. |
|
|
76
|
+
| `send_message` | Targets a direct child by path or durable id. Legacy starts/joins the next FIFO turn; `mailbox-v2` only durably appends. |
|
|
77
|
+
| `followup_task` | `mailbox-v2` only: targets a direct child by path or id, atomically claims the pending FIFO batch, and starts one scheduled turn. |
|
|
78
|
+
| `wait_agent` | `mailbox-v2` only: waits event-driven for unread direct-child completions without starting a model turn or consuming a scheduler slot. |
|
|
79
|
+
| `interrupt_agent` | Requests cancellation of a live descendant by path or id without deleting its session. Active only when background execution is enabled. |
|
|
80
|
+
| `list_agents` | Lists readable descendant paths as `running`, `idle`, or `ready`, including separate `pending=N` task and `updates=N` completion counts. Active only when background execution is enabled. |
|
|
71
81
|
| `report` | Child-only return channel. Installed automatically in continuable children. |
|
|
72
82
|
|
|
73
83
|
The `/subagents` command shows the effective scheduling mode, available agent definitions,
|
|
@@ -92,52 +102,118 @@ Use subagent_fork with planner to plan the change using our completed discussion
|
|
|
92
102
|
List my subagents, then send the scout a follow-up asking for exact call sites.
|
|
93
103
|
```
|
|
94
104
|
|
|
105
|
+
With `"backgroundProtocol": "mailbox-v2"`, enqueue first and start explicitly:
|
|
106
|
+
|
|
107
|
+
```text
|
|
108
|
+
Send the scout two mailbox messages, then call followup_task once so it handles
|
|
109
|
+
the current FIFO batch in one turn. Call wait_agent when the next action needs
|
|
110
|
+
its quiet completion update.
|
|
111
|
+
```
|
|
112
|
+
|
|
95
113
|
Pi executes sibling tool calls in parallel, so this package deliberately accepts one delegation per `subagent` call instead of embedding a separate `tasks` array.
|
|
96
114
|
|
|
97
|
-
|
|
115
|
+
### Task paths and context
|
|
116
|
+
|
|
117
|
+
Every new child has an immutable path rooted at `/root`:
|
|
98
118
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
119
|
+
```text
|
|
120
|
+
/root
|
|
121
|
+
├─ review
|
|
122
|
+
│ └─ auth
|
|
123
|
+
└─ tests
|
|
124
|
+
```
|
|
103
125
|
|
|
104
|
-
|
|
105
|
-
|
|
126
|
+
Set `task_name` to choose the final path segment. Names use 1–64 lowercase
|
|
127
|
+
ASCII letters, digits, hyphens, or underscores. If omitted, the extension
|
|
128
|
+
slugs `description` and appends `-2`, `-3`, and so on to avoid sibling
|
|
129
|
+
collisions. Explicit duplicate sibling names fail before child creation.
|
|
106
130
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
3. nearest trusted `.pi/agents/*.md`
|
|
131
|
+
Control tools retain their existing parameter names for compatibility, but
|
|
132
|
+
accept any of:
|
|
110
133
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
project definitions; `both` loads bundled definitions, user overrides, then
|
|
115
|
-
project overrides.
|
|
134
|
+
- a durable UUIDv7 agent id;
|
|
135
|
+
- an absolute path such as `/root/review/auth`;
|
|
136
|
+
- a path relative to the caller, such as `auth`, `./auth`, or `../tests`.
|
|
116
137
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
138
|
+
References cannot escape `/root`. Path lookup is resolved to the durable agent
|
|
139
|
+
id before per-agent serialization; mailbox ownership, events, and durable
|
|
140
|
+
lineage remain UUID-based. Direct-child restrictions still apply to
|
|
141
|
+
`send_message` and `followup_task`, while `interrupt_agent` still requires a
|
|
142
|
+
descendant. Paths do not bypass those checks.
|
|
121
143
|
|
|
122
|
-
|
|
144
|
+
`subagent` accepts an optional context object:
|
|
123
145
|
|
|
124
|
-
|
|
125
|
-
|
|
146
|
+
```json
|
|
147
|
+
{
|
|
148
|
+
"task_name": "review",
|
|
149
|
+
"context": {
|
|
150
|
+
"mode": "last_n_completed",
|
|
151
|
+
"completed_turns": 2
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Context modes are:
|
|
157
|
+
|
|
158
|
+
| Mode | Initial child context |
|
|
159
|
+
| --- | --- |
|
|
160
|
+
| `fresh` | No parent conversation. This is the compatible `subagent` default. |
|
|
161
|
+
| `all_completed` | The parent's compaction-aware context through its latest completed assistant turn. |
|
|
162
|
+
| `last_n_completed` | The last `completed_turns` complete parent turns, bounded to 1–100. |
|
|
163
|
+
|
|
164
|
+
The active assistant/tool-call suffix is always excluded. A compaction summary
|
|
165
|
+
is retained when it is the only safe representation of completed history; if
|
|
166
|
+
it prevents exact turn counting, `last_n_completed` keeps that summary only
|
|
167
|
+
when fewer than the requested number of explicit completed turns remain.
|
|
168
|
+
Context is copied once into a new child session. Descriptor, lineage, mailbox,
|
|
169
|
+
completion, and other plain extension-state entries are not copied.
|
|
170
|
+
|
|
171
|
+
`subagent_fork` is the compatibility shortcut for `all_completed`. It remains
|
|
172
|
+
foreground unless `run_in_background: true` is explicitly supplied, even when
|
|
173
|
+
`defaultBackground` is true. A background fork is continuable and supports the
|
|
174
|
+
same legacy or mailbox-v2 follow-up lifecycle as a fresh child.
|
|
175
|
+
|
|
176
|
+
New sessions persist descriptor version 3 with their task path and context
|
|
177
|
+
policy. Version-2 descriptors remain readable and controllable by UUID; they
|
|
178
|
+
are displayed under the deterministic compatibility namespace
|
|
179
|
+
`/root/.legacy/<agent-id>`.
|
|
180
|
+
|
|
181
|
+
## Agent definitions
|
|
182
|
+
|
|
183
|
+
The package ships `scout`, `planner`, `reviewer`, and `worker` as initialization
|
|
184
|
+
templates. On the first extension startup after installation, and whenever the
|
|
185
|
+
detected package version changes, those templates are materialized into:
|
|
126
186
|
|
|
127
187
|
```text
|
|
128
188
|
<Pi agent dir>/agents/*.md
|
|
129
189
|
```
|
|
130
190
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
191
|
+
The package copies are **never runtime agent definitions or fallbacks**.
|
|
192
|
+
Runtime discovery reads only:
|
|
193
|
+
|
|
194
|
+
1. `<Pi agent dir>/agents/*.md`
|
|
195
|
+
2. nearest trusted `.pi/agents/*.md`
|
|
196
|
+
|
|
197
|
+
Project definitions replace user definitions with the same name when project
|
|
198
|
+
scope is enabled. Project agents are disabled by the default
|
|
199
|
+
`agentScope: "user"`. Setting the scope to `project` selects only project
|
|
200
|
+
definitions; `both` loads user definitions followed by project overrides.
|
|
201
|
+
|
|
202
|
+
After the current package version has been initialized, the user directory is
|
|
203
|
+
authoritative. Same-version startups do not restore missing files or refresh
|
|
204
|
+
changed templates. If the user deletes every agent definition, the effective
|
|
205
|
+
catalog is empty and delegation tools are inactive after restart or `/reload`.
|
|
206
|
+
A later package-version change starts a new initialization pass and installs
|
|
207
|
+
missing bundled templates again.
|
|
208
|
+
|
|
209
|
+
Initialization behavior:
|
|
134
210
|
|
|
135
211
|
1. **First startup:** missing presets are installed. A different pre-existing same-name file
|
|
136
212
|
is backed up before the bundled version replaces it.
|
|
137
213
|
2. **Ordinary restart of the same release:** user edits are preserved.
|
|
138
214
|
3. **Plugin update:** differing user presets are backed up, then replaced with the new
|
|
139
|
-
bundled versions. A bundled prompt
|
|
140
|
-
|
|
215
|
+
bundled versions. A bundled prompt change without a package-version change does not
|
|
216
|
+
trigger a refresh.
|
|
141
217
|
4. **Retired preset:** a formerly bundled name is backed up and removed so an obsolete
|
|
142
218
|
prompt does not remain silently active.
|
|
143
219
|
5. Files whose names were never managed bundled presets are left untouched.
|
|
@@ -146,8 +222,10 @@ Synchronization holds a cross-process lock, then preflights and stages the whole
|
|
|
146
222
|
before changing agent files. If a commit fails, it rolls back already-applied changes and
|
|
147
223
|
fails extension startup rather than falling back to package prompts. Same-name symbolic
|
|
148
224
|
links are preserved as symbolic links inside the backup directory before the user path is
|
|
149
|
-
replaced. An invalid synchronization manifest is copied to a
|
|
150
|
-
|
|
225
|
+
replaced. An invalid synchronization manifest is copied to a content-addressed
|
|
226
|
+
`.corrupt-*` file and skips template initialization; user and project agent discovery
|
|
227
|
+
continues with a warning. Repair the manifest, or deliberately remove it to request a new
|
|
228
|
+
first-install initialization pass.
|
|
151
229
|
|
|
152
230
|
Synchronization state and backups live at:
|
|
153
231
|
|
|
@@ -236,12 +314,15 @@ See [`config.example.json`](config.example.json) and [`config.schema.json`](conf
|
|
|
236
314
|
{
|
|
237
315
|
"$schema": "/path/to/pi-subagent/config.schema.json",
|
|
238
316
|
"agentScope": "user",
|
|
239
|
-
"syncBundledAgents": false,
|
|
240
317
|
"maxDepth": 3,
|
|
241
318
|
"enableRunInBackground": true,
|
|
242
319
|
"defaultBackground": true,
|
|
320
|
+
"maxConcurrentBackgroundRuns": 4,
|
|
321
|
+
"maxIdleRuntimes": 0,
|
|
322
|
+
"backgroundProtocol": "legacy",
|
|
243
323
|
"reportDelivery": "wakeup",
|
|
244
324
|
"inheritExtensions": false,
|
|
325
|
+
"openAIIdentity": false,
|
|
245
326
|
"maxOutputBytes": 51200
|
|
246
327
|
}
|
|
247
328
|
```
|
|
@@ -249,16 +330,33 @@ See [`config.example.json`](config.example.json) and [`config.schema.json`](conf
|
|
|
249
330
|
| Setting | Default | Meaning |
|
|
250
331
|
| --- | --- | --- |
|
|
251
332
|
| `agentScope` | `user` | Select user definitions, project definitions, or user definitions followed by project overrides. |
|
|
252
|
-
| `syncBundledAgents` | `false` | **User-level config only.** Opt in to writing managed bundled presets into `<Pi agent dir>/agents`. `true` may install, replace, retire, and back up those files. |
|
|
253
333
|
| `maxDepth` | `3` | Absolute delegation depth; a top-level Pi session is depth 0. |
|
|
254
334
|
| `enableRunInBackground` | `true` | Enable continuable background children and their model-facing lifecycle controls. Set `false` for strict foreground-only mode. |
|
|
255
|
-
| `defaultBackground` | `true` | Default scheduling for
|
|
256
|
-
| `
|
|
335
|
+
| `defaultBackground` | `true` | Default scheduling for `subagent` calls when background execution is enabled. `subagent_fork` remains foreground unless explicitly requested. |
|
|
336
|
+
| `maxConcurrentBackgroundRuns` | `4` | Maximum continuable subagent turns executing at once in one extension runtime. Additional top-level runs wait in FIFO order; nested work fails at capacity instead of deadlocking its parent turn. |
|
|
337
|
+
| `maxIdleRuntimes` | `0` | Process-wide LRU capacity for settled continuable runtimes. `0` preserves immediate unload; a positive value keeps the most recently used idle runtimes and transparently cold-resumes evicted paths. |
|
|
338
|
+
| `backgroundProtocol` | `legacy` | `legacy` preserves immediate `send_message` turns. `mailbox-v2` makes `send_message` enqueue-only and requires `followup_task` to start a turn. The protocol is snapshotted in each child descriptor. |
|
|
339
|
+
| `reportDelivery` | `wakeup` | Controls explicit `report` calls: `wakeup` starts/queues a parent turn; `quiet` waits for the parent's next turn. Mailbox-v2 completion updates are always quiet. |
|
|
257
340
|
| `inheritExtensions` | `false` | Load other Pi extensions in child runtimes. This package filters itself out; explicit agent tool ceilings still apply. |
|
|
258
|
-
| `
|
|
341
|
+
| `openAIIdentity` | `false` | For OpenAI Responses child models, inject only the named `pi-codex-minimal-tools` identity lifecycle inline. Codex Session/Thread/Turn/Window ids remain owned and serialized by that package. |
|
|
342
|
+
| `maxOutputBytes` | `51200` | Cap for parent-visible foreground output, reports, completion updates, and legacy settlement notices. Full output remains in the child session. |
|
|
259
343
|
|
|
260
344
|
Invalid configuration and unknown child tool names fail loud before the child's first model request.
|
|
261
345
|
|
|
346
|
+
The retired user-level `syncBundledAgents` key from versions 0.2 and 0.3 is
|
|
347
|
+
accepted for configuration compatibility but ignored. Template initialization
|
|
348
|
+
is now automatic and runtime discovery never reads bundled definitions.
|
|
349
|
+
|
|
350
|
+
`openAIIdentity` and `inheritExtensions` are independent. The former adds only
|
|
351
|
+
the lightweight Codex identity lifecycle even when normal extension inheritance
|
|
352
|
+
is disabled. Enable `inheritExtensions` as well when the child should receive
|
|
353
|
+
the complete separately installed Codex extension tool surface such as
|
|
354
|
+
`web_search` and `apply_patch`.
|
|
355
|
+
|
|
356
|
+
The Codex adapter is an optional package dependency. If an installation omits
|
|
357
|
+
optional dependencies, `openAIIdentity: true` fails before the child starts
|
|
358
|
+
with an actionable missing-adapter error.
|
|
359
|
+
|
|
262
360
|
### Foreground-only mode
|
|
263
361
|
|
|
264
362
|
```json
|
|
@@ -273,14 +371,15 @@ In this mode:
|
|
|
273
371
|
- `run_in_background` is removed from the model-facing schema at session startup;
|
|
274
372
|
- a forced `run_in_background: true` call is rejected before a child is created;
|
|
275
373
|
- nested subagents inherit the foreground-only policy through the durable runtime snapshot;
|
|
276
|
-
- `send_message`, `interrupt_agent`, and `list_agents` are removed from the active
|
|
374
|
+
- `send_message`, `followup_task`, `wait_agent`, `interrupt_agent`, and `list_agents` are removed from the active
|
|
277
375
|
model tool set, including inside nested children;
|
|
278
376
|
- sibling foreground calls may still execute in parallel in one assistant message.
|
|
279
377
|
|
|
280
|
-
`subagent_fork`
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
378
|
+
`subagent_fork` remains foreground in this mode and its `run_in_background`
|
|
379
|
+
field is removed too. The `/subagents` command remains available for human
|
|
380
|
+
inspection of historical children, but persisted continuable children cannot
|
|
381
|
+
be resumed until background execution is re-enabled. Run `/reload` or restart
|
|
382
|
+
Pi after changing this setting so the active tool set and displayed schema are
|
|
284
383
|
refreshed.
|
|
285
384
|
|
|
286
385
|
## Lifecycle
|
|
@@ -301,38 +400,131 @@ The caller waits for one isolated child run. Only the child's last non-empty ass
|
|
|
301
400
|
|
|
302
401
|
### Continuable
|
|
303
402
|
|
|
304
|
-
The start tool resolves at prompt preflight acceptance and returns the
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
403
|
+
The start tool resolves at prompt preflight acceptance and returns the child's
|
|
404
|
+
readable task path plus stable agent id (UUIDv7). Agent ids are independent of
|
|
405
|
+
Pi session (file) ids: they are
|
|
406
|
+
generated once per subagent, recorded in the child's session as `pi-subagent/agent`,
|
|
407
|
+
and chained through `parentAgentId` in the descriptor, so children stay addressable
|
|
408
|
+
even when a parent session is forked or re-created. When an activation settles:
|
|
409
|
+
|
|
410
|
+
1. `legacy` sends the parent its existing wakeup settlement; `mailbox-v2`
|
|
411
|
+
appends a quiet completion update to the direct parent's session instead;
|
|
412
|
+
2. once owned descendants are done, the child runtime is either disposed or
|
|
413
|
+
retained in the optional idle LRU;
|
|
414
|
+
3. an unloaded persistent session is `ready`; a retained settled runtime is
|
|
415
|
+
`idle`;
|
|
416
|
+
4. legacy `send_message`, or mailbox-v2 `followup_task`, can cold-resume that
|
|
417
|
+
same session for another turn.
|
|
418
|
+
|
|
419
|
+
A child can explicitly call `report` before settlement. Reports retain
|
|
420
|
+
`reportDelivery` behavior and are separate from quiet mailbox-v2 completions.
|
|
421
|
+
|
|
422
|
+
Continuable turns share a bounded scheduler. Calls targeting the same durable
|
|
423
|
+
agent are serialized so concurrent messages cannot create multiple cold
|
|
424
|
+
runtimes for one child session. Every scheduler-admitted run has a stable
|
|
425
|
+
`turnId` in delegation details and the paired `pi-subagent:turn-start` /
|
|
426
|
+
`pi-subagent:turn-end` events. FIFO follow-ups accepted while that
|
|
427
|
+
`AgentSession` is already running remain part of the same admitted run.
|
|
428
|
+
Existing `pi-subagent:start` / `pi-subagent:end` events continue to describe
|
|
429
|
+
the wider activation lifecycle and now include `taskPath`.
|
|
430
|
+
|
|
431
|
+
With `maxIdleRuntimes: 0`, disposal behavior is unchanged. A positive value
|
|
432
|
+
retains only settled continuable runtimes with no active run, owned descendant,
|
|
433
|
+
or pending mailbox claim. LRU accounting is serialized across concurrent
|
|
434
|
+
settlements. Eviction disposes only the runtime; the descriptor, path, context,
|
|
435
|
+
session history, task mailbox, and completion mailbox remain durable, so the
|
|
436
|
+
next accepted turn cold-resumes normally.
|
|
437
|
+
|
|
438
|
+
#### Mailbox-v2
|
|
439
|
+
|
|
440
|
+
Set `"backgroundProtocol": "mailbox-v2"` to separate delivery from execution:
|
|
441
|
+
|
|
442
|
+
1. `send_message` appends a bounded message record to the direct child's JSONL
|
|
443
|
+
session and returns its stable message id. It does not create a runtime,
|
|
444
|
+
acquire a scheduler permit, create a `turnId`, or emit turn events.
|
|
445
|
+
2. `followup_task` snapshots the current pending FIFO prefix, waits for the
|
|
446
|
+
normal background scheduler, and starts one turn containing that batch.
|
|
447
|
+
Messages arriving after the snapshot remain pending for a later turn.
|
|
448
|
+
3. A claim is committed only after Pi prompt preflight succeeds. The durable
|
|
449
|
+
user-turn marker makes a claim without its corresponding prompt recoverable
|
|
450
|
+
after a crash. Once the user turn is durable, the batch is consumed even if
|
|
451
|
+
that model turn later fails or is interrupted.
|
|
452
|
+
4. Scheduler rejection, cancellation while queued, and shutdown before prompt
|
|
453
|
+
acceptance leave the batch pending. Concurrent sends and starts for one
|
|
454
|
+
agent are serialized within the extension process.
|
|
455
|
+
5. A completed turn appends a stable completion record to the direct parent's
|
|
456
|
+
separate notification mailbox before the child unloads. This custom entry
|
|
457
|
+
does not enter model context and does not wake or start the parent.
|
|
458
|
+
6. `wait_agent` returns existing unread updates immediately or subscribes to
|
|
459
|
+
in-process mailbox activity and rechecks durable state after wakeup. Its
|
|
460
|
+
optional timeout defaults to 30 seconds and is capped at 120 seconds.
|
|
461
|
+
7. A returned update becomes read only after Pi durably appends the successful
|
|
462
|
+
`wait_agent` tool result. An interrupted/failed delivery is released at the
|
|
463
|
+
end of the parent turn; a process restart also makes an orphan reservation
|
|
464
|
+
available again. Delivery output is bounded to a 256 KiB FIFO prefix.
|
|
465
|
+
8. If the parent completion append fails, the child records an undelivered
|
|
466
|
+
fallback in its own session and emits `pi-subagent:completion-error` before
|
|
467
|
+
normal residency cleanup; no false completion is exposed to `wait_agent`.
|
|
468
|
+
|
|
469
|
+
Each message is limited to 131,072 characters; a mailbox is limited to 256 pending
|
|
470
|
+
messages and 256 KiB of pending UTF-8 content. `list_agents` exposes task
|
|
471
|
+
`pending` and completion `updates` independently from lifecycle and scheduler
|
|
472
|
+
state.
|
|
473
|
+
|
|
474
|
+
FIFO follows durable append order after target resolution, not the invocation
|
|
475
|
+
order of concurrent `send_message` calls. Each returned `pendingMessages` count
|
|
476
|
+
describes that append. If one message must precede another, await the first send
|
|
477
|
+
before starting the next.
|
|
478
|
+
|
|
479
|
+
`mailbox-v2` is opt-in. Existing descriptors without a protocol field resume as
|
|
480
|
+
`legacy`, and the default legacy tool behavior is unchanged. A persisted
|
|
481
|
+
mailbox-v2 child keeps its protocol snapshot. `followup_task` and `wait_agent` remain available
|
|
482
|
+
when such a child exists even if the current default is later changed back to
|
|
483
|
+
legacy.
|
|
484
|
+
|
|
485
|
+
`wait_agent` observes only completions written by the current agent's direct
|
|
486
|
+
children. Nested parents consume their own child updates; a root wait does not
|
|
487
|
+
steal grandchild updates. Legacy settlements and all explicit reports retain
|
|
488
|
+
their previous behavior.
|
|
489
|
+
|
|
490
|
+
### Inherited-context boundary
|
|
491
|
+
|
|
492
|
+
The parent is executing a tool when an inherited-context child starts, so its
|
|
493
|
+
current assistant/tool-result sequence is incomplete. The provider projects
|
|
494
|
+
Pi's active compaction-aware context only through a safe completed boundary,
|
|
495
|
+
then copies model-facing entries into a new child session. This avoids seeding
|
|
496
|
+
an invalid unbalanced tool turn and prevents parent control-log records from
|
|
497
|
+
becoming child descriptors or mailbox ownership.
|
|
316
498
|
|
|
317
499
|
## Security
|
|
318
500
|
|
|
319
501
|
- Extensions and subagents run with the user's OS permissions.
|
|
320
|
-
-
|
|
321
|
-
agent directory and may create backups under
|
|
322
|
-
`<Pi agent dir>/.pi-subagent/backups`.
|
|
323
|
-
paths.
|
|
502
|
+
- First-install and package-version initialization writes bundled templates
|
|
503
|
+
into the user agent directory and may create backups under
|
|
504
|
+
`<Pi agent dir>/.pi-subagent/backups`.
|
|
324
505
|
- Project-local agents are repository-controlled prompts. They are loaded only when the project is trusted and configuration enables project scope.
|
|
325
506
|
- `inheritExtensions` is disabled by default because loading an extension in a child executes its code and may duplicate external side effects.
|
|
326
507
|
- Explicit agent tool lists are enforced as registry ceilings, but this controls model visibility and execution composition rather than providing an OS sandbox.
|
|
327
|
-
- A child may send content only to its recorded direct parent through `report`;
|
|
508
|
+
- A child may send content only to its recorded direct parent through `report`;
|
|
509
|
+
path resolution is only an address lookup, and `send_message` /
|
|
510
|
+
`followup_task` still require direct-parent identity.
|
|
328
511
|
|
|
329
512
|
## Current limitations
|
|
330
513
|
|
|
331
|
-
- Activations
|
|
332
|
-
|
|
333
|
-
-
|
|
514
|
+
- Activations, scheduling ownership, and mailbox serialization are process-local;
|
|
515
|
+
two Pi processes must not concurrently control the same child session.
|
|
516
|
+
- Readable-path reservation and idle-LRU accounting are process-local. Durable
|
|
517
|
+
UUID identity remains authoritative when multiple processes are involved,
|
|
518
|
+
which is still unsupported.
|
|
519
|
+
- Resident parents still retain `ownedChildren` until descendants settle;
|
|
520
|
+
actor-graph residency, orphan handling, and background GC are not implemented.
|
|
521
|
+
- Pi lazily creates a new child JSONL file on its first assistant entry. The
|
|
522
|
+
initial background agent id therefore has a crash window after prompt
|
|
523
|
+
acceptance; mailbox-v2 `send_message` waits for that first durable checkpoint
|
|
524
|
+
before acknowledging an enqueue.
|
|
525
|
+
- Legacy `send_message` still has Pi's prompt-acceptance crash window. Use
|
|
526
|
+
`mailbox-v2` when delivery must be persisted before an explicit turn start.
|
|
334
527
|
- `interrupt_agent` is fire-and-return and relies on Pi's current `AgentSession.abort()` queue behavior.
|
|
335
|
-
- The fork provider is intentionally one-shot.
|
|
336
528
|
- Structured-output delegation is not implemented yet.
|
|
337
529
|
- Continuable starts require a persisted parent session; ephemeral (`--no-session`) parents can use foreground one-shot delegation only.
|
|
338
530
|
- `subagent_fork` needs a persisted parent to copy completed history; before the first completed turn its safe prefix is empty and it behaves like a fresh child.
|
|
@@ -352,6 +544,5 @@ The test suite includes provider-boundary, descriptor, configuration, discovery,
|
|
|
352
544
|
MIT © 2026 oai404iao. See [LICENSE](LICENSE) and
|
|
353
545
|
[THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).
|
|
354
546
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
writing user files.
|
|
547
|
+
Bundled presets are initialization templates only. Runtime agent discovery is
|
|
548
|
+
limited to user and trusted project configuration.
|
package/agents/worker.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: worker
|
|
3
3
|
description: General-purpose implementation agent with coding tools
|
|
4
|
-
tools: read, grep, find, ls, bash, $mutation, subagent, subagent_fork, send_message, interrupt_agent, list_agents
|
|
4
|
+
tools: read, grep, find, ls, bash, $mutation, subagent, subagent_fork, send_message, followup_task, wait_agent, interrupt_agent, list_agents
|
|
5
5
|
thinking: high
|
|
6
6
|
---
|
|
7
7
|
|
package/config.example.json
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./config.schema.json",
|
|
3
3
|
"agentScope": "user",
|
|
4
|
-
"syncBundledAgents": false,
|
|
5
4
|
"maxDepth": 3,
|
|
6
5
|
"enableRunInBackground": true,
|
|
7
6
|
"defaultBackground": true,
|
|
7
|
+
"maxConcurrentBackgroundRuns": 4,
|
|
8
|
+
"maxIdleRuntimes": 0,
|
|
9
|
+
"backgroundProtocol": "legacy",
|
|
8
10
|
"reportDelivery": "wakeup",
|
|
9
11
|
"inheritExtensions": false,
|
|
12
|
+
"openAIIdentity": false,
|
|
10
13
|
"maxOutputBytes": 51200
|
|
11
14
|
}
|
package/config.schema.json
CHANGED
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
},
|
|
20
20
|
"syncBundledAgents": {
|
|
21
21
|
"type": "boolean",
|
|
22
|
-
"
|
|
23
|
-
"
|
|
22
|
+
"deprecated": true,
|
|
23
|
+
"description": "Retired user-level compatibility key from versions 0.2 and 0.3. It is validated but ignored; template initialization is automatic and bundled definitions are never used at runtime."
|
|
24
24
|
},
|
|
25
25
|
"maxDepth": {
|
|
26
26
|
"type": "integer",
|
|
@@ -36,13 +36,33 @@
|
|
|
36
36
|
},
|
|
37
37
|
"defaultBackground": {
|
|
38
38
|
"type": "boolean",
|
|
39
|
-
"description": "Default run mode for
|
|
39
|
+
"description": "Default run mode for subagent calls when background execution is enabled. subagent_fork remains foreground unless explicitly requested.",
|
|
40
40
|
"default": true
|
|
41
41
|
},
|
|
42
|
+
"maxConcurrentBackgroundRuns": {
|
|
43
|
+
"type": "integer",
|
|
44
|
+
"minimum": 1,
|
|
45
|
+
"maximum": 9007199254740991,
|
|
46
|
+
"description": "Maximum number of continuable subagent turns that may execute concurrently within one extension runtime.",
|
|
47
|
+
"default": 4
|
|
48
|
+
},
|
|
49
|
+
"maxIdleRuntimes": {
|
|
50
|
+
"type": "integer",
|
|
51
|
+
"minimum": 0,
|
|
52
|
+
"maximum": 9007199254740991,
|
|
53
|
+
"description": "Maximum settled continuable child runtimes retained in the process-wide idle LRU. Zero unloads immediately.",
|
|
54
|
+
"default": 0
|
|
55
|
+
},
|
|
56
|
+
"backgroundProtocol": {
|
|
57
|
+
"type": "string",
|
|
58
|
+
"enum": ["legacy", "mailbox-v2"],
|
|
59
|
+
"description": "Background message protocol. legacy starts or follows a turn from send_message; mailbox-v2 durably enqueues until followup_task explicitly starts one turn.",
|
|
60
|
+
"default": "legacy"
|
|
61
|
+
},
|
|
42
62
|
"reportDelivery": {
|
|
43
63
|
"type": "string",
|
|
44
64
|
"enum": ["wakeup", "quiet"],
|
|
45
|
-
"description": "Whether child reports trigger a parent turn or wait for the parent's next turn.",
|
|
65
|
+
"description": "Whether explicit child reports trigger a parent turn or wait for the parent's next turn. mailbox-v2 completion updates are always quiet.",
|
|
46
66
|
"default": "wakeup"
|
|
47
67
|
},
|
|
48
68
|
"inheritExtensions": {
|
|
@@ -50,6 +70,11 @@
|
|
|
50
70
|
"description": "Load the parent's other Pi extensions in child runtimes. pi-subagent itself is filtered out and explicit agent tool ceilings still apply.",
|
|
51
71
|
"default": false
|
|
52
72
|
},
|
|
73
|
+
"openAIIdentity": {
|
|
74
|
+
"type": "boolean",
|
|
75
|
+
"description": "Inject the pi-codex-minimal-tools identity lifecycle as a named inline extension for OpenAI Responses child models.",
|
|
76
|
+
"default": false
|
|
77
|
+
},
|
|
53
78
|
"maxOutputBytes": {
|
|
54
79
|
"type": "integer",
|
|
55
80
|
"minimum": 1024,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oai404iao/pi-subagent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0-alpha.0",
|
|
4
4
|
"description": "Durable, continuable subagents for Pi with spawn/fork providers and lifecycle controls.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -37,11 +37,14 @@
|
|
|
37
37
|
"@earendil-works/pi-tui": ">=0.84.2",
|
|
38
38
|
"typebox": "*"
|
|
39
39
|
},
|
|
40
|
+
"optionalDependencies": {
|
|
41
|
+
"@oai404iao/pi-codex-minimal-tools": "1.4.1-alpha.0"
|
|
42
|
+
},
|
|
40
43
|
"devDependencies": {
|
|
41
|
-
"@earendil-works/pi-agent-core": "
|
|
42
|
-
"@earendil-works/pi-ai": "
|
|
43
|
-
"@earendil-works/pi-coding-agent": "
|
|
44
|
-
"@earendil-works/pi-tui": "
|
|
44
|
+
"@earendil-works/pi-agent-core": "0.85.1",
|
|
45
|
+
"@earendil-works/pi-ai": "0.85.1",
|
|
46
|
+
"@earendil-works/pi-coding-agent": "0.85.1",
|
|
47
|
+
"@earendil-works/pi-tui": "0.85.1",
|
|
45
48
|
"@types/node": "^26.2.0",
|
|
46
49
|
"tsx": "^4.20.6",
|
|
47
50
|
"typebox": "^1.1.24",
|
|
@@ -84,5 +87,5 @@
|
|
|
84
87
|
"optional": true
|
|
85
88
|
}
|
|
86
89
|
},
|
|
87
|
-
"gitHead": "
|
|
90
|
+
"gitHead": "53026bf9e3f6a1d16a9c990e6034b49041928eab"
|
|
88
91
|
}
|