@pi-ohm/subagents 0.6.4-dev.25351601005.1.815a0e8 → 0.6.4-dev.25620170147.1.0b6891f

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/README.md +0 -562
  2. package/dist/agent-controller.d.ts +59 -0
  3. package/dist/agent-controller.js +330 -0
  4. package/dist/config.d.ts +69 -0
  5. package/dist/config.js +336 -0
  6. package/dist/extension.d.ts +5 -26
  7. package/dist/extension.js +5 -202
  8. package/dist/schema.d.ts +40 -0
  9. package/dist/schema.js +128 -0
  10. package/package.json +16 -14
  11. package/dist/catalog.d.ts +0 -32
  12. package/dist/catalog.js +0 -102
  13. package/dist/errors.d.ts +0 -74
  14. package/dist/errors.js +0 -62
  15. package/dist/policy.js +0 -73
  16. package/dist/runtime/backend/index.js +0 -15
  17. package/dist/runtime/backend/model-scope.js +0 -199
  18. package/dist/runtime/backend/model-selection.js +0 -79
  19. package/dist/runtime/backend/pi-cli-backend.js +0 -301
  20. package/dist/runtime/backend/pi-sdk-backend.js +0 -212
  21. package/dist/runtime/backend/prompt-profile-rules.js +0 -196
  22. package/dist/runtime/backend/prompts.js +0 -122
  23. package/dist/runtime/backend/runners.js +0 -402
  24. package/dist/runtime/backend/scaffold-backend.js +0 -63
  25. package/dist/runtime/backend/sdk-stream-capture.js +0 -79
  26. package/dist/runtime/backend/subagent-prompts.js +0 -100
  27. package/dist/runtime/backend/system-prompt-authoring.js +0 -32
  28. package/dist/runtime/backend/system-prompt-packs.js +0 -62
  29. package/dist/runtime/backend/system-prompts.js +0 -338
  30. package/dist/runtime/events.d.ts +0 -39
  31. package/dist/runtime/events.js +0 -130
  32. package/dist/runtime/live-ui.d.ts +0 -41
  33. package/dist/runtime/live-ui.js +0 -193
  34. package/dist/runtime/subagent-profiles.js +0 -93
  35. package/dist/runtime/task-transcript.js +0 -255
  36. package/dist/runtime/tasks/persistence.js +0 -362
  37. package/dist/runtime/tasks/store.js +0 -643
  38. package/dist/runtime/tasks/types.d.ts +0 -123
  39. package/dist/runtime/tasks/types.js +0 -5
  40. package/dist/runtime/ui.d.ts +0 -37
  41. package/dist/runtime/ui.js +0 -151
  42. package/dist/schema/shared.js +0 -38
  43. package/dist/schema/task-record.d.ts +0 -42
  44. package/dist/schema/task-record.js +0 -65
  45. package/dist/schema/task-tool.js +0 -199
  46. package/dist/tools/primary.js +0 -297
  47. package/dist/tools/task/defaults.js +0 -84
  48. package/dist/tools/task/execution/batch.js +0 -288
  49. package/dist/tools/task/execution/cancel.js +0 -52
  50. package/dist/tools/task/execution/kernel.js +0 -30
  51. package/dist/tools/task/execution/lifecycle.js +0 -419
  52. package/dist/tools/task/execution/projection.js +0 -118
  53. package/dist/tools/task/execution/send.js +0 -227
  54. package/dist/tools/task/execution/shared.js +0 -246
  55. package/dist/tools/task/execution/start.js +0 -96
  56. package/dist/tools/task/execution/status.js +0 -27
  57. package/dist/tools/task/execution/wait.js +0 -155
  58. package/dist/tools/task/operations.js +0 -186
  59. package/dist/tools/task/render.js +0 -508
  60. package/dist/tools/task/transport.js +0 -183
  61. package/dist/tools/task/updates.js +0 -221
  62. package/src/runtime/backend/prompts/finder.claude.txt +0 -34
  63. package/src/runtime/backend/prompts/finder.gemini.txt +0 -34
  64. package/src/runtime/backend/prompts/finder.general.txt +0 -34
  65. package/src/runtime/backend/prompts/finder.gpt.txt +0 -34
  66. package/src/runtime/backend/prompts/librarian.claude.txt +0 -54
  67. package/src/runtime/backend/prompts/librarian.gemini.txt +0 -54
  68. package/src/runtime/backend/prompts/librarian.general.txt +0 -55
  69. package/src/runtime/backend/prompts/librarian.gpt.txt +0 -53
  70. package/src/runtime/backend/prompts/oracle.claude.txt +0 -51
  71. package/src/runtime/backend/prompts/oracle.gemini.txt +0 -50
  72. package/src/runtime/backend/prompts/oracle.general.txt +0 -50
  73. package/src/runtime/backend/prompts/oracle.gpt.txt +0 -50
package/README.md CHANGED
@@ -1,562 +0,0 @@
1
- # @pi-ohm/subagents
2
-
3
- Install only subagent support for Pi (task-routed + primary-tool profiles).
4
-
5
- ```bash
6
- pi install npm:@pi-ohm/subagents
7
- ```
8
-
9
- Scaffolded subagents:
10
-
11
- - `librarian` — multi-repo code understanding (default: primary-tool profile)
12
- - `oracle` — reasoning-heavy advisor/reviewer
13
- - `finder` — intelligent behavior-based search
14
- - `task` — isolated parallel execution worker
15
- - `painter` — explicit-request image generation/editing helper
16
-
17
- Profiles can be marked with `primary: true` in config/catalog to indicate direct
18
- invocation as a top-level tool entrypoint instead of task-tool-only invocation.
19
-
20
- Primary profiles are registered as direct tools automatically. Tool names are derived
21
- from profile IDs with deterministic collision handling.
22
-
23
- `primary: true` is additive:
24
-
25
- - profile gets a direct top-level tool
26
- - profile stays available in `task` subagent roster (`subagent_type`)
27
- - direct-tool execution and task-routed execution share the same runtime/result envelope
28
-
29
- The orchestration tool name is **`task`**. Async orchestration lifecycle
30
- operations (`start/status/wait/send/cancel`) are exposed through this tool.
31
- Subagent starts are synchronous/blocking. `async:true` start requests are rejected.
32
-
33
- ## Task tool (current)
34
-
35
- Current behavior:
36
-
37
- - supports `op: "start"` for a single task payload (sync)
38
- - supports batched `op: "start"` payloads via `tasks[]` with optional `parallel:true`
39
- - supports lifecycle operations: `status`, `wait`, `send`, `cancel`
40
- - input normalization: `status`/`wait` accept `id` or `ids`; `op:"result"` is normalized to `status`
41
- - non-debug result text renders Amp-style inline message trees (prompt -> tool calls -> result)
42
- - running updates stream inline tool rows in-place from SDK events
43
- - returns `task_id`, status, and deterministic task details
44
- - includes explicit wait/cancel ergonomics fields:
45
- - `wait_status` (`completed|timeout|aborted`)
46
- - `done` (boolean completion flag for `wait`)
47
- - `cancel_applied`
48
- - `prior_status`
49
- - includes batch acceptance accounting for `start` with `tasks[]`:
50
- - `total_count`
51
- - `accepted_count`
52
- - `rejected_count`
53
- - `batch_status` (`accepted|partial|completed|rejected`)
54
- - includes structured output metadata in details/items:
55
- - `output_available`
56
- - `output_total_chars`
57
- - `output_returned_chars`
58
- - includes structured SDK-derived tool transcript rows in details/items when available:
59
- - `tool_rows` (deterministic per-tool lifecycle rows)
60
- - `event_count` (captured structured event count)
61
- - `assistant_text` (event-derived assistant transcript tail)
62
- - includes machine marker on every tool details payload:
63
- - `contract_version: "task.v1"`
64
- - includes observability fields on details/items:
65
- - `provider`
66
- - `model`
67
- - `runtime`
68
- - `route`
69
- - collection lifecycle ops (`status`/`wait`) aggregate observability from task items
70
- (so top-level `runtime`/`route` align with per-item metadata when present)
71
- - persists task registry snapshots to disk for resume/reload behavior
72
- - enforces terminal-task retention expiry with explicit `task_expired` lookup errors
73
- - validates all payloads with TypeBox boundary schema + typed Result errors
74
-
75
- ## Subagent backend behavior
76
-
77
- Runtime backend is selected from `subagentBackend` config:
78
-
79
- - `interactive-sdk` (default): executes subagent prompts through in-process Pi SDK
80
- sessions with in-memory session/settings managers
81
- - `interactive-shell` (fallback): executes a real nested `pi` run for subagent prompts
82
- using built-in tools (`read,bash,edit,write,grep,find,ls`)
83
- - `none`: uses deterministic scaffold backend (echo-style debug output)
84
- - `custom-plugin`: currently returns `unsupported_subagent_backend`
85
-
86
- Per-subagent model override is supported via `ohm.json`:
87
-
88
- ```jsonc
89
- {
90
- "subagents": {
91
- "finder": { "model": "openai/gpt-4o" },
92
- "oracle": { "model": "anthropic/claude-sonnet-4-5" },
93
- "librarian": { "model": "openai/gpt-5:high" },
94
- },
95
- }
96
- ```
97
-
98
- - format is required: `<provider>/<model>`
99
- - optional thinking suffix: `<provider>/<model>:<thinking>`
100
- - valid thinking values: `off|minimal|low|medium|high|xhigh`
101
- - provider is normalized to lowercase
102
- - SDK backend validates against Pi model registry (built-ins + custom `models.json`)
103
- - interactive-shell backend forwards the same `--model` pattern to nested `pi`
104
-
105
- Subagent runtime profiles now support prompt/description/usage overrides, custom
106
- subagent entries, and wildcard variants:
107
-
108
- ```jsonc
109
- {
110
- "subagents": {
111
- "librarian": {
112
- "model": "openai/gpt-5.3-codex:medium",
113
- "prompt": "{file:./prompts/librarian.general.txt}",
114
- "description": "Optional summary override",
115
- "whenToUse": ["Optional guidance override"],
116
- },
117
- "my-custom-agent": {
118
- "model": "openai/gpt-5.3-codex:medium",
119
- "prompt": "{file:./prompts/my-custom-agent.general.txt}",
120
- "description": "Custom delegated helper",
121
- "whenToUse": ["Use for custom workflows"],
122
- "permissions": {
123
- "bash": "allow",
124
- "edit": "deny",
125
- },
126
- "variants": {
127
- "*gemini*": {
128
- "model": "github-copilot/gemini-3.1-pro-preview:high",
129
- "prompt": "{file:./prompts/my-custom-agent.gemini.txt}",
130
- "permissions": {
131
- "edit": "inherit",
132
- "apply_patch": "deny",
133
- },
134
- },
135
- },
136
- },
137
- },
138
- }
139
- ```
140
-
141
- Variant matching rules:
142
-
143
- - variant keys are wildcard matchers (for example `*gemini*`)
144
- - match target is normalized model pattern + model token (provider is optional)
145
- - first matching variant wins
146
- - variant fields override base profile fields (`model`, `prompt`, `description`, `whenToUse`)
147
- - permissions support `allow|deny|inherit` (inherit falls back to base profile map)
148
-
149
- Prompt file references:
150
-
151
- - prompt fields support `{file:...}` references
152
- - relative paths resolve from task `cwd` first, then Pi config dir fallback
153
-
154
- Built-in prompt management:
155
-
156
- - catalog metadata (`packages/subagents/src/catalog.ts`) is now display/orchestration metadata for
157
- main-agent exposure (name/description/when-to-use/invocation)
158
- - execution prompt text is resolved separately
159
- - built-in execution prompts are file-backed under `packages/subagents/src/runtime/backend/prompts/*`
160
- - built-in variant selection uses wildcard model keys (`*gemini*`, `*gpt*`, `*claude*`)
161
-
162
- ## Dynamic prompt profile routing
163
-
164
- SDK prompt profile selection is runtime-driven and deterministic:
165
-
166
- 1. active runtime model (`provider/modelId`) when available
167
- 2. explicit subagent model override (`ohm.json` `subagents.<id>.model`)
168
- 3. scoped model catalog inferred from Pi `settings.json` `enabledModels`
169
- 4. generic fallback
170
-
171
- Scoped model discovery (`enabledModels`) uses deterministic config precedence:
172
-
173
- 1. `<cwd>/.pi/agent/settings.json`
174
- 2. `${PI_CONFIG_DIR}/settings.json`
175
- 3. `${PI_CODING_AGENT_DIR}/settings.json`
176
- 4. `${PI_AGENT_DIR}/settings.json`
177
- 5. resolved Pi agent dir (`@pi-ohm/config`)
178
- 6. `~/.pi/agent/settings.json`
179
-
180
- Provider/profile routing rules are config-driven from `ohm.providers.json`:
181
-
182
- ```jsonc
183
- {
184
- "subagents": {
185
- "promptProfiles": {
186
- "rules": [
187
- {
188
- "profile": "google",
189
- "priority": 900,
190
- "match": {
191
- "providers": ["acme-neon"],
192
- "models": [],
193
- },
194
- },
195
- ],
196
- },
197
- },
198
- }
199
- ```
200
-
201
- Allowed `profile` values: `anthropic | openai | google | moonshot`.
202
- Invalid/missing rules fail-soft to built-in defaults.
203
-
204
- Prompt-profile observability fields are emitted on task details/items:
205
-
206
- - `prompt_profile`
207
- - `prompt_profile_source`
208
- - `prompt_profile_reason`
209
-
210
- Trace lines are hidden by default. Enable debug rendering with:
211
-
212
- - `OHM_DEBUG=true`
213
-
214
- When `OHM_DEBUG=true`, running stream updates now include current routing metadata
215
- (`provider`, `model`, `runtime`, `route`, `prompt_profile*`) as soon as backend
216
- preflight resolves them.
217
- For batch payloads with mixed routing, debug text also prints per-item observability
218
- rows instead of only `mixed`.
219
-
220
- Optional safety fallback:
221
-
222
- - set `OHM_SUBAGENTS_SDK_FALLBACK_TO_CLI=true` to fallback from `interactive-sdk` to
223
- `interactive-shell` when SDK bootstrap/execution fails (`task_backend_execution_failed`)
224
-
225
- If output appears like prompt regurgitation, verify `subagentBackend` is not set to `none`.
226
-
227
- Nested interactive-shell outputs are sanitized to strip runtime metadata lines (`backend:`,
228
- `provider:`, `model:`) before surfacing task output.
229
-
230
- For unknown tasks/expired tasks, error categorization is explicit: `error_category: "not_found"`.
231
-
232
- ## Operator cookbook
233
-
234
- ### 1) Execution mode policy
235
-
236
- | scenario | recommended mode | why |
237
- | -------------------------------------------- | ----------------------------- | ------------------------------------------------------- |
238
- | quick lookup, single task, result needed now | `start` (sync blocking) | simplest UX; one call, one terminal result |
239
- | fan-out independent tasks | `start tasks[] parallel:true` | deterministic ordered aggregation + bounded concurrency |
240
- | follow-up on an existing active task | `send` | preserves task history + follow-up prompts |
241
-
242
- `async:true` start requests are rejected (`task_async_disabled`).
243
-
244
- ### 2) Backend tradeoff matrix
245
-
246
- | backend | strengths | tradeoffs | when to pick |
247
- | ------------------------------ | ---------------------------------------------------------------------------- | ------------------------------------------------ | ------------------------------ |
248
- | `interactive-sdk` (default) | structured tool/assistant events, event-derived rows, better inline fidelity | newer path | default |
249
- | `interactive-shell` (fallback) | mature nested CLI behavior; straightforward rollback | text-capture based transcript fidelity | explicit rollback / fallback |
250
- | `none` | deterministic scaffold output | no real execution | testing/demo/debug wiring only |
251
- | `custom-plugin` | reserved hook | not implemented (`unsupported_subagent_backend`) | none currently |
252
-
253
- Fallback policy:
254
-
255
- - enable `OHM_SUBAGENTS_SDK_FALLBACK_TO_CLI=true` to downgrade only recoverable SDK bootstrap failures (`task_backend_execution_failed`) from SDK -> CLI path.
256
-
257
- ### 3) Recommended smoke matrix
258
-
259
- ```bash
260
- # default backend visibility
261
- printf '/ohm-subagents\n' | pi -e ./packages/subagents/extension.ts
262
-
263
- # explicit sdk backend visibility
264
- mkdir -p /tmp/pi-ohm-sdk-smoke
265
- cat >/tmp/pi-ohm-sdk-smoke/ohm.json <<'EOF'
266
- { "subagentBackend": "interactive-sdk" }
267
- EOF
268
- printf '/ohm-subagents\n' | PI_CONFIG_DIR=/tmp/pi-ohm-sdk-smoke pi -e ./packages/subagents/extension.ts
269
- ```
270
-
271
- Task lifecycle smoke checklist:
272
-
273
- 1. sync single `start`
274
- 2. async guard (`start async:true` returns `task_async_disabled`)
275
- 3. batch partial acceptance (`tasks[]` mixed validity)
276
- 4. timeout path (`wait timeout_ms`)
277
- 5. follow-up `send` on running task
278
-
279
- ### 3.1) Prompt-profile demos (H1/H6/H7 closure runbook)
280
-
281
- H1-006 scoped model discovery demo (non-default provider, no hardcoded list):
282
-
283
- ```bash
284
- yarn test:subagents --test-name-pattern "scoped model loader discovers non-default providers"
285
- ```
286
-
287
- H6-006 interactive runtime demo (active model drives profile in-session):
288
-
289
- ```bash
290
- mkdir -p /tmp/pi-ohm-active-model-demo
291
- cat >/tmp/pi-ohm-active-model-demo/ohm.json <<'EOF'
292
- {
293
- "subagentBackend": "interactive-sdk",
294
- "subagents": {
295
- "finder": { "model": "openai/gpt-5" }
296
- }
297
- }
298
- EOF
299
-
300
- OHM_DEBUG=true \
301
- PI_CONFIG_DIR=/tmp/pi-ohm-active-model-demo \
302
- pi -e ./packages/subagents/extension.ts
303
- ```
304
-
305
- In-session, run a finder task via `task op:start ...`. In verbose result text, verify:
306
-
307
- - `prompt_profile: openai`
308
- - `prompt_profile_source: active_model`
309
-
310
- Then change only active model (for example `finder` override to `google/gemini-3-pro-preview`),
311
- rerun, and verify profile/source update without code changes.
312
-
313
- H7-004 provider-add repro demo (config-only mapping + end-to-end validation):
314
-
315
- ```bash
316
- yarn test:subagents --test-name-pattern "new provider mapping can be added via rules"
317
- ```
318
-
319
- System prompt harness snapshots:
320
-
321
- ```bash
322
- # verify full main-agent + subagent-sdk prompt/tool snapshots
323
- yarn test:subagents:golden
324
-
325
- # regenerate snapshot goldens from current code
326
- yarn test:subagents:golden:update
327
- ```
328
-
329
- ### 3.2) Provider onboarding playbook (no core router edits)
330
-
331
- 1. Add a rule in `ohm.providers.json` under `subagents.promptProfiles.rules`:
332
- - map provider/model tokens to one existing profile pack
333
- - set explicit `priority` above overlapping rules
334
- 2. Validate via tests:
335
- - `yarn test:subagents --test-name-pattern "prompt profile mapping changes after config edit"`
336
- - `yarn test:subagents --test-name-pattern "new provider mapping can be added via rules"`
337
- 3. Validate runtime diagnostics:
338
- - run with `OHM_DEBUG=true`
339
- - confirm `prompt_profile/source/reason` in task result details
340
- 4. Only add code-level prompt pack modules when a genuinely new behavior family is needed.
341
-
342
- ### 4) Troubleshooting quick map
343
-
344
- | symptom | likely cause | check/fix |
345
- | --------------------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------ |
346
- | output looks scaffolded/echoed | backend is `none` | set `subagentBackend` to `interactive-shell` or `interactive-sdk` |
347
- | sdk selected but execution drops to cli | fallback env enabled and sdk hit recoverable bootstrap failure | inspect `OHM_SUBAGENTS_SDK_FALLBACK_TO_CLI`; disable to keep hard sdk failures |
348
- | `task_backend_timeout` (often oracle) | backend timeout budget exceeded for reasoning-heavy run | narrow prompt/files or raise `OHM_SUBAGENTS_BACKEND_TIMEOUT_MS_ORACLE` |
349
- | `task_wait_timeout` | task still non-terminal at timeout | increase `timeout_ms`, poll with `status`, or reduce batch size |
350
- | `task_wait_aborted` | caller signal cancelled wait | retry wait with active signal |
351
- | `task_expired` on old IDs | retention/capacity eviction | increase retention/cap env knobs; treat task IDs as ephemeral |
352
- | too many inline progress updates | high-frequency non-terminal emissions | increase `OHM_SUBAGENTS_ONUPDATE_THROTTLE_MS` |
353
- | brief UI stall when many tasks finish | sync persistence flush churn + heavy final update diffs | raise `OHM_SUBAGENTS_TASK_PERSIST_DEBOUNCE_MS`; reduce batch size per call |
354
-
355
- ### 5) Guardrail env knobs
356
-
357
- - `OHM_SUBAGENTS_TASK_RETENTION_MS` — terminal task retention window
358
- - `OHM_SUBAGENTS_TASK_MAX_EVENTS` — per-task structured event cap
359
- - `OHM_SUBAGENTS_TASK_MAX_ENTRIES` — in-memory task registry cap
360
- - `OHM_SUBAGENTS_TASK_MAX_EXPIRED_ENTRIES` — expired-task reason cache cap
361
- - `OHM_SUBAGENTS_TASK_PERSIST_DEBOUNCE_MS` — debounce non-terminal persistence flushes (default `90`, `0` disables)
362
- - `OHM_SUBAGENTS_BACKEND_TIMEOUT_MS` — global backend timeout budget in ms (default `180000`)
363
- - `OHM_SUBAGENTS_BACKEND_TIMEOUT_MS_<SUBAGENT_ID>` — per-subagent timeout override in ms (e.g. `..._ORACLE`)
364
- - `OHM_SUBAGENTS_ONUPDATE_THROTTLE_MS` — non-terminal onUpdate emission throttle
365
-
366
- Notes:
367
-
368
- - oracle defaults to a 1h backend timeout budget (`3600000ms`) for reasoning-heavy runs
369
- - librarian also defaults to a larger backend timeout budget than generic subagents
370
- - timeout errors now include remediation hints and the effective model when available
371
- - if sdk backend downgrades to interactive-shell fallback, compact output now includes an explicit route-fallback note
372
-
373
- ### Output policy
374
-
375
- Task output returned in tool payloads is always full (no runtime output cap).
376
-
377
- - `output_total_chars` reports total output size
378
- - `output_returned_chars` matches `output_total_chars`
379
- - `output_truncated` is always `false`
380
-
381
- Example payload:
382
-
383
- ```jsonc
384
- {
385
- "op": "start",
386
- "subagent_type": "finder",
387
- "description": "Auth flow scan",
388
- "prompt": "Trace token validation + refresh paths",
389
- }
390
- ```
391
-
392
- Batch execution notes:
393
-
394
- - aggregate item order is deterministic (input order)
395
- - bounded parallelism is enforced by `subagents.taskMaxConcurrency` (default `3`)
396
- - task failures are isolated; one failed batch item does not abort siblings
397
-
398
- ## Task permission policy
399
-
400
- Task orchestration enforces policy decisions from runtime config:
401
-
402
- - `allow` — task execution proceeds
403
- - `deny` — execution is blocked with `task_permission_denied`
404
-
405
- Config shape:
406
-
407
- ```jsonc
408
- {
409
- "subagents": {
410
- "permissions": {
411
- "default": "allow",
412
- "subagents": {
413
- "finder": "deny",
414
- },
415
- "allowInternalRouting": false,
416
- },
417
- },
418
- }
419
- ```
420
-
421
- Additional hardening behaviors:
422
-
423
- - internal profiles (`internal:true`) are hidden from task roster exposure unless
424
- `allowInternalRouting` is enabled
425
- - wait timeout/abort are explicit (`task_wait_timeout`, `task_wait_aborted`)
426
- - tool error payloads include stable `error_category`
427
-
428
- Persistence details:
429
-
430
- - default snapshot path: `${XDG_DATA_HOME:-~/.local/share}/pi-ohm/agent/ohm.subagents.tasks.json`
431
- - override snapshot path: `OHM_SUBAGENTS_TASK_PERSIST_PATH=/abs/path/ohm.subagents.tasks.json`
432
- - retention window is configurable via `OHM_SUBAGENTS_TASK_RETENTION_MS` (positive integer ms)
433
- - per-task structured event timeline cap is configurable via `OHM_SUBAGENTS_TASK_MAX_EVENTS`
434
- (default `120`)
435
- - in-memory task registry capacity is configurable via `OHM_SUBAGENTS_TASK_MAX_ENTRIES`
436
- (default `200`); oldest terminal tasks are evicted first once cap is exceeded
437
- - expired-task reason cache is configurable via `OHM_SUBAGENTS_TASK_MAX_EXPIRED_ENTRIES`
438
- (default `500`)
439
- - corrupt snapshot files are auto-recovered to `*.corrupt-<epoch>` and runtime falls back to empty state
440
- - inline `onUpdate` emission is throttled via `OHM_SUBAGENTS_ONUPDATE_THROTTLE_MS`
441
- (default `120ms`) with duplicate-frame suppression to avoid async wait/update spam
442
-
443
- ## Migration notes
444
-
445
- Behavior has moved from scaffold-only single start calls to a lifecycle runtime,
446
- with real backend execution as the default:
447
-
448
- - orchestration now supports `start/status/wait/send/cancel`
449
- - batched `start` supports deterministic ordering and bounded concurrency
450
- - primary tools and task-routed calls share one execution/runtime contract
451
- - policy-denied calls now fail deterministically instead of silently proceeding
452
-
453
- Existing slash commands remain unchanged:
454
-
455
- - `/ohm-subagents`
456
- - `/ohm-subagent <id>`
457
-
458
- ### Prompt-routing migration (static/env matcher -> dynamic/config-driven)
459
-
460
- - provider/profile routing now comes from runtime model truth + config files
461
- (`settings.json` + `ohm.providers.json`)
462
- - static hardcoded/env-driven matcher assumptions should be removed from local forks
463
- - keep provider additions in config first (`subagents.promptProfiles.rules`) before touching code
464
- - debug with `OHM_DEBUG=true`
465
-
466
- ## Invocation mode behavior
467
-
468
- `task-routed` and `primary-tool` invocation paths share one runtime/result envelope.
469
-
470
- Current shared fields:
471
-
472
- - `contract_version`
473
- - `status`
474
- - `subagent_type`
475
- - `description`
476
- - `backend`
477
- - `provider`
478
- - `model`
479
- - `runtime`
480
- - `route`
481
- - `output_available`
482
- - `output` (subject to truncation policy)
483
-
484
- Invocation mode differences are intentional and explicit via `invocation`:
485
-
486
- - `task-routed` for non-primary profiles
487
- - `primary-tool` for direct primary profile calls
488
-
489
- ## Live TUI feedback
490
-
491
- `@pi-ohm/subagents` uses shared component `@pi-ohm/tui` (`SubagentTaskTreeComponent`) for task runtime visuals.
492
- Live bottom widget mode now defaults to `off`; inline tool-result updates are the primary UX.
493
-
494
- Baseline running-task display includes:
495
-
496
- - spinner
497
- - prompt line from task start payload (main-agent instruction)
498
- - best-effort parsed tool-call rows
499
- - terminal/final result row
500
-
501
- Runtime UI surfaces are synchronized from one task snapshot model:
502
-
503
- - footer status (`setStatus`) with running/active counters
504
- - widget task tree (`setWidget`) using Amp-style tree component
505
- - headless fallback `onUpdate` text with equivalent description/tool-count/elapsed info
506
-
507
- Example running block:
508
-
509
- ```bash
510
- ⠋ Finder · Auth flow scan
511
- ├── Trace auth validation
512
- ├── ✓ Read packages/subagents/src
513
- ├── ✓ Grep auth|token in packages/subagents/src
514
- ╰── Working...
515
- ```
516
-
517
- Terminal examples:
518
-
519
- ```bash
520
- ✓ Finder · Auth flow scan
521
- ├── Trace auth validation
522
- ├── ✓ Read packages/subagents/src
523
- ╰── Auth validation path uses task permission policy + runtime store transitions.
524
-
525
- ✕ Finder · Auth flow scan
526
- ├── Trace auth validation
527
- ╰── Task failed: backend timeout while reading repository files.
528
- ```
529
-
530
- ## Error handling
531
-
532
- `@pi-ohm/subagents` uses `better-result` for recoverable errors:
533
-
534
- - runtime and orchestration paths should return `Result<T, E>`
535
- - typed error categories should use `TaggedError`
536
- - avoid broad try/catch error propagation for recoverable failures
537
-
538
- Commands:
539
-
540
- - `/ohm-subagents`
541
- - `/ohm-subagent <id>`
542
-
543
- ## Primary tool input schemas
544
-
545
- For profiles marked `primary:true`, direct tool input schema is subagent-specific:
546
-
547
- - `librarian`
548
- - required: `query`
549
- - optional: `context`, `description`
550
- - `oracle`
551
- - required: `task`
552
- - optional: `context`, `files[]`, `description`
553
- - `finder`
554
- - required: `query`
555
- - optional: `description`
556
-
557
- Normalization behavior:
558
-
559
- - `context` is forwarded in a dedicated prompt section (`Context:`)
560
- - oracle `files[]` is forwarded in a dedicated prompt block (`Files:` + bullet paths)
561
- - `async:true` inputs are rejected by task lifecycle policy (`task_async_disabled`)
562
- - task lifecycle/result payload remains the same shape after primary normalization
@@ -0,0 +1,59 @@
1
+ import { AgentToolResult, ExtensionAPI, ToolDefinition } from "@earendil-works/pi-coding-agent";
2
+ import { Static, Type } from "@earendil-works/pi-ai";
3
+
4
+ //#region src/agent-controller.d.ts
5
+ declare const SpawnAgentArgsSchema: Type.TObject<{
6
+ task_name: Type.TString;
7
+ prompt: Type.TString;
8
+ summary: Type.TString;
9
+ agent_type: Type.TOptional<Type.TString>;
10
+ model: Type.TOptional<Type.TString>;
11
+ thinking: Type.TOptional<Type.TUnion<[Type.TLiteral<"off">, Type.TLiteral<"minimal">, Type.TLiteral<"low">, Type.TLiteral<"medium">, Type.TLiteral<"high">, Type.TLiteral<"xhigh">]>>;
12
+ max_turns: Type.TOptional<Type.TNumber>;
13
+ run_in_background: Type.TOptional<Type.TBoolean>;
14
+ fork_context: Type.TOptional<Type.TBoolean>;
15
+ }>;
16
+ declare const SendAgentInputArgsSchema: Type.TObject<{
17
+ target: Type.TString;
18
+ prompt: Type.TString;
19
+ mode: Type.TOptional<Type.TUnion<[Type.TLiteral<"prompt">, Type.TLiteral<"steer">, Type.TLiteral<"follow_up">]>>;
20
+ }>;
21
+ declare const WaitAgentArgsSchema: Type.TObject<{
22
+ targets: Type.TArray<Type.TString>;
23
+ timeout_ms: Type.TOptional<Type.TNumber>;
24
+ }>;
25
+ declare const CloseAgentArgsSchema: Type.TObject<{
26
+ target: Type.TString;
27
+ }>;
28
+ declare const ResumeAgentArgsSchema: Type.TObject<{
29
+ id: Type.TString;
30
+ }>;
31
+ declare const GetAgentResultArgsSchema: Type.TObject<{
32
+ target: Type.TString;
33
+ }>;
34
+ declare const ListAgentsArgsSchema: Type.TObject<{
35
+ path_prefix: Type.TOptional<Type.TString>;
36
+ }>;
37
+ type SpawnAgentArgs = Static<typeof SpawnAgentArgsSchema>;
38
+ type SendAgentInputArgs = Static<typeof SendAgentInputArgsSchema>;
39
+ type WaitAgentArgs = Static<typeof WaitAgentArgsSchema>;
40
+ type CloseAgentArgs = Static<typeof CloseAgentArgsSchema>;
41
+ type ResumeAgentArgs = Static<typeof ResumeAgentArgsSchema>;
42
+ type GetAgentResultArgs = Static<typeof GetAgentResultArgsSchema>;
43
+ type ListAgentsArgs = Static<typeof ListAgentsArgsSchema>;
44
+ declare function registerAgentControllerTool(pi: Pick<ExtensionAPI, "registerTool" | "appendEntry" | "on">): void;
45
+ declare function createSubagentToolRuntime(pi: Pick<ExtensionAPI, "appendEntry">): SubagentToolRuntime;
46
+ interface SubagentToolRuntime {
47
+ spawn(params: SpawnAgentArgs, ctx: ToolContext): Promise<AgentToolResult<unknown>>;
48
+ send(params: SendAgentInputArgs, ctx: ToolContext): Promise<AgentToolResult<unknown>>;
49
+ wait(params: WaitAgentArgs, ctx: ToolContext): Promise<AgentToolResult<unknown>>;
50
+ close(params: CloseAgentArgs, ctx: ToolContext): Promise<AgentToolResult<unknown>>;
51
+ resume(params: ResumeAgentArgs, ctx: ToolContext): Promise<AgentToolResult<unknown>>;
52
+ get(params: GetAgentResultArgs, ctx: ToolContext): Promise<AgentToolResult<unknown>>;
53
+ list(params: ListAgentsArgs, ctx: ToolContext): Promise<AgentToolResult<unknown>>;
54
+ dispose(): Promise<void>;
55
+ }
56
+ type ToolContext = Parameters<ToolDefinition["execute"]>[4];
57
+ declare function createSubagentTools(runtime: SubagentToolRuntime): readonly ToolDefinition[];
58
+ //#endregion
59
+ export { SubagentToolRuntime, createSubagentToolRuntime, createSubagentTools, registerAgentControllerTool };