@yefengr/pi-subagents 0.0.0-stage → 0.1.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/CHANGELOG.md +2411 -0
- package/LICENSE +21 -0
- package/README.md +374 -2
- package/UPSTREAM.md +48 -0
- package/dist/public.d.ts +201 -0
- package/dist/settings.d.ts +82 -0
- package/docs/architecture/architecture.md +833 -0
- package/docs/architecture/client-server-opportunities.md +127 -0
- package/docs/architecture/history/phase-1-api-boundary.md +8 -0
- package/docs/architecture/history/phase-10-structural-decomposition.md +141 -0
- package/docs/architecture/history/phase-11-closure-to-class.md +100 -0
- package/docs/architecture/history/phase-12-complexity-test-fixtures.md +55 -0
- package/docs/architecture/history/phase-13-remaining-smells.md +88 -0
- package/docs/architecture/history/phase-14-strip-policy.md +49 -0
- package/docs/architecture/history/phase-15-domain-model-evolution.md +73 -0
- package/docs/architecture/history/phase-16-invert-dependencies.md +144 -0
- package/docs/architecture/history/phase-17-core-consolidation.md +214 -0
- package/docs/architecture/history/phase-18-reconsider-ui.md +166 -0
- package/docs/architecture/history/phase-19-implement-ui-decisions.md +282 -0
- package/docs/architecture/history/phase-2-remove-scheduling.md +9 -0
- package/docs/architecture/history/phase-20-result-delivery.md +245 -0
- package/docs/architecture/history/phase-21-classification-model-boundary.md +107 -0
- package/docs/architecture/history/phase-3-remove-rpc-groupjoin.md +11 -0
- package/docs/architecture/history/phase-4-implement-service.md +8 -0
- package/docs/architecture/history/phase-5-decompose-index.md +42 -0
- package/docs/architecture/history/phase-7-encapsulation.md +173 -0
- package/docs/architecture/history/phase-8-testability.md +103 -0
- package/docs/architecture/history/phase-9-observation-ctx.md +122 -0
- package/docs/comparison-with-upstream.md +79 -0
- package/docs/configuration.md +215 -0
- package/docs/decisions/0001-deferred-patches.md +80 -0
- package/docs/decisions/0002-extensions-on-a-minimal-core.md +114 -0
- package/docs/decisions/0003-publish-bundled-type-declarations.md +71 -0
- package/docs/decisions/0004-reconsider-ui-direction.md +279 -0
- package/index.ts +1 -0
- package/package.json +91 -4
- package/src/config/agent-enablement.ts +132 -0
- package/src/config/agent-types.ts +144 -0
- package/src/config/custom-agents.ts +114 -0
- package/src/config/default-agents.ts +120 -0
- package/src/config/invocation-config.ts +39 -0
- package/src/config/resource-limits.ts +26 -0
- package/src/config/settings-file.ts +174 -0
- package/src/debug.ts +14 -0
- package/src/handlers/index.ts +3 -0
- package/src/handlers/interrupt.ts +58 -0
- package/src/handlers/lifecycle.ts +65 -0
- package/src/handlers/tool-start.ts +32 -0
- package/src/index.ts +257 -0
- package/src/layered-settings.ts +105 -0
- package/src/lifecycle/child-lifecycle.ts +89 -0
- package/src/lifecycle/child-shutdown.ts +105 -0
- package/src/lifecycle/concurrency-limiter.ts +123 -0
- package/src/lifecycle/create-subagent-session.ts +265 -0
- package/src/lifecycle/invocation-control.ts +109 -0
- package/src/lifecycle/lifecycle-record.ts +159 -0
- package/src/lifecycle/parent-snapshot.ts +46 -0
- package/src/lifecycle/run-listeners.ts +41 -0
- package/src/lifecycle/subagent-manager.ts +392 -0
- package/src/lifecycle/subagent-session.ts +287 -0
- package/src/lifecycle/subagent-state.ts +307 -0
- package/src/lifecycle/subagent.ts +854 -0
- package/src/lifecycle/usage.ts +60 -0
- package/src/lifecycle/workspace-bracket.ts +59 -0
- package/src/lifecycle/workspace.ts +47 -0
- package/src/observation/composite-subagent-observer.ts +53 -0
- package/src/observation/notification.ts +233 -0
- package/src/observation/record-observer.ts +78 -0
- package/src/observation/renderer.ts +106 -0
- package/src/observation/subagent-events-observer.ts +75 -0
- package/src/runtime.ts +78 -0
- package/src/service/service-adapter.ts +159 -0
- package/src/service/service.ts +147 -0
- package/src/session/content-items.ts +53 -0
- package/src/session/context.ts +80 -0
- package/src/session/conversation.ts +49 -0
- package/src/session/env.ts +40 -0
- package/src/session/model-resolver.ts +135 -0
- package/src/session/package-exclusions.ts +75 -0
- package/src/session/prompts.ts +145 -0
- package/src/session/provider-inheritance.ts +38 -0
- package/src/session/session-config.ts +177 -0
- package/src/session/session-dir.ts +38 -0
- package/src/settings.ts +436 -0
- package/src/tools/agent-tool.ts +289 -0
- package/src/tools/background-spawner.ts +73 -0
- package/src/tools/foreground-runner.ts +135 -0
- package/src/tools/get-result-report.ts +73 -0
- package/src/tools/get-result-tool.ts +109 -0
- package/src/tools/helpers.ts +134 -0
- package/src/tools/result-renderer.ts +121 -0
- package/src/tools/spawn-config.ts +182 -0
- package/src/tools/steer-tool.ts +120 -0
- package/src/types.ts +145 -0
- package/src/ui/agent-widget.ts +313 -0
- package/src/ui/display.ts +214 -0
- package/src/ui/glyphs.ts +62 -0
- package/src/ui/session-navigation.ts +152 -0
- package/src/ui/session-navigator.ts +257 -0
- package/src/ui/subagents-agents.ts +116 -0
- package/src/ui/subagents-settings.ts +207 -0
- package/src/ui/transcript-content.ts +374 -0
- package/src/ui/widget-renderer.ts +289 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 tintinweb
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,375 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @yefengr/pi-subagents
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[yefengr](https://github.com/yefengr) maintains this [Pi](https://pi.dev) subagent package. It provides an in-process subagent runtime with foreground and background execution, steering, resume, session inspection, lifecycle events, and cross-extension type contracts.
|
|
4
|
+
|
|
5
|
+
The local baseline comes from `@gotgenes/pi-subagents@19.3.4` and has since evolved independently in this repository. See [`UPSTREAM.md`](./UPSTREAM.md) for the exact source, verification records, import boundaries, and local adaptations. Historical differences from the original project and `tintinweb/pi-subagents` are kept in [Comparison with upstream](./docs/comparison-with-upstream.md).
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **In-process & native** — agents run inside the same pi runtime (no spawned subprocesses), sharing tool names, calling conventions, and UI patterns (`subagent`, `get_subagent_result`, `steer_subagent`) — feels native
|
|
10
|
+
- **Parallel background agents** — spawn multiple agents that run concurrently with automatic queuing (configurable concurrency limit, default 4) and individual completion notifications
|
|
11
|
+
- **Live widget UI** — persistent above-editor widget with animated spinners, live tool activity, token counts, and colored status icons
|
|
12
|
+
- **Session transcripts** — open any subagent's full session transcript (running or with its session released) in pi's native read-only viewer via `/subagents:sessions`
|
|
13
|
+
- **Custom agent types** — define agents in `.pi/agents/<name>.md` with YAML frontmatter: custom system prompts, model selection, thinking levels, tool restrictions
|
|
14
|
+
- **Mid-run steering** — inject messages into running agents to redirect their work without restarting
|
|
15
|
+
- **Session resume** — pick up where an agent left off, preserving full conversation context
|
|
16
|
+
- **Bounded invocations** — strict turn and runtime budgets, a reserved wrap-up window, and independent queue deadlines keep every invocation finite
|
|
17
|
+
- **Case-insensitive agent types** — `"explore"`, `"Explore"`, `"EXPLORE"` all work.
|
|
18
|
+
Unknown types fall back to general-purpose with a note
|
|
19
|
+
- **Fuzzy model selection** — specify models by name (`"haiku"`, `"sonnet"`) instead of full IDs, with automatic filtering to only available/configured models
|
|
20
|
+
- **Context inheritance** — optionally fork the parent conversation into a sub-agent so it knows what's been discussed
|
|
21
|
+
- **Styled completion notifications** — background agent results render as themed, compact notification boxes (icon, stats, result preview) instead of raw XML.
|
|
22
|
+
Expandable to show full output
|
|
23
|
+
- **Event bus** — lifecycle events (`subagents:created`, `started`, `completed`, `failed`, `resumed`, `steered`, `compacted`) emitted via `pi.events`, enabling other extensions to react to sub-agent activity
|
|
24
|
+
|
|
25
|
+
## Loading and development
|
|
26
|
+
|
|
27
|
+
Install from npm:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pi install npm:@yefengr/pi-subagents
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Run `/reload` or restart Pi after installation. Other extensions can also depend on this package through `@yefengr/pi-subagents`.
|
|
34
|
+
|
|
35
|
+
When developing directly in the package directory:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm ci
|
|
39
|
+
npm run check
|
|
40
|
+
npm test
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
You can also load the entry explicitly for a development smoke test:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pi -e ./index.ts
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Quick Start
|
|
50
|
+
|
|
51
|
+
The parent agent spawns sub-agents using the `subagent` tool:
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
subagent({
|
|
55
|
+
subagent_type: "Explore",
|
|
56
|
+
prompt: "Find all files that handle authentication",
|
|
57
|
+
description: "Find auth files",
|
|
58
|
+
run_in_background: true,
|
|
59
|
+
})
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Foreground agents block until complete and return results inline. Fresh foreground terminal results include `Agent ID: <id>` so the parent can resume the same agent without a separate lookup.
|
|
63
|
+
Background agents return an ID immediately and notify you on completion.
|
|
64
|
+
|
|
65
|
+
## UI
|
|
66
|
+
|
|
67
|
+
The extension renders a persistent widget above the editor showing active background agents (foreground runs are rendered inline by the `subagent` tool's progress stream):
|
|
68
|
+
|
|
69
|
+
```text
|
|
70
|
+
● Agents
|
|
71
|
+
├─ ⠹ Agent Refactor auth module · ↻5≤30 · 5 tool uses · 33.8k token (62%) · 12.3s
|
|
72
|
+
│ ⎿ editing 2 files…
|
|
73
|
+
├─ ⠹ Explore Find auth files · ↻3 · 3 tool uses · 12.4k token (8%) · 4.1s
|
|
74
|
+
│ ⎿ searching…
|
|
75
|
+
├─ ⠹ Agent Long-running task · ↻42 · 38 tool uses · 91.0k token (84% · ⇊2) · 2m17s
|
|
76
|
+
│ ⎿ reading…
|
|
77
|
+
└─ 2 queued
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The token field is annotated with two optional signals inside parens:
|
|
81
|
+
|
|
82
|
+
- **`NN%`** — context-window utilization (color-coded: <70% dim, 70–85% warning, ≥85% error).
|
|
83
|
+
Omitted when the model has no declared `contextWindow`, or briefly right after compaction.
|
|
84
|
+
- **`⇊N`** — number of times the session has compacted, when > 0.
|
|
85
|
+
Stays dim; the percent's color carries urgency.
|
|
86
|
+
|
|
87
|
+
Individual agent results render inline in the conversation:
|
|
88
|
+
|
|
89
|
+
| Phase / outcome | Example |
|
|
90
|
+
| --------------- | --------------------------------------------------------------------- |
|
|
91
|
+
| **Running** | `⠹ ↻3≤30 · 3 tool uses · 12.4k token (8%)` / `⎿ searching…` |
|
|
92
|
+
| **Completed** | `✓ ↻8 · 5 tool uses · 33.8k token (62%) · 12.3s` / `⎿ Done` |
|
|
93
|
+
| **Turn limit** | `✗ ↻30≤30 · 5 tool uses · 33.8k token` / `⎿ Turn limit reached` |
|
|
94
|
+
| **Timed out** | `✗ ↻3 · 3 tool uses · 12.4k token` / `⎿ Invocation timed out` |
|
|
95
|
+
| **Cancelled** | `✗ ↻3 · 3 tool uses · 12.4k token` / `⎿ Cancelled` |
|
|
96
|
+
| **Queue timeout** | `✗` / `⎿ Queue wait timed out before execution` |
|
|
97
|
+
|
|
98
|
+
Completed results can be expanded (ctrl+o in pi) to show the full agent output inline.
|
|
99
|
+
|
|
100
|
+
Background agent completion notifications render as styled boxes:
|
|
101
|
+
|
|
102
|
+
```text
|
|
103
|
+
✓ Find auth files completed
|
|
104
|
+
↻3 · 3 tool uses · 12.4k token · 4.1s
|
|
105
|
+
⎿ Found 5 files related to authentication...
|
|
106
|
+
transcript: .pi/output/agent-abc123.jsonl
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The LLM receives structured `<task-notification>` XML for parsing, while the user sees the themed visual.
|
|
110
|
+
|
|
111
|
+
## Tools
|
|
112
|
+
|
|
113
|
+
### `subagent`
|
|
114
|
+
|
|
115
|
+
Launch a sub-agent.
|
|
116
|
+
|
|
117
|
+
| Parameter | Type | Required | Description |
|
|
118
|
+
| ------------------- | ------------ | -------- | ---------------------------------------------------------------- |
|
|
119
|
+
| `prompt` | string | yes | The task for the agent |
|
|
120
|
+
| `description` | string | yes | Short 3-5 word summary (shown in UI) |
|
|
121
|
+
| `subagent_type` | string | yes | Agent type (built-in or custom) |
|
|
122
|
+
| `model` | string | no | Model — `provider/modelId` or fuzzy name (`"haiku"`, `"sonnet"`) |
|
|
123
|
+
| `thinking` | string | no | Thinking level: off, minimal, low, medium, high, xhigh |
|
|
124
|
+
| `max_turns` | integer | no | Strict hard maximum for model turns; can only tighten the configured limit |
|
|
125
|
+
| `wrap_up_turns` | integer | no | Turns reserved within `max_turns` for a final response; defaults from the profile or global setting |
|
|
126
|
+
| `max_duration_seconds` | integer | no | Execution-time limit in seconds; can only tighten the configured limit |
|
|
127
|
+
| `run_in_background` | boolean | no | Run without blocking |
|
|
128
|
+
| `resume` | string | no | Agent ID to resume a previous session |
|
|
129
|
+
| `inherit_context` | boolean | no | Fork parent conversation into agent |
|
|
130
|
+
|
|
131
|
+
### `get_subagent_result`
|
|
132
|
+
|
|
133
|
+
Check status and retrieve results from a background agent.
|
|
134
|
+
|
|
135
|
+
| Parameter | Type | Required | Description |
|
|
136
|
+
| ---------- | ------- | -------- | ----------------------------- |
|
|
137
|
+
| `agent_id` | string | yes | Agent ID to check |
|
|
138
|
+
| `wait` | boolean | no | Wait for completion |
|
|
139
|
+
| `verbose` | boolean | no | Include full conversation log |
|
|
140
|
+
|
|
141
|
+
### `steer_subagent`
|
|
142
|
+
|
|
143
|
+
Send a steering message to a running agent.
|
|
144
|
+
The message interrupts after the current tool execution.
|
|
145
|
+
|
|
146
|
+
| Parameter | Type | Required | Description |
|
|
147
|
+
| ---------- | ------ | -------- | ----------------------------------------- |
|
|
148
|
+
| `agent_id` | string | yes | Agent ID to steer |
|
|
149
|
+
| `message` | string | yes | Message to inject into agent conversation |
|
|
150
|
+
|
|
151
|
+
## Commands
|
|
152
|
+
|
|
153
|
+
| Command | Description |
|
|
154
|
+
| --------------------- | ----------------------------------------------------------------------------------- |
|
|
155
|
+
| `/subagents:settings` | Configure concurrency, resource budgets, retention, and interrupt policy |
|
|
156
|
+
| `/subagents:sessions` | View a subagent's session transcript (read-only) |
|
|
157
|
+
|
|
158
|
+
### `/subagents:agents`
|
|
159
|
+
|
|
160
|
+
List all built-in and custom agent types, including disabled types. Select an agent to inspect its definition and choose whether to enable or disable it in the current project or globally. The reset action removes the selected layer's override: project settings then follow global settings, while global settings return to the default enabled state. Project settings take precedence over global settings. Global agent overrides are stored in the untracked `~/.pi/agent/subagents.local.json`; shared runtime settings remain in `~/.pi/agent/subagents.json`.
|
|
161
|
+
|
|
162
|
+
### `/subagents:settings`
|
|
163
|
+
|
|
164
|
+
Interactive list to tune max concurrency, max turns, reserved wrap-up turns, maximum execution duration, maximum queue wait, abort grace, the two session-retention windows, and whether ESC aborts every subagent.
|
|
165
|
+
The numeric settings open an input prompt; the abort-on-ESC entry is a direct flip.
|
|
166
|
+
Changes persist across pi restarts (see [Persistent Settings](./docs/configuration.md#persistent-settings)).
|
|
167
|
+
|
|
168
|
+
### `/subagents:sessions`
|
|
169
|
+
|
|
170
|
+
Pick any subagent — running, or completed with its live session already released — and read its full session transcript in pi's native per-entry viewer.
|
|
171
|
+
Read-only: no steering, no session takeover (steering lives in the `steer_subagent` tool and the background widget).
|
|
172
|
+
|
|
173
|
+
Creating and editing agent definitions is not a command — write an agent `.md` file in your editor, or ask a pi session to generate one (see [Custom Agents](./docs/configuration.md#custom-agents)).
|
|
174
|
+
|
|
175
|
+
## Resource Limits
|
|
176
|
+
|
|
177
|
+
Every invocation has finite limits. The defaults are `max_turns: 30`, `wrap_up_turns: 2`, `max_duration_seconds: 1800`, `max_queue_wait_seconds: 900`, and `abort_grace_seconds: 5`.
|
|
178
|
+
|
|
179
|
+
`max_turns` is a strict hard maximum: the runtime never intentionally starts model turn `max_turns + 1`. `wrap_up_turns` is reserved **within** that maximum, not added to it. When the child still needs another model turn in the reserved window, it receives a final-response instruction; a child with no remaining reserved turns stops at the hard maximum.
|
|
180
|
+
|
|
181
|
+
Profile and invocation values for `max_turns` and `max_duration_seconds` can only tighten the global ceiling. The effective value is the smallest valid value from global settings, profile frontmatter, and tool call. The wrap-up window uses invocation, then profile, then global precedence and is clamped to `0..max_turns - 1`.
|
|
182
|
+
|
|
183
|
+
The execution clock starts when a child is admitted to run and includes workspace preparation, session construction, model calls, and tools. Background queue time is excluded from that clock and bounded separately. A queue timeout becomes terminal without starting a child session. On an execution timeout or cancellation, the runtime requests cooperative abort and releases the parent waiter and concurrency slot after `abort_grace_seconds` if the child remains unsettled; tools that ignore `AbortSignal` cannot be forcibly terminated inside this shared process. A terminal cancellation cannot be resumed until its prior turn loop has settled.
|
|
184
|
+
|
|
185
|
+
## Concurrency
|
|
186
|
+
|
|
187
|
+
Background agents are subject to a configurable concurrency limit (default: 4).
|
|
188
|
+
Excess agents are queued and start as slots free. Each queued agent has an independent maximum wait (default: 900 seconds); when it expires, the agent reaches the `queue_timeout` terminal outcome without executing.
|
|
189
|
+
The widget shows queued agents as a collapsed count.
|
|
190
|
+
|
|
191
|
+
Foreground agents bypass the queue — they block the parent anyway.
|
|
192
|
+
|
|
193
|
+
Stopping a still-queued agent produces the same completion notification a running agent's stop does.
|
|
194
|
+
Because that agent never started, the notification says so and offers no result to collect.
|
|
195
|
+
|
|
196
|
+
## Child session lifecycle
|
|
197
|
+
|
|
198
|
+
A child session runs in the parent's process but is a full Pi session with its own extension set.
|
|
199
|
+
It receives the standard pair of session lifecycle events:
|
|
200
|
+
|
|
201
|
+
| Event | When | Reason |
|
|
202
|
+
| ------------------ | --------------------------------------------------- | ----------- |
|
|
203
|
+
| `session_start` | Extensions are bound, before the child's first turn | `"startup"` |
|
|
204
|
+
| `session_shutdown` | The child session is disposed | `"quit"` |
|
|
205
|
+
|
|
206
|
+
Disposal happens when the retention window for a finished agent expires, when completed records are cleared at session start or switch, when the parent session shuts down, or when child extension binding fails partway.
|
|
207
|
+
It does **not** happen the moment an agent finishes: the session is retained so the agent can be resumed, per the `consumedSessionRetentionMinutes` and `unconsumedSessionRetentionMinutes` settings above. The lightweight subagent record retains the child `sessionId` and optional `outputFile` even after the heavy session object is released.
|
|
208
|
+
|
|
209
|
+
The shutdown event is dispatched and awaited **before** the child's `AgentSession` is disposed, so a handler still has a live context and can close what it opened — stdio subprocesses, sockets, timers, file handles.
|
|
210
|
+
Each child's shutdown is bounded: a handler that never resolves is abandoned after a few seconds and disposal proceeds, so one misbehaving extension cannot stall the parent's teardown or Pi's exit.
|
|
211
|
+
|
|
212
|
+
If you author an extension that runs in children, note that its `session_shutdown` handler now fires **once per child session** in addition to once for the parent.
|
|
213
|
+
A handler that flushes a log, writes a summary, or closes a shared resource should be safe to run repeatedly within one process.
|
|
214
|
+
Before this behavior existed, children fired `session_start` with no matching shutdown, so extension-owned resources accumulated for the life of the parent process.
|
|
215
|
+
|
|
216
|
+
## Events
|
|
217
|
+
|
|
218
|
+
Agent lifecycle events are emitted via `pi.events.emit()` so other extensions can react. Agent events use lifecycle record v3; earlier payload shapes are not supported.
|
|
219
|
+
|
|
220
|
+
Every v3 payload contains `recordVersion: 3`, agent identity, `phase` (`queued`, `running`, or `terminal`), terminal `outcome` when applicable (`completed`, `turn_limit`, `timeout`, `queue_timeout`, `cancelled`, or `error`), invocation identity (`invocationKind`, `invocationSource`, `invocationIndex`, and tool-driven `toolCallId`), effective resource limits, separate invocation/lifetime turn counts and usage, and explicit session state. `sessionId` is mandatory once a child session exists. `sessionState: "not-created"` is reserved for a pre-session error, queued cancellation, or queue timeout. `outputFile` is optional diagnostic information, not the session attribution key.
|
|
221
|
+
|
|
222
|
+
| Event | When | Additional fields / behavior |
|
|
223
|
+
| ---------------------------- | ------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
|
|
224
|
+
| `subagents:created` | Background agent registered | v3 snapshot before limiter admission; not persisted |
|
|
225
|
+
| `subagents:started` | Agent enters `running`, including queue admission | v3 snapshot; not persisted |
|
|
226
|
+
| `subagents:completed` | Fresh invocation reaches `completed` | terminal v3 payload; exact same object is persisted as `subagents:record` |
|
|
227
|
+
| `subagents:failed` | Fresh invocation has any non-completed terminal outcome | terminal v3 payload; exact same object is persisted as `subagents:record` |
|
|
228
|
+
| `subagents:resumed` | Resume invocation reaches a terminal outcome | terminal v3 payload with the current resume `toolCallId`; exact same object is persisted |
|
|
229
|
+
| `subagents:steered` | Steering message accepted | v3 snapshot plus `instruction`; steering stays inside the current invocation |
|
|
230
|
+
| `subagents:compacted` | Agent's session successfully compacted | v3 snapshot plus `reason`, `tokensBefore`, and `compactionCount` |
|
|
231
|
+
| `subagents:settings_loaded` | Persisted settings applied at extension init | `settings` (merged global + project) |
|
|
232
|
+
| `subagents:settings_changed` | `/subagents:settings` mutation was applied | `settings`, `persisted` (`boolean`; `false` on write failure) |
|
|
233
|
+
|
|
234
|
+
`invocationUsage.total` and `lifetimeUsage.total` equal `input + output + cacheWrite`. `cacheRead` is excluded because each turn reports the cumulative cached prefix re-read on that API call. A fresh run and every resume open a zeroed invocation window while preserving lifetime totals, so prior turns, tools, duration, and usage cannot consume the new invocation's budget.
|
|
235
|
+
|
|
236
|
+
## Worktree Isolation
|
|
237
|
+
|
|
238
|
+
Worktree isolation lives in a companion package, not this core.
|
|
239
|
+
Install [`@gotgenes/pi-subagents-worktrees`](https://github.com/gotgenes/pi-packages/tree/main/packages/pi-subagents-worktrees) and list the agent types you want isolated in its `worktreeAgents` config — opted-in agents run in a temporary git worktree, and their changes are saved to a branch on completion.
|
|
240
|
+
The earlier `isolation: "worktree"` spawn flag and `isolation:` frontmatter key were removed from the core.
|
|
241
|
+
|
|
242
|
+
## Removed: agent memory and skill preloading
|
|
243
|
+
|
|
244
|
+
Persistent agent memory (the `memory:` frontmatter key) and skill preloading (the `skills:` frontmatter key) were removed when the core was slimmed down.
|
|
245
|
+
Children inherit the parent's skills and extensions by default, so the `isolated`, `extensions`, and `skills` frontmatter keys no longer exist.
|
|
246
|
+
Package-level extension opt-outs live in the [`excludedExtensionPackages`](./docs/configuration.md#excluding-package-extensions-from-children) setting rather than agent frontmatter.
|
|
247
|
+
|
|
248
|
+
## Migrating from `disallowed_tools`
|
|
249
|
+
|
|
250
|
+
The `disallowed_tools` frontmatter field has been removed.
|
|
251
|
+
Use [`@gotgenes/pi-permission-system`](https://github.com/gotgenes/pi-permission-system)'s `permission:` frontmatter instead — it provides richer semantics (allow/ask/deny vs. binary hide):
|
|
252
|
+
|
|
253
|
+
```yaml
|
|
254
|
+
# Before (no longer supported)
|
|
255
|
+
disallowed_tools: bash
|
|
256
|
+
|
|
257
|
+
# After
|
|
258
|
+
permission:
|
|
259
|
+
bash: deny
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## Permission System Integration
|
|
263
|
+
|
|
264
|
+
When [`@gotgenes/pi-permission-system`](https://github.com/gotgenes/pi-permission-system) is installed, this extension integrates automatically:
|
|
265
|
+
|
|
266
|
+
- **Per-agent permission policies** — define `permission:` in agent YAML frontmatter to set allow/ask/deny rules per agent type.
|
|
267
|
+
The permission system resolves the agent name from the `<active_agent>` tag in the child system prompt.
|
|
268
|
+
- **Tool filtering** — the permission system's `before_agent_start` handler removes denied tools from the child session before the agent starts.
|
|
269
|
+
- **`ask`-state forwarding** — when a child session triggers an `ask` permission, the prompt forwards to the parent session's UI.
|
|
270
|
+
The parent approves or denies, and the child resumes.
|
|
271
|
+
- **Deterministic child detection** — this extension publishes `subagents:child:session-created` before `bindExtensions()` fires; the permission system subscribes and registers the child session synchronously, so detection does not rely on env vars or filesystem heuristics.
|
|
272
|
+
|
|
273
|
+
No configuration is required.
|
|
274
|
+
When `@gotgenes/pi-permission-system` is not installed, the lifecycle events have no subscriber — a harmless no-op.
|
|
275
|
+
|
|
276
|
+
## For Extension Authors
|
|
277
|
+
|
|
278
|
+
This package exposes two public subpath exports for companion extensions. `npm pack` verifies that its declarations are independently consumable.
|
|
279
|
+
|
|
280
|
+
### `@yefengr/pi-subagents` — cross-extension service contract
|
|
281
|
+
|
|
282
|
+
Access the subagent service from another extension at runtime:
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
const { getSubagentsService } = await import("@yefengr/pi-subagents");
|
|
286
|
+
const svc = getSubagentsService();
|
|
287
|
+
svc?.spawn("Explore", "Check for stale TODOs");
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Declare this package as an optional peer dependency.
|
|
291
|
+
See `src/service/service.ts` for the full `SubagentsService` interface and the `WorkspaceProvider` seam.
|
|
292
|
+
|
|
293
|
+
### `@yefengr/pi-subagents/settings` — layered config loader
|
|
294
|
+
|
|
295
|
+
Extensions that store configuration in JSON files can use the shared layered loader, which reads a global file (`<agentDir>/<filename>`) and a project file (`<cwd>/.pi/<filename>`) and merges them — project wins on conflicts, missing files are silent, malformed files warn and fall back:
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
import { loadLayeredSettings, type LayeredSettingsSource } from "@yefengr/pi-subagents/settings";
|
|
299
|
+
|
|
300
|
+
interface MyConfig { enabled?: boolean; limit?: number }
|
|
301
|
+
|
|
302
|
+
function sanitize(raw: unknown): Partial<MyConfig> {
|
|
303
|
+
if (!raw || typeof raw !== "object") return {};
|
|
304
|
+
const r = raw as Record<string, unknown>;
|
|
305
|
+
const out: Partial<MyConfig> = {};
|
|
306
|
+
if (typeof r.enabled === "boolean") out.enabled = r.enabled;
|
|
307
|
+
if (typeof r.limit === "number") out.limit = r.limit;
|
|
308
|
+
return out;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const config = loadLayeredSettings<MyConfig>({
|
|
312
|
+
agentDir, // Pi runtime agent home directory
|
|
313
|
+
cwd, // project root — project file lives at <cwd>/.pi/<filename>
|
|
314
|
+
filename: "my-extension.json",
|
|
315
|
+
sanitize,
|
|
316
|
+
warnLabel: "my-extension", // prefix for the malformed-file stderr warning
|
|
317
|
+
});
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
`loadLayeredSettings` returns `Partial<T>` (all fields optional); apply your defaults after the call.
|
|
321
|
+
It never throws — all error conditions produce a `console.warn` and return `{}`.
|
|
322
|
+
|
|
323
|
+
## Scope and non-goals
|
|
324
|
+
|
|
325
|
+
**Purpose.**
|
|
326
|
+
A minimal, in-process sub-agent core.
|
|
327
|
+
It spawns a child session derived from the parent, runs the turn loop, streams and collects the result, gates concurrency, supports resume, and publishes its lifecycle.
|
|
328
|
+
Everything else is a consumer.
|
|
329
|
+
|
|
330
|
+
**In scope.**
|
|
331
|
+
Defects in the surfaces the core already owns, completeness of the public lifecycle-event contract, and internal work toward the minimal-core target.
|
|
332
|
+
Anything attaching to the core either subscribes to a lifecycle event, or registers a provider if it must return a value the core consumes — see [ADR-0002](./docs/decisions/0002-extensions-on-a-minimal-core.md).
|
|
333
|
+
|
|
334
|
+
**Non-goals.**
|
|
335
|
+
|
|
336
|
+
- _Capability the fork deliberately left behind._
|
|
337
|
+
Scheduling, cross-extension RPC, model-scope enforcement, and a built-in tool denylist belong to upstream — see [Relationship to upstream](#relationship-to-upstream).
|
|
338
|
+
- _Policy about what a child may do._
|
|
339
|
+
Tool restriction is allow/ask/deny in a permission layer, not a binary hide in a spawner — see [Migrating from `disallowed_tools`](#migrating-from-disallowed_tools).
|
|
340
|
+
- _Widening a child's tool allowlist on the agent's behalf._
|
|
341
|
+
An agent's `tools:` frontmatter is the complete allowlist and the only mechanism that widens it, because a settings-level list would hand a read-only `Explore` agent write-capable tools from a file its author never saw.
|
|
342
|
+
- _A global run-mode default._
|
|
343
|
+
Foreground or background is a per-invocation argument and a per-agent frontmatter key; a global flip changes every existing agent file at once.
|
|
344
|
+
- _Provider seams with no consumer._
|
|
345
|
+
A seam nobody supplies is a speculative abstraction that taxes every reader; the architecture may admit one without shipping it until a real consumer exists.
|
|
346
|
+
|
|
347
|
+
The [architecture doc](./docs/architecture/architecture.md#scope-and-non-goals) carries the full inventory, including the removed UI surfaces and the reasoning behind each.
|
|
348
|
+
|
|
349
|
+
**Where adjacent requests belong.**
|
|
350
|
+
Tool restriction and per-agent permission policy → [@gotgenes/pi-permission-system](https://www.npmjs.com/package/@gotgenes/pi-permission-system).
|
|
351
|
+
Worktree isolation → [@gotgenes/pi-subagents-worktrees](https://www.npmjs.com/package/@gotgenes/pi-subagents-worktrees).
|
|
352
|
+
Timed dispatch, telemetry, and alternate UIs → a consumer over the lifecycle events and the typed service.
|
|
353
|
+
A batteries-included alternative → upstream [`tintinweb/pi-subagents`](https://github.com/tintinweb/pi-subagents).
|
|
354
|
+
|
|
355
|
+
## Documentation
|
|
356
|
+
|
|
357
|
+
| Document | Contents |
|
|
358
|
+
| -------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
359
|
+
| [Configuration](./docs/configuration.md) | Default agent types, custom agent files and their frontmatter fields, and the `subagents.json` settings file |
|
|
360
|
+
| [Architecture](./docs/architecture/architecture.md) | Design principles, domain decomposition, module dependency flow, Mermaid diagrams, and the improvement roadmap |
|
|
361
|
+
| [Comparison with upstream](./docs/comparison-with-upstream.md) | Feature-by-feature comparison against the current upstream release |
|
|
362
|
+
|
|
363
|
+
## Architecture
|
|
364
|
+
|
|
365
|
+
This extension is a minimal, composable core: it owns agent spawning, execution, and result retrieval, and exposes a typed `SubagentsService` plus lifecycle events that other extensions build on.
|
|
366
|
+
|
|
367
|
+
## Relationship to upstream
|
|
368
|
+
|
|
369
|
+
This package starts from the verified `@gotgenes/pi-subagents@19.3.4` source baseline and is maintained independently in this repository. That source was itself a hard fork of [`tintinweb/pi-subagents`](https://github.com/tintinweb/pi-subagents). See [`UPSTREAM.md`](./UPSTREAM.md) for the exact tag, commit, integrity evidence and import policy.
|
|
370
|
+
|
|
371
|
+
The imported comparison and decision documents describe the state of the `19.3.4` baseline. They are retained as design history and must not be treated as a promise to track later third-party releases.
|
|
372
|
+
|
|
373
|
+
## License
|
|
374
|
+
|
|
375
|
+
MIT — [tintinweb](https://github.com/tintinweb) (upstream) and [Chris Lasher](https://github.com/gotgenes) (fork)
|
package/UPSTREAM.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# 上游来源
|
|
2
|
+
|
|
3
|
+
`packages/pi-subagents/` 由本仓库以 `@yefengr/pi-subagents` 独立维护,不在运行时依赖上游子代理 npm 包。
|
|
4
|
+
|
|
5
|
+
## 基线
|
|
6
|
+
|
|
7
|
+
- 上游仓库:[`gotgenes/pi-packages`](https://github.com/gotgenes/pi-packages)
|
|
8
|
+
- 上游目录:`packages/pi-subagents`
|
|
9
|
+
- npm 包:`@gotgenes/pi-subagents@19.3.4`
|
|
10
|
+
- Git 标签:`pi-subagents-v19.3.4`
|
|
11
|
+
- Git 提交:`b330769ec96928479941543d196eeafcbc6489d0`
|
|
12
|
+
- npm tarball SHA-1:`43fc057ead921e33b9fd544df81d1f2d257b0b01`
|
|
13
|
+
- 许可证:MIT,原始版权声明保留在 [`LICENSE`](./LICENSE)
|
|
14
|
+
|
|
15
|
+
GitHub 标签、npm Registry 的 SLSA provenance 和 npm tarball 均指向或验证了上述提交。本地迁移前还逐文件核对了 npm tarball 与已安装的 `19.3.4`:两者均为 95 个文件且内容完全一致。tarball 与上游提交的共同文件中,除发布流程生成的 `package.json` 外内容一致;`dist/public.d.ts` 和 `dist/settings.d.ts` 是构建产物。
|
|
16
|
+
|
|
17
|
+
## 迁入范围
|
|
18
|
+
|
|
19
|
+
迁入:
|
|
20
|
+
|
|
21
|
+
- 完整 `src/` 与 `test/`。
|
|
22
|
+
- npm 发布范围内的 README、CHANGELOG、配置、架构与决策文档。
|
|
23
|
+
- 类型声明构建、公开类型验证和 Vitest 配置。
|
|
24
|
+
- 原始 MIT LICENSE。
|
|
25
|
+
|
|
26
|
+
不迁入:
|
|
27
|
+
|
|
28
|
+
- 上游仓库级配置、workspace、lockfile 和共享脚本。
|
|
29
|
+
- 上游 `.pi/`、`AGENTS.md` 等开发 harness 配置。
|
|
30
|
+
- 上游 `docs/plans/`、`docs/retro/`、媒体文件及其他历史开发产物。
|
|
31
|
+
- `node_modules/` 与生成的 `dist/`。
|
|
32
|
+
|
|
33
|
+
## 本地适配
|
|
34
|
+
|
|
35
|
+
- 包名改为 `agent-tools-subagents`,版本从 `0.1.0` 独立演进,并设置为 private,避免误发布。
|
|
36
|
+
- 使用 npm 和 package-local lockfile,不依赖上游 pnpm workspace 或 catalog。
|
|
37
|
+
- `tsconfig.json`、Biome 配置和测试入口改为自包含;不迁入上游 monorepo 的 ESLint、rumdl、fallow 与 release 工具链,本地门禁为 Biome、TypeScript、完整 Vitest、声明构建和打包后消费者类型检查。
|
|
38
|
+
- Pi 核心包以 peer dependency 声明,开发验证固定到当前仓库使用的 Pi `0.85.1`。
|
|
39
|
+
- 工具 schema 从旧 `@sinclair/typebox` 切换到 Pi 当前提供的 `typebox` peer。
|
|
40
|
+
- Pi `0.85.1` 已以 `ModelRuntime` 取代 `createAgentSession()` 的旧 `modelRegistry` 参数;本地实现创建独立 child runtime,并参考后续上游修复提交 [`f805ffc4a6ae1849c4d396cd7697f09ea38b6ec6`](https://github.com/gotgenes/pi-packages/commit/f805ffc4a6ae1849c4d396cd7697f09ea38b6ec6) 复制父会话运行时 provider 注册。
|
|
41
|
+
- 跨扩展 service key 与文档示例使用本地包身份,不提供旧包名兼容入口。
|
|
42
|
+
- 生命周期公共事件与 `subagents:record` 持久化改为本项目唯一支持的 v2 契约:稳定 `sessionId`、逐调用身份、逐调用 usage/tool-use 窗口和 lifetime 累计分层,不兼容旧 payload。
|
|
43
|
+
- fresh/resume 的父工具调用分别记录当次 `toolCallId`;service 调用使用显式 `invocationSource: "service"`,不伪造工具调用 ID。
|
|
44
|
+
- 公开类型验证改用 npm,并在临时消费者中验证打包后的声明文件。
|
|
45
|
+
|
|
46
|
+
后续同步上游时必须重新核对许可证、来源提交、实际差异和本地契约;不得直接用上游最新 HEAD 覆盖本地实现。
|
|
47
|
+
- 2026-10 迁出 agent-tools,以当前包名 `@yefengr/pi-subagents` 发布到 npm,取消 private;版本从 `0.1.0` 继续独立演进,跨扩展服务身份为 `@yefengr/pi-subagents:service`,命令前缀和事件命名空间统一为 `subagents:`,配置文件名 `subagents.json` 保持不变。
|
|
48
|
+
- 开发验证基线升级到 Pi `1.4.0` 与 `typebox` `1.3.27`,与当前运行环境一致;host 包仍以 `*` 声明 peer。
|
package/dist/public.d.ts
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { ThinkingLevel } from '@earendil-works/pi-ai';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* types.ts — Type definitions for the subagent system.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** Agent type: any string name (built-in defaults or user-defined). */
|
|
8
|
+
type SubagentType = string;
|
|
9
|
+
interface AgentInvocation {
|
|
10
|
+
/** Short display name, e.g. "haiku" — only set when different from parent. */
|
|
11
|
+
modelName?: string;
|
|
12
|
+
thinking?: ThinkingLevel;
|
|
13
|
+
maxTurns?: number;
|
|
14
|
+
wrapUpTurns?: number;
|
|
15
|
+
maxDurationSeconds?: number;
|
|
16
|
+
inheritContext?: boolean;
|
|
17
|
+
runInBackground?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** Identifies the parent invocation currently driving a subagent turn. */
|
|
20
|
+
type SubagentInvocationIdentity = {
|
|
21
|
+
kind: "fresh" | "resume";
|
|
22
|
+
source: "tool";
|
|
23
|
+
toolCallId: string;
|
|
24
|
+
} | {
|
|
25
|
+
kind: "fresh" | "resume";
|
|
26
|
+
source: "service";
|
|
27
|
+
toolCallId?: never;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/** usage.ts — Token usage: shapes, accumulator operators, session-stats readers. */
|
|
31
|
+
/**
|
|
32
|
+
* Lifetime usage components, accumulated via `message_end` events. Survives
|
|
33
|
+
* compaction (which replaces session.state.messages and would reset any
|
|
34
|
+
* stats-derived sum). cacheRead is excluded because each turn's cacheRead is
|
|
35
|
+
* the cumulative cached prefix re-read on that one call — summing across
|
|
36
|
+
* turns counts the prefix N times. See issue #38.
|
|
37
|
+
*/
|
|
38
|
+
type LifetimeUsage = {
|
|
39
|
+
input: number;
|
|
40
|
+
output: number;
|
|
41
|
+
cacheWrite: number;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* subagent-state.ts — SubagentState value object: lifecycle phase/outcome, metrics, and live activity.
|
|
46
|
+
*
|
|
47
|
+
* Owns the passive, readable state of a subagent — phase, outcome, result, error,
|
|
48
|
+
* timestamps, lifetime and current-invocation metrics, compactionCount, and
|
|
49
|
+
* live-activity fields (invocation/lifetime turn counts, activeTools, responseText) — together with the transition
|
|
50
|
+
* methods (markRunning, markCompleted, …), accumulation methods
|
|
51
|
+
* (incrementToolUses, addUsage, incrementCompactions), and live-activity
|
|
52
|
+
* transition methods (incrementTurnCount, addActiveTool, removeActiveTool,
|
|
53
|
+
* resetResponseText, appendResponseText) that mutate them.
|
|
54
|
+
*
|
|
55
|
+
* State is encapsulated behind getters; external code reads through them but
|
|
56
|
+
* mutates only via the transition/accumulation methods. The value object owns
|
|
57
|
+
* all of its own mutations — no field is written from outside.
|
|
58
|
+
*
|
|
59
|
+
* Subagent holds one of these privately and delegates its getters and mutation
|
|
60
|
+
* methods to it. Extracting it lets the lifecycle state machine and the
|
|
61
|
+
* session-event observer be unit-tested without constructing an executor.
|
|
62
|
+
*/
|
|
63
|
+
|
|
64
|
+
type SubagentPhase = "queued" | "running" | "terminal";
|
|
65
|
+
type SubagentOutcome = "completed" | "turn_limit" | "timeout" | "queue_timeout" | "cancelled" | "error";
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* workspace.ts — The single generative extension seam (ADR 0002, Phase 16 Step 2).
|
|
69
|
+
*
|
|
70
|
+
* "Where does a child run, and what brackets the run?" is a strategy (git
|
|
71
|
+
* worktree, container, tmpdir, remote sandbox), not core behavior. The core
|
|
72
|
+
* needs only a working directory plus a disposal hook; the default — the
|
|
73
|
+
* parent's cwd, with no setup/teardown — is always correct.
|
|
74
|
+
*
|
|
75
|
+
* Unlike the observational lifecycle events in child-lifecycle.ts, this is a
|
|
76
|
+
* *generative* seam: a registered provider returns a value the core consumes
|
|
77
|
+
* synchronously at run-start. The core has no knowledge of git or worktrees.
|
|
78
|
+
*/
|
|
79
|
+
|
|
80
|
+
/** Context the core hands a provider when a child run starts. */
|
|
81
|
+
interface WorkspacePrepareContext {
|
|
82
|
+
agentId: string;
|
|
83
|
+
agentType: SubagentType;
|
|
84
|
+
baseCwd: string;
|
|
85
|
+
invocation?: AgentInvocation;
|
|
86
|
+
}
|
|
87
|
+
/** Outcome the core reports to a workspace when the run ends. */
|
|
88
|
+
interface WorkspaceDisposeOutcome {
|
|
89
|
+
outcome: SubagentOutcome;
|
|
90
|
+
description: string;
|
|
91
|
+
}
|
|
92
|
+
/** What dispose may hand back for the core to fold into the child result. */
|
|
93
|
+
interface WorkspaceDisposeResult {
|
|
94
|
+
/** Appended verbatim to the child's result text — the provider owns the wording. */
|
|
95
|
+
resultAddendum?: string;
|
|
96
|
+
}
|
|
97
|
+
/** A prepared working directory plus its bracketed teardown. Born complete. */
|
|
98
|
+
interface Workspace {
|
|
99
|
+
/** The working directory — already exists when the workspace is handed back. */
|
|
100
|
+
readonly cwd: string;
|
|
101
|
+
dispose(outcome: WorkspaceDisposeOutcome): WorkspaceDisposeResult | undefined;
|
|
102
|
+
}
|
|
103
|
+
/** The single generative seam: supplies a child's workspace. */
|
|
104
|
+
interface WorkspaceProvider {
|
|
105
|
+
prepare(ctx: WorkspacePrepareContext): Promise<Workspace | undefined>;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* service.ts — Public API surface for cross-extension access to subagents.
|
|
110
|
+
*
|
|
111
|
+
* Consumers declare this package as an optional peer dependency and use
|
|
112
|
+
* dynamic import to access the accessor functions:
|
|
113
|
+
*
|
|
114
|
+
* const { getSubagentsService } = await import("@yefengr/pi-subagents");
|
|
115
|
+
* const svc = getSubagentsService();
|
|
116
|
+
* svc?.spawn("Explore", "Check for stale TODOs");
|
|
117
|
+
*/
|
|
118
|
+
|
|
119
|
+
/** Serializable snapshot of an agent's state — no live session objects. */
|
|
120
|
+
interface SubagentRecord {
|
|
121
|
+
id: string;
|
|
122
|
+
type: string;
|
|
123
|
+
description: string;
|
|
124
|
+
phase: SubagentPhase;
|
|
125
|
+
outcome?: SubagentOutcome;
|
|
126
|
+
result?: string;
|
|
127
|
+
error?: string;
|
|
128
|
+
isBackground: boolean;
|
|
129
|
+
lifecycleInvocation: SubagentInvocationIdentity;
|
|
130
|
+
invocationIndex: number;
|
|
131
|
+
sessionState: "created" | "not-created";
|
|
132
|
+
sessionId?: string;
|
|
133
|
+
outputFile?: string;
|
|
134
|
+
toolUses: number;
|
|
135
|
+
startedAt: number;
|
|
136
|
+
completedAt?: number;
|
|
137
|
+
lifetimeUsage: LifetimeUsage;
|
|
138
|
+
invocationStartedAt: number;
|
|
139
|
+
invocationToolUses: number;
|
|
140
|
+
invocationUsage: LifetimeUsage;
|
|
141
|
+
compactionCount: number;
|
|
142
|
+
invocationTurnCount: number;
|
|
143
|
+
lifetimeTurnCount: number;
|
|
144
|
+
maxTurns: number;
|
|
145
|
+
wrapUpTurns: number;
|
|
146
|
+
maxDurationSeconds: number;
|
|
147
|
+
}
|
|
148
|
+
/** Options for spawning an agent via the service. */
|
|
149
|
+
interface SpawnOptions {
|
|
150
|
+
description?: string;
|
|
151
|
+
model?: string;
|
|
152
|
+
maxTurns?: number;
|
|
153
|
+
wrapUpTurns?: number;
|
|
154
|
+
maxDurationSeconds?: number;
|
|
155
|
+
thinkingLevel?: string;
|
|
156
|
+
inheritContext?: boolean;
|
|
157
|
+
foreground?: boolean;
|
|
158
|
+
bypassQueue?: boolean;
|
|
159
|
+
}
|
|
160
|
+
/** The public service contract for cross-extension subagent access. */
|
|
161
|
+
interface SubagentsService {
|
|
162
|
+
/** Spawn an agent. Returns the agent ID immediately. */
|
|
163
|
+
spawn(type: string, prompt: string, options?: SpawnOptions): string;
|
|
164
|
+
/** Get a snapshot of an agent's current state. */
|
|
165
|
+
getRecord(id: string): SubagentRecord | undefined;
|
|
166
|
+
/** List all tracked agents, most recent first. */
|
|
167
|
+
listAgents(): SubagentRecord[];
|
|
168
|
+
/** Abort a running or queued agent. Returns false if not found. */
|
|
169
|
+
abort(id: string): boolean;
|
|
170
|
+
/** Send a steering message to a running agent. */
|
|
171
|
+
steer(id: string, message: string): Promise<boolean>;
|
|
172
|
+
/** Wait for all running and queued agents to complete. */
|
|
173
|
+
waitForAll(): Promise<void>;
|
|
174
|
+
/** Whether any agents are running or queued. */
|
|
175
|
+
hasRunning(): boolean;
|
|
176
|
+
/**
|
|
177
|
+
* Register the single workspace provider that supplies a child's working
|
|
178
|
+
* directory plus bracketed setup/teardown. Throws if one is already
|
|
179
|
+
* registered. Returns a disposer that unregisters the provider.
|
|
180
|
+
*/
|
|
181
|
+
registerWorkspaceProvider(provider: WorkspaceProvider): () => void;
|
|
182
|
+
}
|
|
183
|
+
/** Event channel constants for pi.events subscriptions. */
|
|
184
|
+
declare const SUBAGENT_EVENTS: {
|
|
185
|
+
readonly STARTED: "subagents:started";
|
|
186
|
+
readonly COMPLETED: "subagents:completed";
|
|
187
|
+
readonly FAILED: "subagents:failed";
|
|
188
|
+
readonly RESUMED: "subagents:resumed";
|
|
189
|
+
readonly COMPACTED: "subagents:compacted";
|
|
190
|
+
readonly CREATED: "subagents:created";
|
|
191
|
+
readonly STEERED: "subagents:steered";
|
|
192
|
+
};
|
|
193
|
+
/** Publish the SubagentsService on globalThis for cross-extension access. */
|
|
194
|
+
declare function publishSubagentsService(service: SubagentsService): void;
|
|
195
|
+
/** Retrieve the published SubagentsService, or undefined if not yet published. */
|
|
196
|
+
declare function getSubagentsService(): SubagentsService | undefined;
|
|
197
|
+
/** Remove the SubagentsService from globalThis (call on shutdown/reload). */
|
|
198
|
+
declare function unpublishSubagentsService(): void;
|
|
199
|
+
|
|
200
|
+
export { SUBAGENT_EVENTS, getSubagentsService, publishSubagentsService, unpublishSubagentsService };
|
|
201
|
+
export type { LifetimeUsage, SpawnOptions, SubagentInvocationIdentity, SubagentOutcome, SubagentPhase, SubagentRecord, SubagentsService, Workspace, WorkspaceDisposeOutcome, WorkspaceDisposeResult, WorkspacePrepareContext, WorkspaceProvider };
|