@d3ara1n/pi-subagent 0.3.0 → 0.5.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 CHANGED
@@ -17,7 +17,7 @@ This means:
17
17
  - **Multiple subagents can run in parallel** — emit multiple `delegate` calls in one turn; pi executes them concurrently
18
18
  - **Subagents can nest subagents** — a `worker` can delegate exploration to `explorer` without returning to the main model
19
19
 
20
- > This design intentionally excludes chain pipelines and context-forking — those patterns are better suited when subagents act as advisors (planner, oracle), not executors.
20
+ > This design currently focuses on single-task delegation rather than chain pipelines or context-forking — those patterns fit better when subagents act as advisors (planner, oracle) rather than executors.
21
21
 
22
22
  ## How it works
23
23
 
@@ -47,11 +47,9 @@ This means:
47
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
- ## Requirements
50
+ ## Dependencies
51
51
 
52
- - **@d3ara1n/pi-model-roles** must be installed and configured
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
 
@@ -63,43 +61,44 @@ pi install @d3ara1n/pi-subagent
63
61
 
64
62
  Edit `~/.pi/agent/settings.json`:
65
63
 
66
- ```jsonc
64
+ ```json
67
65
  {
68
66
  "subagent": {
69
- // Default timeout per subagent (5 minutes)
70
- "timeoutMs": 300000,
71
-
72
- // Summary generation — uses a lightweight model to create
73
- // a one-line summary for the TUI display
67
+ "timeout": 600,
68
+ "maxConcurrency": 4,
69
+ "maxDepth": 3,
70
+ "maxTurns": 0,
71
+ "maxCost": 0,
72
+ "history": {
73
+ "enabled": true
74
+ },
74
75
  "summary": {
75
- "role": "utility", // pi-model-roles role for summarization
76
- "enabled": true // set false to disable
76
+ "role": "utility",
77
+ "enabled": true
77
78
  }
78
79
  }
79
80
  }
80
81
  ```
81
82
 
82
- All fields are optional. Defaults: `timeoutMs: 300000`, `summary.role: "utility"`, `summary.enabled: true`.
83
+ All fields are optional. Defaults: `timeout: 600` (seconds; 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
84
 
84
85
  ### Agent Overrides
85
86
 
86
87
  Override, disable, or add subagent roles via `agentOverrides`. Built-in and custom roles are treated equally — all descriptions, examples, and decision triggers feed into the LLM's prompt dynamically.
87
88
 
88
- ```jsonc
89
+ ```json
89
90
  {
90
91
  "subagent": {
91
92
  "agentOverrides": {
92
- // ── Override a built-in role (only specify changed fields) ──
93
93
  "worker": {
94
- "role": "heavy" // use a stronger model
94
+ "role": "heavy",
95
+ "timeout": 600,
96
+ "maxTurns": 50,
97
+ "maxCost": 1.0
95
98
  },
96
-
97
- // ── Disable a built-in role ──
98
99
  "reviewer": {
99
100
  "disabled": true
100
101
  },
101
-
102
- // ── Add a custom role (all required fields must be provided) ──
103
102
  "tester": {
104
103
  "role": "default",
105
104
  "description": "Test automation & QA — write and run tests, validate fixes. Tools: read, bash, edit, write, grep. Can delegate to explorer.",
@@ -118,7 +117,7 @@ Override, disable, or add subagent roles via `agentOverrides`. Built-in and cust
118
117
 
119
118
  **Required fields for custom roles:** `role`, `description`, `examples`, `decisionTrigger`, `tools`, `systemPrompt`.
120
119
 
121
- **Optional fields:** `subagentRoles` (roles this role can spawn via delegate), `fallbackRole` (backup pi-model-roles role on provider errors).
120
+ **Optional fields:** `subagentRoles` (roles this role can spawn via delegate), `timeout` (per-role timeout override in seconds; 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
121
 
123
122
  Invalid custom roles (missing required fields) are silently skipped with an error notification at session start.
124
123
 
@@ -151,6 +150,48 @@ Delegate tasks that would generate many tool calls or verbose output to keep you
151
150
  ]
152
151
  ```
153
152
 
153
+ ### Passing context and reference files
154
+
155
+ pi-subagent delivers context to the child as **independent channels**, never fused into the task string. This keeps the task an unambiguous directive and lets each channel be sized independently.
156
+
157
+ #### `context` (inline text)
158
+
159
+ Hand the subagent precise context — selected code, a prior delegate's result, a file list, a git diff — without inflating the `task` string. It's delivered as a separate channel:
160
+
161
+ ```json
162
+ {
163
+ "role": "worker",
164
+ "task": "Add input validation to the login function",
165
+ "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."
166
+ }
167
+ ```
168
+
169
+ The stored/displayed task stays as the original `task`. When small, `context` inlines as a `<context>` block; when large (over 8,000 chars) it spills to a temp file injected via `@file`, so a large context never drags a short task into a spill.
170
+
171
+ #### `files` (reference paths)
172
+
173
+ ```json
174
+ {
175
+ "role": "explorer",
176
+ "task": "Report the public API of the auth module",
177
+ "files": ["src/auth.ts", "src/auth.types.ts"]
178
+ }
179
+ ```
180
+
181
+ Each path is injected as an independent `@file` attachment the subagent reads directly. **File contents stay out of your context window** — you pass only the paths. Prefer this over pasting file contents into `context`, since the child receives the content on its first turn without spending a tool call to read it.
182
+
183
+ ### Budget enforcement
184
+
185
+ `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`.
186
+
187
+ ### Oversized outputs
188
+
189
+ 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.
190
+
191
+ ### Run history
192
+
193
+ 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`.
194
+
154
195
  ## License
155
196
 
156
197
  MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@d3ara1n/pi-subagent",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
5
  "description": "Role-based subagent orchestration for pi — delegates tasks to specialized pi child processes with configurable model roles",
6
6
  "main": "src/index.ts",
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
- const stripped = content.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
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
- timeoutMs: raw.timeoutMs ?? DEFAULT_CONFIG.timeoutMs,
57
+ timeout: raw.timeout ?? DEFAULT_CONFIG.timeout,
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,