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