@d3ara1n/pi-subagent 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -12
- package/package.json +2 -1
- package/src/config.ts +9 -2
- package/src/index.ts +411 -237
- package/src/spawn.ts +125 -40
- package/src/types.ts +46 -1
- package/src/utils.test.ts +252 -0
- package/src/utils.ts +263 -0
package/README.md
CHANGED
|
@@ -44,19 +44,17 @@ This means:
|
|
|
44
44
|
## TUI Display
|
|
45
45
|
|
|
46
46
|
- **During execution**: Shows role, elapsed time, turn count, and live tool calls
|
|
47
|
-
- **Collapsed result**: `✓ explorer ·
|
|
47
|
+
- **Collapsed result**: `✓ explorer · Found login, registration, and token logic` + recent tool calls + usage stats
|
|
48
48
|
- **Expanded result** (Ctrl+O): Full task text, all tool calls, final output as rendered Markdown, and usage details
|
|
49
49
|
|
|
50
|
-
##
|
|
50
|
+
## Dependencies
|
|
51
51
|
|
|
52
|
-
-
|
|
53
|
-
- **@earendil-works/pi-tui** — bundled with pi, no separate install needed
|
|
54
|
-
- Role definitions must exist in `modelRoles` settings
|
|
52
|
+
- [`@d3ara1n/pi-model-roles`](../pi-model-roles) — model role resolution
|
|
55
53
|
|
|
56
54
|
## Installation
|
|
57
55
|
|
|
58
56
|
```bash
|
|
59
|
-
pi
|
|
57
|
+
pi install @d3ara1n/pi-subagent
|
|
60
58
|
```
|
|
61
59
|
|
|
62
60
|
## Configuration
|
|
@@ -66,11 +64,30 @@ Edit `~/.pi/agent/settings.json`:
|
|
|
66
64
|
```jsonc
|
|
67
65
|
{
|
|
68
66
|
"subagent": {
|
|
69
|
-
// Default timeout per subagent (
|
|
70
|
-
"timeoutMs":
|
|
67
|
+
// Default timeout per subagent (10 minutes)
|
|
68
|
+
"timeoutMs": 600000,
|
|
69
|
+
|
|
70
|
+
// Max subagents running at once; extras queue with a "queued" TUI hint
|
|
71
|
+
"maxConcurrency": 4,
|
|
72
|
+
|
|
73
|
+
// Max subagent nesting depth (the main session is depth 0).
|
|
74
|
+
// Default 3 covers worker → researcher → explorer chains.
|
|
75
|
+
"maxDepth": 3,
|
|
76
|
+
|
|
77
|
+
// Turn / cost budgets (0 = unlimited). A run is killed once either is hit;
|
|
78
|
+
// partial output is returned with stopReason "budget_exceeded".
|
|
79
|
+
"maxTurns": 0,
|
|
80
|
+
"maxCost": 0,
|
|
81
|
+
|
|
82
|
+
// Audit log: one JSON per delegate run under
|
|
83
|
+
// ~/.pi/subagent/history/{sessionId}/{toolCallId}.json
|
|
84
|
+
"history": {
|
|
85
|
+
"enabled": true
|
|
86
|
+
},
|
|
71
87
|
|
|
72
88
|
// Summary generation — uses a lightweight model to create
|
|
73
|
-
// a one-line
|
|
89
|
+
// a one-line summary for the TUI display.
|
|
90
|
+
// Outputs ≤ 150 chars skip the API call and reuse the text directly.
|
|
74
91
|
"summary": {
|
|
75
92
|
"role": "utility", // pi-model-roles role for summarization
|
|
76
93
|
"enabled": true // set false to disable
|
|
@@ -79,7 +96,7 @@ Edit `~/.pi/agent/settings.json`:
|
|
|
79
96
|
}
|
|
80
97
|
```
|
|
81
98
|
|
|
82
|
-
All fields are optional. Defaults: `timeoutMs:
|
|
99
|
+
All fields are optional. Defaults: `timeoutMs: 600000` (10 min; roles that can `delegate` get 2× automatically when no per-role timeout is set), `maxConcurrency: 4`, `maxDepth: 3`, `maxTurns: 0` (unlimited), `maxCost: 0` (unlimited), `history.enabled: true`, `summary.role: "utility"`, `summary.enabled: true`.
|
|
83
100
|
|
|
84
101
|
### Agent Overrides
|
|
85
102
|
|
|
@@ -91,7 +108,10 @@ Override, disable, or add subagent roles via `agentOverrides`. Built-in and cust
|
|
|
91
108
|
"agentOverrides": {
|
|
92
109
|
// ── Override a built-in role (only specify changed fields) ──
|
|
93
110
|
"worker": {
|
|
94
|
-
"role": "heavy"
|
|
111
|
+
"role": "heavy", // use a stronger model
|
|
112
|
+
"timeoutMs": 600000, // per-role timeout (overrides global)
|
|
113
|
+
"maxTurns": 50, // per-role turn budget (0 = unlimited)
|
|
114
|
+
"maxCost": 1.0 // per-role cost ceiling in USD (0 = unlimited)
|
|
95
115
|
},
|
|
96
116
|
|
|
97
117
|
// ── Disable a built-in role ──
|
|
@@ -118,7 +138,7 @@ Override, disable, or add subagent roles via `agentOverrides`. Built-in and cust
|
|
|
118
138
|
|
|
119
139
|
**Required fields for custom roles:** `role`, `description`, `examples`, `decisionTrigger`, `tools`, `systemPrompt`.
|
|
120
140
|
|
|
121
|
-
**Optional fields:** `subagentRoles` (roles this role can spawn via delegate), `fallbackRole` (backup pi-model-roles role on provider errors).
|
|
141
|
+
**Optional fields:** `subagentRoles` (roles this role can spawn via delegate), `timeoutMs` (per-role timeout override; when unset, delegate-capable roles get 2× the global default automatically), `maxTurns` / `maxCost` (per-role budget overrides; 0 = unlimited), `fallbackRole` (backup pi-model-roles role on provider errors).
|
|
122
142
|
|
|
123
143
|
Invalid custom roles (missing required fields) are silently skipped with an error notification at session start.
|
|
124
144
|
|
|
@@ -151,6 +171,32 @@ Delegate tasks that would generate many tool calls or verbose output to keep you
|
|
|
151
171
|
]
|
|
152
172
|
```
|
|
153
173
|
|
|
174
|
+
### Passing extra context
|
|
175
|
+
|
|
176
|
+
The optional `context` field lets you hand a subagent precise context — selected code, a prior delegate's result, a file list, a git diff — without inflating the `task` string. It's prepended before the task:
|
|
177
|
+
|
|
178
|
+
```json
|
|
179
|
+
{
|
|
180
|
+
"role": "worker",
|
|
181
|
+
"task": "Add input validation to the login function",
|
|
182
|
+
"context": "Current implementation (src/auth.ts:42-70):\n```ts\nasync function login(email, pw) { ... }\n```\nValidation must reject empty/invalid emails and enforce a min 8-char password."
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
The stored/displayed task stays as the original `task`; the `context` is merged into the prompt the subagent receives.
|
|
187
|
+
|
|
188
|
+
### Budget enforcement
|
|
189
|
+
|
|
190
|
+
`maxTurns` / `maxCost` cap a run. When exceeded, the child is killed and the last completed output is returned with `stopReason: "budget_exceeded"` (shown in the expanded TUI). Defaults are unlimited (0); set global defaults in config or per-role via `agentOverrides`.
|
|
191
|
+
|
|
192
|
+
### Oversized outputs
|
|
193
|
+
|
|
194
|
+
When a run's output exceeds the size limit (50,000 chars), pi-subagent first tries to **compress** it with the summary model (same role configured under `summary.role`) into a compact form that preserves conclusions, code, file paths, and errors. If compression fails or doesn't shrink enough, it falls back to mechanical head+tail truncation. The prepared text is what the main model receives and what the expanded TUI renders; a hint line notes which method was used. The **full raw output is always kept in the history file** for auditing.
|
|
195
|
+
|
|
196
|
+
### Run history
|
|
197
|
+
|
|
198
|
+
Every completed delegate run is written (best-effort) to `~/.pi/subagent/history/{sessionId}/{toolCallId}.json`, recording role, task, usage, activity log, and the **full raw output** (even when the main model saw a compressed/truncated version). Useful for auditing what subagents did and how much they cost. Disable with `history.enabled: false`.
|
|
199
|
+
|
|
154
200
|
## License
|
|
155
201
|
|
|
156
202
|
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@d3ara1n/pi-subagent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"type": "module",
|
|
4
5
|
"description": "Role-based subagent orchestration for pi — delegates tasks to specialized pi child processes with configurable model roles",
|
|
5
6
|
"main": "src/index.ts",
|
|
6
7
|
"keywords": [
|
package/src/config.ts
CHANGED
|
@@ -21,8 +21,7 @@ function readSettingsFile(filePath: string): any {
|
|
|
21
21
|
try {
|
|
22
22
|
if (!fs.existsSync(filePath)) return {};
|
|
23
23
|
const content = fs.readFileSync(filePath, "utf-8");
|
|
24
|
-
|
|
25
|
-
return JSON.parse(stripped);
|
|
24
|
+
return JSON.parse(content);
|
|
26
25
|
} catch {
|
|
27
26
|
return {};
|
|
28
27
|
}
|
|
@@ -53,8 +52,16 @@ export function loadSubagentConfig(cwd?: string): SubagentConfig {
|
|
|
53
52
|
if (!raw) return DEFAULT_CONFIG;
|
|
54
53
|
|
|
55
54
|
const rawSummary = raw?.summary;
|
|
55
|
+
const rawHistory = raw?.history;
|
|
56
56
|
return {
|
|
57
57
|
timeoutMs: raw.timeoutMs ?? DEFAULT_CONFIG.timeoutMs,
|
|
58
|
+
maxConcurrency: raw.maxConcurrency ?? DEFAULT_CONFIG.maxConcurrency,
|
|
59
|
+
maxDepth: raw.maxDepth ?? DEFAULT_CONFIG.maxDepth,
|
|
60
|
+
maxTurns: raw.maxTurns ?? DEFAULT_CONFIG.maxTurns,
|
|
61
|
+
maxCost: raw.maxCost ?? DEFAULT_CONFIG.maxCost,
|
|
62
|
+
history: {
|
|
63
|
+
enabled: rawHistory?.enabled ?? DEFAULT_CONFIG.history.enabled,
|
|
64
|
+
},
|
|
58
65
|
summary: {
|
|
59
66
|
role: rawSummary?.role ?? DEFAULT_CONFIG.summary.role,
|
|
60
67
|
enabled: rawSummary?.enabled ?? DEFAULT_CONFIG.summary.enabled,
|