@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.
- package/README.md +0 -562
- package/dist/agent-controller.d.ts +59 -0
- package/dist/agent-controller.js +330 -0
- package/dist/config.d.ts +69 -0
- package/dist/config.js +336 -0
- package/dist/extension.d.ts +5 -26
- package/dist/extension.js +5 -202
- package/dist/schema.d.ts +40 -0
- package/dist/schema.js +128 -0
- package/package.json +16 -14
- package/dist/catalog.d.ts +0 -32
- package/dist/catalog.js +0 -102
- package/dist/errors.d.ts +0 -74
- package/dist/errors.js +0 -62
- package/dist/policy.js +0 -73
- package/dist/runtime/backend/index.js +0 -15
- package/dist/runtime/backend/model-scope.js +0 -199
- package/dist/runtime/backend/model-selection.js +0 -79
- package/dist/runtime/backend/pi-cli-backend.js +0 -301
- package/dist/runtime/backend/pi-sdk-backend.js +0 -212
- package/dist/runtime/backend/prompt-profile-rules.js +0 -196
- package/dist/runtime/backend/prompts.js +0 -122
- package/dist/runtime/backend/runners.js +0 -402
- package/dist/runtime/backend/scaffold-backend.js +0 -63
- package/dist/runtime/backend/sdk-stream-capture.js +0 -79
- package/dist/runtime/backend/subagent-prompts.js +0 -100
- package/dist/runtime/backend/system-prompt-authoring.js +0 -32
- package/dist/runtime/backend/system-prompt-packs.js +0 -62
- package/dist/runtime/backend/system-prompts.js +0 -338
- package/dist/runtime/events.d.ts +0 -39
- package/dist/runtime/events.js +0 -130
- package/dist/runtime/live-ui.d.ts +0 -41
- package/dist/runtime/live-ui.js +0 -193
- package/dist/runtime/subagent-profiles.js +0 -93
- package/dist/runtime/task-transcript.js +0 -255
- package/dist/runtime/tasks/persistence.js +0 -362
- package/dist/runtime/tasks/store.js +0 -643
- package/dist/runtime/tasks/types.d.ts +0 -123
- package/dist/runtime/tasks/types.js +0 -5
- package/dist/runtime/ui.d.ts +0 -37
- package/dist/runtime/ui.js +0 -151
- package/dist/schema/shared.js +0 -38
- package/dist/schema/task-record.d.ts +0 -42
- package/dist/schema/task-record.js +0 -65
- package/dist/schema/task-tool.js +0 -199
- package/dist/tools/primary.js +0 -297
- package/dist/tools/task/defaults.js +0 -84
- package/dist/tools/task/execution/batch.js +0 -288
- package/dist/tools/task/execution/cancel.js +0 -52
- package/dist/tools/task/execution/kernel.js +0 -30
- package/dist/tools/task/execution/lifecycle.js +0 -419
- package/dist/tools/task/execution/projection.js +0 -118
- package/dist/tools/task/execution/send.js +0 -227
- package/dist/tools/task/execution/shared.js +0 -246
- package/dist/tools/task/execution/start.js +0 -96
- package/dist/tools/task/execution/status.js +0 -27
- package/dist/tools/task/execution/wait.js +0 -155
- package/dist/tools/task/operations.js +0 -186
- package/dist/tools/task/render.js +0 -508
- package/dist/tools/task/transport.js +0 -183
- package/dist/tools/task/updates.js +0 -221
- package/src/runtime/backend/prompts/finder.claude.txt +0 -34
- package/src/runtime/backend/prompts/finder.gemini.txt +0 -34
- package/src/runtime/backend/prompts/finder.general.txt +0 -34
- package/src/runtime/backend/prompts/finder.gpt.txt +0 -34
- package/src/runtime/backend/prompts/librarian.claude.txt +0 -54
- package/src/runtime/backend/prompts/librarian.gemini.txt +0 -54
- package/src/runtime/backend/prompts/librarian.general.txt +0 -55
- package/src/runtime/backend/prompts/librarian.gpt.txt +0 -53
- package/src/runtime/backend/prompts/oracle.claude.txt +0 -51
- package/src/runtime/backend/prompts/oracle.gemini.txt +0 -50
- package/src/runtime/backend/prompts/oracle.general.txt +0 -50
- 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 };
|