@clanker-code/pi-subagents 0.10.5
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/.plans/PLAN-next-changes.md +183 -0
- package/.plans/README.md +14 -0
- package/AGENTS.md +31 -0
- package/CHANGELOG.md +583 -0
- package/CLAUDE.md +1 -0
- package/LICENSE +21 -0
- package/README.md +630 -0
- package/RELEASE.md +39 -0
- package/dist/abort-resend.d.ts +35 -0
- package/dist/abort-resend.js +71 -0
- package/dist/agent-details.d.ts +17 -0
- package/dist/agent-details.js +22 -0
- package/dist/agent-manager.d.ts +132 -0
- package/dist/agent-manager.js +493 -0
- package/dist/agent-runner.d.ts +165 -0
- package/dist/agent-runner.js +732 -0
- package/dist/agent-tool-description.d.ts +9 -0
- package/dist/agent-tool-description.js +147 -0
- package/dist/agent-types.d.ts +60 -0
- package/dist/agent-types.js +157 -0
- package/dist/context.d.ts +12 -0
- package/dist/context.js +56 -0
- package/dist/cross-extension-rpc.d.ts +46 -0
- package/dist/cross-extension-rpc.js +76 -0
- package/dist/custom-agents.d.ts +14 -0
- package/dist/custom-agents.js +149 -0
- package/dist/default-agents.d.ts +7 -0
- package/dist/default-agents.js +119 -0
- package/dist/enabled-models.d.ts +49 -0
- package/dist/enabled-models.js +145 -0
- package/dist/env.d.ts +6 -0
- package/dist/env.js +28 -0
- package/dist/group-join.d.ts +32 -0
- package/dist/group-join.js +116 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.js +1918 -0
- package/dist/invocation-config.d.ts +25 -0
- package/dist/invocation-config.js +19 -0
- package/dist/memory.d.ts +49 -0
- package/dist/memory.js +151 -0
- package/dist/model-resolver.d.ts +19 -0
- package/dist/model-resolver.js +62 -0
- package/dist/notifications.d.ts +6 -0
- package/dist/notifications.js +107 -0
- package/dist/output-file.d.ts +24 -0
- package/dist/output-file.js +86 -0
- package/dist/peek.d.ts +37 -0
- package/dist/peek.js +121 -0
- package/dist/prompts.d.ts +40 -0
- package/dist/prompts.js +95 -0
- package/dist/schedule-store.d.ts +38 -0
- package/dist/schedule-store.js +155 -0
- package/dist/schedule.d.ts +109 -0
- package/dist/schedule.js +338 -0
- package/dist/settings.d.ts +135 -0
- package/dist/settings.js +168 -0
- package/dist/skill-loader.d.ts +24 -0
- package/dist/skill-loader.js +93 -0
- package/dist/status-note.d.ts +13 -0
- package/dist/status-note.js +24 -0
- package/dist/types.d.ts +184 -0
- package/dist/types.js +7 -0
- package/dist/ui/agent-tool-rendering.d.ts +34 -0
- package/dist/ui/agent-tool-rendering.js +154 -0
- package/dist/ui/agent-widget-tree.d.ts +33 -0
- package/dist/ui/agent-widget-tree.js +130 -0
- package/dist/ui/agent-widget.d.ts +156 -0
- package/dist/ui/agent-widget.js +408 -0
- package/dist/ui/conversation-viewer.d.ts +47 -0
- package/dist/ui/conversation-viewer.js +290 -0
- package/dist/ui/menu-select.d.ts +20 -0
- package/dist/ui/menu-select.js +46 -0
- package/dist/ui/schedule-menu.d.ts +16 -0
- package/dist/ui/schedule-menu.js +99 -0
- package/dist/ui/viewer-keys.d.ts +20 -0
- package/dist/ui/viewer-keys.js +17 -0
- package/dist/usage.d.ts +50 -0
- package/dist/usage.js +49 -0
- package/dist/wait.d.ts +10 -0
- package/dist/wait.js +37 -0
- package/dist/worktree.d.ts +45 -0
- package/dist/worktree.js +160 -0
- package/docs/design/default-extension-tool-exposure.md +56 -0
- package/docs/superpowers/plans/2026-06-19-recursive-subagent-widget.md +600 -0
- package/docs/superpowers/specs/2026-06-19-recursive-subagent-widget-design.md +189 -0
- package/examples/agent-tool-description.md +45 -0
- package/package.json +56 -0
- package/reviews/proposal-structured-output-schema.md +135 -0
- package/reviews/recursive-subagent-widget-preview-rev2.png +0 -0
- package/reviews/recursive-subagent-widget-preview.html +137 -0
- package/reviews/recursive-subagent-widget-preview.png +0 -0
- package/reviews/subagent-features-comparison.md +350 -0
- package/src/abort-resend.ts +75 -0
- package/src/agent-details.ts +31 -0
- package/src/agent-manager.ts +596 -0
- package/src/agent-runner.ts +872 -0
- package/src/agent-tool-description.ts +163 -0
- package/src/agent-types.ts +189 -0
- package/src/context.ts +58 -0
- package/src/cross-extension-rpc.ts +122 -0
- package/src/custom-agents.ts +160 -0
- package/src/default-agents.ts +123 -0
- package/src/enabled-models.ts +180 -0
- package/src/env.ts +33 -0
- package/src/group-join.ts +141 -0
- package/src/index.ts +2115 -0
- package/src/invocation-config.ts +42 -0
- package/src/memory.ts +165 -0
- package/src/model-resolver.ts +81 -0
- package/src/notifications.ts +120 -0
- package/src/output-file.ts +96 -0
- package/src/peek.ts +155 -0
- package/src/prompts.ts +129 -0
- package/src/schedule-store.ts +153 -0
- package/src/schedule.ts +365 -0
- package/src/settings.ts +289 -0
- package/src/skill-loader.ts +102 -0
- package/src/status-note.ts +25 -0
- package/src/types.ts +195 -0
- package/src/ui/agent-tool-rendering.ts +175 -0
- package/src/ui/agent-widget-tree.ts +169 -0
- package/src/ui/agent-widget.ts +497 -0
- package/src/ui/conversation-viewer.ts +297 -0
- package/src/ui/menu-select.ts +68 -0
- package/src/ui/schedule-menu.ts +105 -0
- package/src/ui/viewer-keys.ts +39 -0
- package/src/usage.ts +60 -0
- package/src/wait.ts +44 -0
- package/src/worktree.ts +191 -0
- package/vitest.config.ts +25 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# Recursive Subagent Widget Design
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
|
|
5
|
+
Show the full recursive subagent delegation tree in the TUI widget, including grandchildren and deeper descendants, with a rich default view, automatic compact fallback, and a focused path view for subagent-local context.
|
|
6
|
+
|
|
7
|
+
## Verified current behavior
|
|
8
|
+
|
|
9
|
+
The current `AgentWidget` renders only `manager.listAgents()` from its own extension instance. It groups records by status (`finished`, `running`, `queued`) and renders them as flat sibling lines. It does not build a tree from `parentAgentId`/`depth`, and descendants spawned by recursive subagents are owned by child extension/manager instances rather than the root widget manager.
|
|
10
|
+
|
|
11
|
+
Evidence from source inspection:
|
|
12
|
+
|
|
13
|
+
- `src/ui/agent-widget.ts` calls `this.manager.listAgents()` and renders flat `finishedLines`, `runningLines`, and `queuedLine` arrays.
|
|
14
|
+
- `src/agent-manager.ts` records already include `depth` and `parentAgentId` metadata.
|
|
15
|
+
- `src/index.ts` emits recursive lifecycle events with `depth` and `parentAgentId`, but the widget does not consume those events into a recursive aggregate.
|
|
16
|
+
|
|
17
|
+
## Settled visual direction
|
|
18
|
+
|
|
19
|
+
The browser preview lives at:
|
|
20
|
+
|
|
21
|
+
- `reviews/recursive-subagent-widget-preview.html`
|
|
22
|
+
- `reviews/recursive-subagent-widget-preview-rev2.png`
|
|
23
|
+
|
|
24
|
+
Approved direction:
|
|
25
|
+
|
|
26
|
+
1. Rich tree is the default.
|
|
27
|
+
2. The widget automatically falls back to compact rendering when the terminal width, line budget, or tree size makes rich rendering too noisy.
|
|
28
|
+
3. Users can configure rendering mode in settings.
|
|
29
|
+
4. A focused path view is used inside subagent-local UI context to show “where this subagent sits in the tree.”
|
|
30
|
+
|
|
31
|
+
## Render modes
|
|
32
|
+
|
|
33
|
+
### Rich mode
|
|
34
|
+
|
|
35
|
+
Rich mode is the default root widget view.
|
|
36
|
+
|
|
37
|
+
Example shape:
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
● Agents 3 running · 1 queued · depth 3/4
|
|
41
|
+
├─ ⠋ Plan opus split task
|
|
42
|
+
│ ⎿ ↻3≤20 · 4 tools · 22.8k token (38%) · 1m 12s
|
|
43
|
+
│ ├─ ⠹ Explore inspect widget data flow
|
|
44
|
+
│ │ ⎿ reading agent-widget.ts · 14.2s
|
|
45
|
+
│ │ └─ ⠼ general-purpose trace manager ownership
|
|
46
|
+
│ │ ⎿ searching tests · 4.8s
|
|
47
|
+
│ └─ ✓ auditor review plan · 31s
|
|
48
|
+
├─ ◦ Explore queued after concurrency cap
|
|
49
|
+
└─ ✗ Plan old attempt error: model unavailable
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Node content:
|
|
53
|
+
|
|
54
|
+
- Connector glyphs show parent/child relationships.
|
|
55
|
+
- Status icon/spinner shows queued/running/success/error/stopped/aborted.
|
|
56
|
+
- Agent type and optional model/tags are shown on the main line.
|
|
57
|
+
- Description is shown on the main line.
|
|
58
|
+
- Activity/stat detail line is shown for active agents.
|
|
59
|
+
- Terminal/error line can include a short error or terminal status.
|
|
60
|
+
|
|
61
|
+
### Compact mode
|
|
62
|
+
|
|
63
|
+
Compact mode renders one line per agent using the same tree structure and ordering, but omits the active detail line.
|
|
64
|
+
|
|
65
|
+
Example shape:
|
|
66
|
+
|
|
67
|
+
```text
|
|
68
|
+
● Agents
|
|
69
|
+
├─ ⠋ Plan split task · ↻3 · 2 tools · 1m 12s
|
|
70
|
+
│ ├─ ⠹ Explore inspect UI · reading…
|
|
71
|
+
│ └─ ✓ auditor review paths · 42s
|
|
72
|
+
└─ ⠼ general-purpose write tests · editing…
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Auto fallback
|
|
76
|
+
|
|
77
|
+
Default behavior is `rich` with automatic fallback to compact when rich mode would exceed the widget budget.
|
|
78
|
+
|
|
79
|
+
Fallback triggers:
|
|
80
|
+
|
|
81
|
+
- Terminal width is too narrow for readable rich lines.
|
|
82
|
+
- Rich tree would exceed the configured widget line cap after subtree overflow summaries are applied.
|
|
83
|
+
- Tree density is high enough that compact mode communicates more useful information than rich mode.
|
|
84
|
+
|
|
85
|
+
Exact thresholds should be conservative and test-covered; the first implementation should prefer readability and bounded output over displaying every detail.
|
|
86
|
+
|
|
87
|
+
### Focused path view
|
|
88
|
+
|
|
89
|
+
Focused path view is for a subagent-local widget or future selectable mode. It answers: “where is this subagent in the recursive delegation tree?”
|
|
90
|
+
|
|
91
|
+
Example shape:
|
|
92
|
+
|
|
93
|
+
```text
|
|
94
|
+
● Agents 7 total · showing active branch
|
|
95
|
+
├─ ⠋ Plan split task · 1m 12s
|
|
96
|
+
│ └─ ⠹ Explore inspect UI · reading…
|
|
97
|
+
│ └─ ⠼ general-purpose trace manager · searching…
|
|
98
|
+
├─ +2 completed siblings hidden
|
|
99
|
+
└─ +2 queued / stale descendants hidden
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Tree data model
|
|
103
|
+
|
|
104
|
+
Create a tree model separate from rendering. The model should be built from agent records and/or lifecycle snapshots.
|
|
105
|
+
|
|
106
|
+
Required fields per node:
|
|
107
|
+
|
|
108
|
+
- `id`
|
|
109
|
+
- `parentAgentId`
|
|
110
|
+
- `depth`
|
|
111
|
+
- `type`
|
|
112
|
+
- `description`
|
|
113
|
+
- `status`
|
|
114
|
+
- `startedAt`
|
|
115
|
+
- `completedAt`
|
|
116
|
+
- `error`
|
|
117
|
+
- `toolUses`
|
|
118
|
+
- `invocation`
|
|
119
|
+
- live activity state when available
|
|
120
|
+
- usage/turn/compaction stats when available
|
|
121
|
+
|
|
122
|
+
The tree builder should:
|
|
123
|
+
|
|
124
|
+
- Key all records by id.
|
|
125
|
+
- Link children to parents by `parentAgentId`.
|
|
126
|
+
- Treat missing parent records as orphans under an `Other agents` group.
|
|
127
|
+
- Sort parent before descendants.
|
|
128
|
+
- Sort active nodes before queued before recently terminal siblings within a sibling set.
|
|
129
|
+
- Preserve stable ordering between renders to avoid visual jitter.
|
|
130
|
+
|
|
131
|
+
## Recursive visibility source
|
|
132
|
+
|
|
133
|
+
The root widget needs a durable aggregate that includes descendants from child manager instances. The design should prefer using existing lifecycle events over tight manager coupling:
|
|
134
|
+
|
|
135
|
+
- `subagents:started`
|
|
136
|
+
- `subagents:completed`
|
|
137
|
+
- `subagents:failed`
|
|
138
|
+
- `subagents:compacted`
|
|
139
|
+
- existing direct manager records for live activity and direct children
|
|
140
|
+
|
|
141
|
+
If lifecycle events do not carry enough live detail for rich rendering, extend event payloads narrowly rather than exposing child managers directly.
|
|
142
|
+
|
|
143
|
+
## Settings
|
|
144
|
+
|
|
145
|
+
Add a widget display setting with these values:
|
|
146
|
+
|
|
147
|
+
- `auto` — default: rich rendering with compact fallback.
|
|
148
|
+
- `rich` — prefer rich rendering; still apply subtree overflow to remain bounded.
|
|
149
|
+
- `compact` — always render compact tree.
|
|
150
|
+
|
|
151
|
+
The settings UI should label this as something like “Subagent widget display” with choices “Auto”, “Rich tree”, and “Compact tree.”
|
|
152
|
+
|
|
153
|
+
## Overflow and truncation
|
|
154
|
+
|
|
155
|
+
The widget must remain bounded.
|
|
156
|
+
|
|
157
|
+
Rules:
|
|
158
|
+
|
|
159
|
+
- Keep the existing `MAX_WIDGET_LINES` style cap, but apply it to a tree-aware layout.
|
|
160
|
+
- Collapse whole subtrees where possible instead of arbitrary middle lines.
|
|
161
|
+
- Show summary lines such as `└─ +4 descendants hidden (2 running, 1 queued, 1 finished)`.
|
|
162
|
+
- Prioritize visible active paths over completed siblings.
|
|
163
|
+
- Preserve width safety using existing `truncateToWidth` behavior.
|
|
164
|
+
|
|
165
|
+
## Testing requirements
|
|
166
|
+
|
|
167
|
+
Add deterministic tests for:
|
|
168
|
+
|
|
169
|
+
1. A parent → child → grandchild tree renders with proper indentation/connectors.
|
|
170
|
+
2. Grandchildren appear in the root widget aggregate.
|
|
171
|
+
3. Compact mode uses one line per node.
|
|
172
|
+
4. Auto mode falls back to compact under constrained width/height.
|
|
173
|
+
5. Overflow collapses subtrees and reports correct hidden counts.
|
|
174
|
+
6. Orphan records render under `Other agents`.
|
|
175
|
+
7. Status bar counts include descendants.
|
|
176
|
+
8. Existing width-safety and status-bar truncation tests continue to pass.
|
|
177
|
+
|
|
178
|
+
## Non-goals for first implementation
|
|
179
|
+
|
|
180
|
+
- Interactive expand/collapse controls inside the widget.
|
|
181
|
+
- Persisted historical trees beyond the existing short linger window.
|
|
182
|
+
- New public API for external extensions unless required by implementation evidence.
|
|
183
|
+
- Reworking core subagent scheduling or completion delivery.
|
|
184
|
+
|
|
185
|
+
## Open implementation notes
|
|
186
|
+
|
|
187
|
+
- Verify whether child lifecycle events already propagate to the root extension’s event bus in real recursive sessions. If they do, use them. If not, add a narrow bridge for descendant lifecycle snapshots.
|
|
188
|
+
- Keep rendering logic isolated from data aggregation so the tree model can be tested without the TUI.
|
|
189
|
+
- Avoid changing the current Agent tool result renderer as part of this feature unless a test proves shared behavior is required.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
Launch a new agent to handle complex, multi-step tasks autonomously. Each agent type has specific capabilities and tools available to it.
|
|
2
|
+
|
|
3
|
+
Available agent types and the tools they have access to:
|
|
4
|
+
{{typeList}}
|
|
5
|
+
|
|
6
|
+
Custom agents can be defined in .pi/agents/<name>.md (project) or {{agentDir}}/agents/<name>.md (global) — they are picked up automatically. Project-level agents override global ones. Creating a .md file with the same name as a default agent overrides it.
|
|
7
|
+
|
|
8
|
+
When using the Agent tool, specify a subagent_type parameter to select which agent type to use.
|
|
9
|
+
|
|
10
|
+
## When not to use
|
|
11
|
+
|
|
12
|
+
If the target is already known, use a direct tool — `read` for a known path, `grep`/`find` for a specific symbol or string. Reserve this tool for open-ended questions that span the codebase, or tasks that match an available agent type.
|
|
13
|
+
|
|
14
|
+
## Usage notes
|
|
15
|
+
|
|
16
|
+
- Always include a short (3-5 word) description summarizing what the agent will do (shown in UI).
|
|
17
|
+
- When you launch multiple agents for independent work, send them in a single message with multiple tool uses so they run concurrently. If the user specifies that they want agents run "in parallel", you MUST send a single message with multiple tool calls.
|
|
18
|
+
- When the agent is done, it returns a single message back to you. The result is not visible to the user — to show the user, send a text message with a concise summary.
|
|
19
|
+
- Trust but verify: an agent's summary describes what it intended to do, not necessarily what it did. When an agent writes or edits code, check the actual changes before reporting work as done.
|
|
20
|
+
- Agents always run in the background. You will be notified when each completes — do NOT poll or sleep waiting for it. Continue with other work or respond to the user instead.
|
|
21
|
+
- Background by default: when useful independent work exists, launch it and keep going. Doing nothing while an agent runs is worse than using background capacity.
|
|
22
|
+
- {{recursiveGuideline}}
|
|
23
|
+
- Use get_subagent_result if you need to retrieve a result before the completion notification arrives, but do not poll or sleep waiting for it.
|
|
24
|
+
- Use resume with an agent ID to continue a previous agent's work. A new (non-resume) Agent call starts a fresh agent with no memory of prior runs, so the prompt must be self-contained.
|
|
25
|
+
- Use list_models to enumerate the model registry the `model:` param accepts before passing a model name explicitly.
|
|
26
|
+
- Use steer_subagent to send mid-run messages to a running background agent.
|
|
27
|
+
- Clearly tell the agent whether you expect it to write code or just to do research (search, file reads, etc.), since it is not aware of the user's intent.
|
|
28
|
+
- If an agent's description says it should be used proactively, try to use it without the user having to ask for it first.
|
|
29
|
+
- Use model to specify a different model (as "provider/modelId", or fuzzy e.g. "haiku", "sonnet").
|
|
30
|
+
- Use thinking to control extended thinking level.
|
|
31
|
+
- Use inherit_context if the agent needs the parent conversation history.
|
|
32
|
+
- Use isolation: "worktree" to run the agent in an isolated git worktree (safe parallel file modifications). The worktree is automatically cleaned up if the agent makes no changes; otherwise the path and branch are returned in the result.{{scheduleGuideline}}
|
|
33
|
+
|
|
34
|
+
## Writing the prompt
|
|
35
|
+
|
|
36
|
+
Provide clear, detailed prompts so the agent can work autonomously. Brief it like a smart colleague who just walked into the room — it hasn't seen this conversation, doesn't know what you've tried, doesn't understand why this task matters.
|
|
37
|
+
- Explain what you're trying to accomplish and why.
|
|
38
|
+
- Describe what you've already learned or ruled out.
|
|
39
|
+
- Give enough context about the surrounding problem that the agent can make judgment calls rather than just following a narrow instruction.
|
|
40
|
+
- If you need a short response, say so ("report in under 200 words").
|
|
41
|
+
- Lookups: hand over the exact command. Investigations: hand over the question — prescribed steps become dead weight when the premise is wrong.
|
|
42
|
+
|
|
43
|
+
Terse command-style prompts produce shallow, generic work.
|
|
44
|
+
|
|
45
|
+
**Never delegate understanding.** Don't write "based on your findings, fix the bug" or "based on the research, implement it." Those phrases push synthesis onto the agent instead of doing it yourself. Write prompts that prove you understood: include file paths, line numbers, what specifically to change.
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@clanker-code/pi-subagents",
|
|
3
|
+
"version": "0.10.5",
|
|
4
|
+
"description": "A pi extension extension that brings smart Claude Code-style autonomous sub-agents to pi.",
|
|
5
|
+
"author": "clankercode",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/clankercode/pi-subagents.git"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/clankercode/pi-subagents#readme",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/clankercode/pi-subagents/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"pi-package",
|
|
17
|
+
"pi",
|
|
18
|
+
"pi-extension",
|
|
19
|
+
"subagent",
|
|
20
|
+
"agent",
|
|
21
|
+
"autonomous"
|
|
22
|
+
],
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"@earendil-works/pi-ai": ">=0.74.0",
|
|
25
|
+
"@earendil-works/pi-coding-agent": ">=0.74.0",
|
|
26
|
+
"@earendil-works/pi-tui": ">=0.74.0"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@sinclair/typebox": "^0.34.49",
|
|
30
|
+
"croner": "^10.0.1",
|
|
31
|
+
"nanoid": "^5.0.0"
|
|
32
|
+
},
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsc",
|
|
35
|
+
"prepublishOnly": "npm run lint && npm run typecheck && npm run test && npm run build",
|
|
36
|
+
"test": "vitest run",
|
|
37
|
+
"test:watch": "vitest",
|
|
38
|
+
"test:e2e": "vitest run e2e --reporter=verbose",
|
|
39
|
+
"typecheck": "tsc --noEmit",
|
|
40
|
+
"lint": "biome check src/ test/",
|
|
41
|
+
"lint:fix": "biome check --fix src/ test/"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@biomejs/biome": "^2.4.14",
|
|
45
|
+
"@types/node": "^25.5.0",
|
|
46
|
+
"typescript": "^6.0.0",
|
|
47
|
+
"vitest": "^4.0.18"
|
|
48
|
+
},
|
|
49
|
+
"pi": {
|
|
50
|
+
"extensions": [
|
|
51
|
+
"./src/index.ts"
|
|
52
|
+
],
|
|
53
|
+
"video": "https://github.com/clankercode/pi-subagents/raw/master/media/demo.mp4",
|
|
54
|
+
"image": "https://github.com/clankercode/pi-subagents/raw/master/media/screenshot.png"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# Proposal: Structured JSON Output for Subagents
|
|
2
|
+
|
|
3
|
+
**Date:** 2026-06-19
|
|
4
|
+
**Status:** Proposal / draft
|
|
5
|
+
**Related:** `reviews/subagent-features-comparison.md`
|
|
6
|
+
|
|
7
|
+
## Problem
|
|
8
|
+
|
|
9
|
+
Today, subagents return free-form text. The parent model must parse the text to extract lists, file paths, decisions, or any other structured data before it can feed results into the next tool or agent. This is slow, unreliable, and becomes a bottleneck when chaining multiple agents together.
|
|
10
|
+
|
|
11
|
+
## Goal
|
|
12
|
+
|
|
13
|
+
Add an optional `output_schema` parameter to the `Agent` tool. When supplied, the agent must return JSON matching the schema. The extension validates the output and surfaces either the parsed object or a clear validation error.
|
|
14
|
+
|
|
15
|
+
The feature must be strictly opt-in: the default is free-form text, and agents should only use structured output when the caller explicitly needs it.
|
|
16
|
+
|
|
17
|
+
## Design
|
|
18
|
+
|
|
19
|
+
### Tool parameter
|
|
20
|
+
|
|
21
|
+
Add to the `Agent` tool schema:
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
output_schema: Type.Optional(
|
|
25
|
+
Type.Union([Type.String(), Type.Object({})], {
|
|
26
|
+
description:
|
|
27
|
+
'Optional JSON Schema the agent\'s final answer must match. "": free-form text (recommended default; only use this when the consumer needs structured data).',
|
|
28
|
+
})
|
|
29
|
+
),
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
- Accepts either a JSON Schema object or a JSON-stringified schema.
|
|
33
|
+
- Default is `undefined` / `""` → free-form text, no validation.
|
|
34
|
+
- The schema type is JSON Schema, the same standard already used for tool-call schemas in pi.
|
|
35
|
+
|
|
36
|
+
### Frontmatter support
|
|
37
|
+
|
|
38
|
+
Optionally allow agent `.md` files to pin a default schema:
|
|
39
|
+
|
|
40
|
+
```yaml
|
|
41
|
+
---
|
|
42
|
+
output_schema:
|
|
43
|
+
type: object
|
|
44
|
+
properties:
|
|
45
|
+
files:
|
|
46
|
+
type: array
|
|
47
|
+
items:
|
|
48
|
+
type: object
|
|
49
|
+
properties:
|
|
50
|
+
path: { type: string }
|
|
51
|
+
reason: { type: string }
|
|
52
|
+
required: [path, reason]
|
|
53
|
+
required: [files]
|
|
54
|
+
---
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The caller-supplied `output_schema` overrides the frontmatter value. This lets custom agent types advertise a structured contract without every caller repeating it.
|
|
58
|
+
|
|
59
|
+
### Prompt injection
|
|
60
|
+
|
|
61
|
+
When `output_schema` is non-empty, append a concise instruction to the agent system prompt:
|
|
62
|
+
|
|
63
|
+
> Your final answer must be a single JSON object matching the provided JSON Schema. Do not wrap the JSON in markdown fences, do not add commentary outside the JSON, and do not emit any text after the JSON object.
|
|
64
|
+
|
|
65
|
+
### Validation
|
|
66
|
+
|
|
67
|
+
On agent completion:
|
|
68
|
+
|
|
69
|
+
1. Extract the last JSON object from the final assistant message.
|
|
70
|
+
2. If the output is wrapped in markdown fences, strip them.
|
|
71
|
+
3. Validate the parsed object against the JSON Schema using a lightweight validator (e.g. `ajv` or TypeBox's `Value.Check`).
|
|
72
|
+
4. If validation fails:
|
|
73
|
+
- Mark the agent status as `failed`.
|
|
74
|
+
- Return an error message containing the schema validation errors and a snippet of the raw output.
|
|
75
|
+
5. If validation passes:
|
|
76
|
+
- Include the parsed object in the result under a `structured` field.
|
|
77
|
+
- Keep the normal textual result preview so the notification UI stays readable.
|
|
78
|
+
|
|
79
|
+
### Result shape
|
|
80
|
+
|
|
81
|
+
For a structured agent, the result should expose:
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"ok": true,
|
|
86
|
+
"data": { "files": [...] },
|
|
87
|
+
"preview": "Found 5 auth-related files..."
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
For failures:
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"ok": false,
|
|
96
|
+
"error": "Output did not match the provided JSON Schema",
|
|
97
|
+
"validationErrors": [...],
|
|
98
|
+
"rawPreview": "..."
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Notification and join modes
|
|
103
|
+
|
|
104
|
+
Structured output does not change the notification path. Background agents still send steering-style notifications. The XML payload can include a `<structured-output>` block with the serialized JSON so the parent model can reason about it directly.
|
|
105
|
+
|
|
106
|
+
### Interaction with existing features
|
|
107
|
+
|
|
108
|
+
- **Worktree isolation:** unchanged; the structured result is still returned through the normal completion path.
|
|
109
|
+
- **Scheduling:** scheduled agents may use `output_schema` so recurring jobs produce machine-readable results.
|
|
110
|
+
- **Resume:** resuming a structured agent does not re-validate old output; only the final completion is validated.
|
|
111
|
+
- **Cross-extension RPC:** `output_schema` is serializable JSON and can be passed through the RPC spawn envelope.
|
|
112
|
+
|
|
113
|
+
## Acceptance criteria
|
|
114
|
+
|
|
115
|
+
- [ ] `Agent` tool accepts optional `output_schema` as JSON Schema object or string.
|
|
116
|
+
- [ ] Default behavior remains free-form text; no validation when omitted.
|
|
117
|
+
- [ ] Frontmatter supports optional `output_schema`.
|
|
118
|
+
- [ ] System prompt instructs the agent to emit only matching JSON.
|
|
119
|
+
- [ ] Output is parsed and validated strictly on completion.
|
|
120
|
+
- [ ] Validation failures produce a clear error with the raw output snippet.
|
|
121
|
+
- [ ] Validation successes expose parsed data in result notifications and RPC responses.
|
|
122
|
+
- [ ] Tests cover valid schema, invalid schema, fenced JSON, and missing schema cases.
|
|
123
|
+
- [ ] `npm run typecheck` and `npm run lint` pass.
|
|
124
|
+
|
|
125
|
+
## Open questions
|
|
126
|
+
|
|
127
|
+
1. Should we add a small built-in helper agent type that demonstrates structured output (e.g. `json-explorer`)?
|
|
128
|
+
2. Should `output_schema` be surfaced in `/agents` agent-type descriptions so the orchestrator knows which agents return structured data?
|
|
129
|
+
3. Should failed validation trigger automatic retry with a steering message, or fail fast?
|
|
130
|
+
|
|
131
|
+
## Rationale
|
|
132
|
+
|
|
133
|
+
JSON Schema was chosen because it is the same standard already used for pi tool definitions. Agents and users do not need to learn a new format, and existing tooling (TypeBox, `ajv`) integrates cleanly.
|
|
134
|
+
|
|
135
|
+
Strict validation keeps the contract trustworthy. If a consumer asks for structured output, receiving invalid data is worse than receiving no data, because the consumer is likely to feed it into code that assumes correctness.
|
|
Binary file
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>Recursive Subagents Widget Preview</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root {
|
|
9
|
+
color-scheme: dark;
|
|
10
|
+
--bg: #0b1020;
|
|
11
|
+
--panel: #121a2d;
|
|
12
|
+
--terminal: #070b13;
|
|
13
|
+
--line: #29364f;
|
|
14
|
+
--text: #dbe7ff;
|
|
15
|
+
--muted: #7f8daa;
|
|
16
|
+
--dim: #566176;
|
|
17
|
+
--accent: #82aaff;
|
|
18
|
+
--green: #8bdc9f;
|
|
19
|
+
--yellow: #ffd479;
|
|
20
|
+
--red: #ff7f8f;
|
|
21
|
+
--cyan: #7ee7f5;
|
|
22
|
+
--purple: #c099ff;
|
|
23
|
+
}
|
|
24
|
+
* { box-sizing: border-box; }
|
|
25
|
+
body {
|
|
26
|
+
margin: 0;
|
|
27
|
+
background: radial-gradient(circle at 20% 0%, #1b2b50 0, transparent 35%), var(--bg);
|
|
28
|
+
color: var(--text);
|
|
29
|
+
font: 14px/1.45 ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
30
|
+
}
|
|
31
|
+
main { max-width: 1220px; margin: 0 auto; padding: 32px; }
|
|
32
|
+
h1 { font-size: 28px; margin: 0 0 8px; }
|
|
33
|
+
h2 { font-size: 18px; margin: 28px 0 12px; color: #f0f5ff; }
|
|
34
|
+
h3 { font-size: 14px; margin: 0 0 10px; color: var(--accent); text-transform: uppercase; letter-spacing: .08em; }
|
|
35
|
+
p { color: #b9c6df; margin: 0 0 14px; }
|
|
36
|
+
.grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 18px; align-items: start; }
|
|
37
|
+
.card { background: color-mix(in srgb, var(--panel) 92%, white 8%); border: 1px solid var(--line); border-radius: 16px; padding: 18px; box-shadow: 0 12px 40px rgba(0,0,0,.25); }
|
|
38
|
+
.recommended { border-color: color-mix(in srgb, var(--accent) 70%, white 10%); box-shadow: 0 0 0 1px rgba(130,170,255,.15), 0 18px 55px rgba(22,41,82,.5); }
|
|
39
|
+
.terminal { background: var(--terminal); border: 1px solid #1e2a3e; border-radius: 12px; padding: 12px 14px; font: 13px/1.35 ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; white-space: pre; overflow: hidden; min-height: 260px; }
|
|
40
|
+
.term-title { display: flex; gap: 6px; align-items: center; margin-bottom: 10px; color: var(--muted); font: 12px ui-monospace, monospace; }
|
|
41
|
+
.dot { width: 9px; height: 9px; border-radius: 999px; display: inline-block; }
|
|
42
|
+
.green { color: var(--green); } .yellow { color: var(--yellow); } .red { color: var(--red); } .cyan { color: var(--cyan); } .purple { color: var(--purple); }
|
|
43
|
+
.muted { color: var(--muted); } .dim { color: var(--dim); } .accent { color: var(--accent); }
|
|
44
|
+
.legend { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 10px; color: var(--muted); font-size: 12px; }
|
|
45
|
+
.plan { display: grid; grid-template-columns: 1.2fr .8fr; gap: 18px; }
|
|
46
|
+
ol, ul { margin: 0; padding-left: 20px; color: #c4cee2; }
|
|
47
|
+
li { margin: 6px 0; }
|
|
48
|
+
.pill { display: inline-flex; align-items: center; gap: 6px; padding: 3px 8px; border-radius: 999px; background: #1b2740; border: 1px solid #344260; color: #cfd9ef; font-size: 12px; }
|
|
49
|
+
.wide { grid-column: 1 / -1; }
|
|
50
|
+
@media (max-width: 980px) { .grid, .plan { grid-template-columns: 1fr; } }
|
|
51
|
+
</style>
|
|
52
|
+
</head>
|
|
53
|
+
<body>
|
|
54
|
+
<main>
|
|
55
|
+
<h1>Recursive Subagents Widget — Plan + Visual Preview</h1>
|
|
56
|
+
<p>Verified issue: the current widget is flat and bound to one manager instance. It does not assemble a durable parent → child → grandchild tree from recursive agent metadata.</p>
|
|
57
|
+
|
|
58
|
+
<section class="plan">
|
|
59
|
+
<div class="card">
|
|
60
|
+
<h2>Implementation plan, once design is approved</h2>
|
|
61
|
+
<ol>
|
|
62
|
+
<li>Create a small tree model layer: records keyed by id, linked by <code>parentAgentId</code>, sorted by start time/status.</li>
|
|
63
|
+
<li>Teach lifecycle events / shared manager state to surface descendants to the root widget, not only direct children.</li>
|
|
64
|
+
<li>Add configurable widget modes: <code>compact</code> (Option A), <code>rich</code> (Option B), and <code>auto</code>.</li>
|
|
65
|
+
<li>Use the focused path view (Option C) when rendering from inside a subagent, or as an optional display mode later.</li>
|
|
66
|
+
<li>Add deterministic tests for parent → child → grandchild rendering, overflow, width truncation, completed/error linger, and mode switching.</li>
|
|
67
|
+
<li>Keep status bar compact: aggregate running/queued counts across the full tree.</li>
|
|
68
|
+
</ol>
|
|
69
|
+
</div>
|
|
70
|
+
<div class="card">
|
|
71
|
+
<h2>Acceptance criteria</h2>
|
|
72
|
+
<ul>
|
|
73
|
+
<li>Grandchildren and deeper descendants are visible.</li>
|
|
74
|
+
<li>Users can choose compact vs rich rendering in settings.</li>
|
|
75
|
+
<li>Subagents can see their location in the larger recursive tree.</li>
|
|
76
|
+
<li>Width/height bounded; no TUI overflow.</li>
|
|
77
|
+
<li>Running activity remains live and readable.</li>
|
|
78
|
+
<li>Completed/error states linger briefly in context.</li>
|
|
79
|
+
</ul>
|
|
80
|
+
</div>
|
|
81
|
+
</section>
|
|
82
|
+
|
|
83
|
+
<h2>Design options</h2>
|
|
84
|
+
<div class="grid">
|
|
85
|
+
<article class="card">
|
|
86
|
+
<h3>Mode: Compact tree</h3>
|
|
87
|
+
<div class="terminal"><div class="term-title"><span class="dot" style="background:#ff5f57"></span><span class="dot" style="background:#ffbd2e"></span><span class="dot" style="background:#28c840"></span><span>Agents widget</span></div><span class="accent">● Agents</span>
|
|
88
|
+
├─ <span class="green">⠋</span> <b>Plan</b> split task <span class="dim">· ↻3 · 2 tools · 1m 12s</span>
|
|
89
|
+
│ ├─ <span class="green">⠹</span> <b>Explore</b> inspect UI <span class="dim">· reading…</span>
|
|
90
|
+
│ └─ <span class="yellow">✓</span> <b>auditor</b> review paths <span class="dim">· 42s</span>
|
|
91
|
+
└─ <span class="green">⠼</span> <b>general-purpose</b> write tests <span class="dim">· editing…</span></div>
|
|
92
|
+
<p><b>Use as:</b> configurable mode <code>compact</code>. <b>Pros:</b> dense, low-risk, close to current widget. <b>Cons:</b> less rich for deep trees.</p>
|
|
93
|
+
</article>
|
|
94
|
+
|
|
95
|
+
<article class="card recommended">
|
|
96
|
+
<h3>Mode: Rich tree (default)</h3>
|
|
97
|
+
<div class="terminal"><div class="term-title"><span class="dot" style="background:#ff5f57"></span><span class="dot" style="background:#ffbd2e"></span><span class="dot" style="background:#28c840"></span><span>Agents widget</span></div><span class="accent">● Agents</span> <span class="muted">3 running · 1 queued · depth 3/4</span>
|
|
98
|
+
├─ <span class="green">⠋</span> <b>Plan</b> <span class="purple">opus</span> <span class="muted">split task</span>
|
|
99
|
+
│ <span class="dim">⎿ ↻3≤20 · 4 tools · 22.8k token (38%) · 1m 12s</span>
|
|
100
|
+
│ ├─ <span class="green">⠹</span> <b>Explore</b> <span class="muted">inspect widget data flow</span>
|
|
101
|
+
│ │ <span class="dim">⎿ reading agent-widget.ts · 14.2s</span>
|
|
102
|
+
│ │ └─ <span class="green">⠼</span> <b>general-purpose</b> <span class="muted">trace manager ownership</span>
|
|
103
|
+
│ │ <span class="dim">⎿ searching tests · 4.8s</span>
|
|
104
|
+
│ └─ <span class="yellow">✓</span> <b>auditor</b> <span class="muted">review plan</span> <span class="dim">· 31s</span>
|
|
105
|
+
├─ <span class="cyan">◦</span> <b>Explore</b> <span class="muted">queued after concurrency cap</span>
|
|
106
|
+
└─ <span class="red">✗</span> <b>Plan</b> <span class="muted">old attempt</span> <span class="red">error: model unavailable</span></div>
|
|
107
|
+
<p><b>Use as:</b> configurable mode <code>rich</code>, recommended default. <b>Pros:</b> best visibility; activity/stats are readable; relationships are obvious. <b>Cons:</b> needs careful overflow rules.</p>
|
|
108
|
+
</article>
|
|
109
|
+
|
|
110
|
+
<article class="card">
|
|
111
|
+
<h3>Focused subagent location view</h3>
|
|
112
|
+
<div class="terminal"><div class="term-title"><span class="dot" style="background:#ff5f57"></span><span class="dot" style="background:#ffbd2e"></span><span class="dot" style="background:#28c840"></span><span>Agents widget</span></div><span class="accent">● Agents</span> <span class="muted">7 total · showing active branch</span>
|
|
113
|
+
├─ <span class="green">⠋</span> <b>Plan</b> split task <span class="dim">· 1m 12s</span>
|
|
114
|
+
│ └─ <span class="green">⠹</span> <b>Explore</b> inspect UI <span class="dim">· reading…</span>
|
|
115
|
+
│ └─ <span class="green">⠼</span> <b>general-purpose</b> trace manager <span class="dim">· searching…</span>
|
|
116
|
+
├─ <span class="dim">+2 completed siblings hidden</span>
|
|
117
|
+
└─ <span class="dim">+2 queued / stale descendants hidden</span></div>
|
|
118
|
+
<p><b>Use as:</b> view shown inside a subagent session to answer “where am I in the tree?” It can also become a selectable mode later. <b>Pros:</b> very compact under load.</p>
|
|
119
|
+
</article>
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
<section class="card wide" style="margin-top:18px;">
|
|
123
|
+
<h2>Settled direction so far</h2>
|
|
124
|
+
<p><span class="pill">rich default</span> <span class="pill">compact setting</span> <span class="pill">focused subagent view</span></p>
|
|
125
|
+
<p>Build one recursive tree model, then render it through multiple views. The root TUI widget can use <code>rich</code>, <code>compact</code>, or <code>auto</code>. A subagent-local widget can render the focused path view so the agent/operator sees the current subagent’s location in the whole delegation tree.</p>
|
|
126
|
+
<ul>
|
|
127
|
+
<li><b>Header:</b> aggregate full-tree counts and max observed depth.</li>
|
|
128
|
+
<li><b>Rich node:</b> connector + status icon/spinner + agent type + model/tag chips + description, plus detail line.</li>
|
|
129
|
+
<li><b>Compact node:</b> same tree structure, one line per agent, fewer stats.</li>
|
|
130
|
+
<li><b>Focused node:</b> ancestor path + current active branch + hidden sibling summaries.</li>
|
|
131
|
+
<li><b>Overflow:</b> collapse by subtree: <code>└─ +4 descendants hidden (2 running, 1 queued, 1 finished)</code>.</li>
|
|
132
|
+
<li><b>Fallback:</b> orphan records render under <code>Other agents</code> with a dim warning marker.</li>
|
|
133
|
+
</ul>
|
|
134
|
+
</section>
|
|
135
|
+
</main>
|
|
136
|
+
</body>
|
|
137
|
+
</html>
|
|
Binary file
|