@nklisch/pi-enhanced 0.2.7 → 0.3.1
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 +16 -0
- package/node_modules/@nklisch/pi-clearance/native/clearance-core.linux-x64-gnu.node +0 -0
- package/node_modules/@nklisch/pi-clearance/native/clearance-core.win32-x64-msvc.node +0 -0
- package/node_modules/@nklisch/pi-plugins/README.md +4 -2
- package/node_modules/@nklisch/pi-plugins/dist/hooks.js +81 -8
- package/node_modules/@nklisch/pi-plugins/dist/hooks.js.map +1 -1
- package/node_modules/@nklisch/pi-plugins/dist/mcp.js +32 -1
- package/node_modules/@nklisch/pi-plugins/dist/mcp.js.map +1 -1
- package/node_modules/@nklisch/pi-plugins/dist/pi/plugin-manager.d.ts +10 -4
- package/node_modules/@nklisch/pi-plugins/dist/pi/plugin-manager.js +144 -10
- package/node_modules/@nklisch/pi-plugins/dist/pi/plugin-manager.js.map +1 -1
- package/node_modules/@nklisch/pi-plugins/dist/runtime-discovery.js +40 -14
- package/node_modules/@nklisch/pi-plugins/dist/runtime-discovery.js.map +1 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/CHANGELOG.md +27 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/README.md +76 -47
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/dist/public.d.ts +171 -140
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/dist/settings.d.ts +2 -2
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/FORK-MAINTENANCE.md +8 -7
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/VISION.md +12 -10
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/architecture/architecture.md +118 -104
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/comparison-with-upstream.md +3 -3
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/decisions/0004-reconsider-ui-direction.md +5 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/package.json +1 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/config/custom-agents.ts +31 -4
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/config/default-agents.ts +1 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/config/invocation-config.ts +7 -4
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/index.ts +18 -9
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/layered-settings.ts +2 -2
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/child-lifecycle.ts +10 -63
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/concurrency-limiter.ts +122 -76
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/create-subagent-session.ts +3 -5
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/lifecycle-interceptor.ts +4 -3
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/run-listeners.ts +2 -23
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/subagent-manager.ts +177 -252
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/subagent-session.ts +90 -280
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/subagent-state.ts +153 -239
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/subagent.ts +569 -700
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/lifecycle/workspace.ts +1 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/observation/notification.ts +78 -122
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/observation/renderer.ts +15 -42
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/observation/subagent-events-observer.ts +44 -95
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/service/service-adapter.ts +157 -90
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/service/service.ts +60 -68
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/session/conversation.ts +3 -3
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/session/query-source.ts +28 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/session/query.ts +488 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/settings.ts +1 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/agent-tool.ts +171 -249
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/get-result-tool.ts +51 -94
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/helpers.ts +9 -6
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/list-tool.ts +46 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/parent-tool-registry.ts +17 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/query-session-tool.ts +412 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/result-renderer.ts +27 -111
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/resume-tool.ts +105 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/spawn-config.ts +26 -8
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/steer-tool.ts +27 -111
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/stop-tool.ts +53 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/types.ts +11 -5
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/agent-widget.ts +33 -27
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/display.ts +6 -3
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/session-navigation.ts +121 -10
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/session-navigator.ts +430 -112
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/subagents-settings.ts +1 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/ui/widget-renderer.ts +8 -9
- package/node_modules/@nklisch/pi-plugins/package.json +2 -2
- package/package.json +1 -1
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/background-spawner.ts +0 -81
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/foreground-runner.ts +0 -149
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/src/tools/get-result-report.ts +0 -77
package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/dist/settings.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Generic layered settings loader for `@
|
|
2
|
+
* Generic layered settings loader for `@nklisch/pi-*` extensions.
|
|
3
3
|
*
|
|
4
4
|
* Extensions that store configuration in JSON files under a global agent
|
|
5
5
|
* directory and a per-project `.pi/` folder share the same three-step idiom:
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* ## Usage
|
|
16
16
|
*
|
|
17
17
|
* ```typescript
|
|
18
|
-
* import { loadLayeredSettings, type LayeredSettingsSource } from "@
|
|
18
|
+
* import { loadLayeredSettings, type LayeredSettingsSource } from "@nklisch/pi-subagents/settings";
|
|
19
19
|
*
|
|
20
20
|
* interface MyConfig { enabled?: boolean; limit?: number }
|
|
21
21
|
*
|
package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/docs/FORK-MAINTENANCE.md
CHANGED
|
@@ -34,11 +34,12 @@ only, not lifecycle semantics or consumer contracts.
|
|
|
34
34
|
|
|
35
35
|
## Scope guard
|
|
36
36
|
|
|
37
|
-
The published package keeps the narrow built-in
|
|
37
|
+
The published package keeps the narrow built-in detached widget, session
|
|
38
38
|
navigator, and settings command accepted by ADR 0004. These status surfaces
|
|
39
|
-
show each subagent's exact effective model, exact effective thinking level,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
show each subagent's exact effective model, exact effective thinking level,
|
|
40
|
+
active or final runtime, run id, mode, and terminal reason. The package
|
|
41
|
+
excludes the retired agent editors, wizards, and bespoke conversation viewer
|
|
42
|
+
from the import branch. Reviving those surfaces is a new decision, not a
|
|
43
|
+
restoration. Children inherit extension tools through a registration-open
|
|
44
|
+
denylist policy; batch identity, hard process termination, and RPC stay outside
|
|
45
|
+
the core.
|
|
@@ -9,8 +9,9 @@ order — capability the observational lifecycle events cannot provide.
|
|
|
9
9
|
## Product shape
|
|
10
10
|
|
|
11
11
|
- A minimal core that owns configuration, model-runtime inheritance, sessions,
|
|
12
|
-
tools,
|
|
13
|
-
limits,
|
|
12
|
+
tools, joined/detached delivery, queueing, concurrency,
|
|
13
|
+
consumption-aware retention, workspaces, turn limits, runtime deadlines,
|
|
14
|
+
cooperative stop/resume, and disposal.
|
|
14
15
|
- Extensions — including the fork's own interceptor seam — compose on that
|
|
15
16
|
core rather than forking it (ADR 0002).
|
|
16
17
|
- Two public entrypoints only: the root service contract and `./settings`.
|
|
@@ -20,15 +21,16 @@ order — capability the observational lifecycle events cannot provide.
|
|
|
20
21
|
## Consumers and compatibility
|
|
21
22
|
|
|
22
23
|
The root export is loaded by pi-plugins through a verified packaged loader;
|
|
23
|
-
its shape is a hard compatibility surface. The published package includes a
|
|
24
|
-
status widget, session navigator, and
|
|
25
|
-
surface identifies the exact effective
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
its shape is a hard compatibility surface. The published package includes a
|
|
25
|
+
narrow built-in operator UI: the detached status widget, session navigator, and
|
|
26
|
+
settings command. Every subagent status surface identifies the exact effective
|
|
27
|
+
model, exact effective thinking level, active or final runtime, run id, delivery
|
|
28
|
+
mode, and terminal reason when one exists. Parent-only lifecycle tools are
|
|
29
|
+
centrally registered and removed from child tool definitions, preventing
|
|
30
|
+
recursive orchestration while preserving ordinary inherited extension tools.
|
|
31
|
+
The package excludes the retired experimental editors, wizards, and bespoke
|
|
28
32
|
conversation viewer from the import branch (see ADR 0004 for the UI direction
|
|
29
|
-
history).
|
|
30
|
-
policy so synchronous and lifecycle-time registrations remain available without
|
|
31
|
-
exposing recursive orchestration tools.
|
|
33
|
+
history).
|
|
32
34
|
|
|
33
35
|
## Fork posture
|
|
34
36
|
|
|
@@ -9,11 +9,11 @@ This document describes the architecture of the pi-subagents fork: a focused, co
|
|
|
9
9
|
2. **Composable by default** — other extensions can spawn agents, observe their lifecycle, and display their state without importing this package directly.
|
|
10
10
|
3. **Typed API boundary** — this package exports a `SubagentsService` interface and `Symbol.for()` accessors (`publishSubagentsService` / `getSubagentsService`).
|
|
11
11
|
Consumers declare this package as an optional peer dependency and use dynamic import for compile-time types.
|
|
12
|
-
The runtime bridge is `Symbol.for("@
|
|
12
|
+
The runtime bridge is `Symbol.for("@nklisch/pi-subagents:service")` on `globalThis` — no separate API package.
|
|
13
13
|
4. **No time-based scheduling** — cron-style timed dispatch (upstream's `schedule.ts` subsystem) is removed from the core (#52).
|
|
14
|
-
Timed dispatch is a separate concern that any extension can implement by calling `
|
|
14
|
+
Timed dispatch is a separate concern that any extension can implement by calling `launch()` on the published API.
|
|
15
15
|
The max-concurrent admission gate is not scheduling in this sense — concurrency management stays in core.
|
|
16
|
-
5. **UI is an in-core, substitutable consumer** — [ADR-0004](../decisions/0004-reconsider-ui-direction.md) records the per-component decision: the widget
|
|
16
|
+
5. **UI is an in-core, substitutable consumer** — [ADR-0004](../decisions/0004-reconsider-ui-direction.md) records the per-component decision: the widget shows detached agents only, the bespoke conversation viewer is replaced by native session navigation, the `/agents` command is dissolved into focused surfaces, and the surviving UI stays in the core as a reactive consumer (not extracted to a separate package).
|
|
17
17
|
Extraction remains an available future option because the composition invariant holds — the core is byte-for-byte identical with or without a given UI consumer.
|
|
18
18
|
6. **Snapshot identity; share the canonical runtime** — mutable parent identity and prompt state are frozen into `ParentSnapshot` at spawn. The parent `ModelRuntime` is deliberately shared so child sessions preserve runtime provider and authentication registrations; no live session context is captured.
|
|
19
19
|
7. **Subscribe, don't thread** — observation of agent progress uses direct session-event subscription, not callback parameters threaded through multiple layers.
|
|
@@ -51,11 +51,11 @@ flowchart TB
|
|
|
51
51
|
|
|
52
52
|
subgraph lifecycle["Lifecycle domain"]
|
|
53
53
|
direction TB
|
|
54
|
-
SubagentManager["SubagentManager<br/>(
|
|
55
|
-
ConcurrencyLimiter["ConcurrencyLimiter<br/>(
|
|
54
|
+
SubagentManager["SubagentManager<br/>(launch, resume, stop, collection)"]
|
|
55
|
+
ConcurrencyLimiter["ConcurrencyLimiter<br/>(cancellable FIFO admission)"]
|
|
56
56
|
CreateSubagentSession["createSubagentSession<br/>(assembly factory)"]
|
|
57
57
|
SubagentSession["SubagentSession<br/>(turn loop, steer, dispose)"]
|
|
58
|
-
Subagent["Subagent<br/>(status,
|
|
58
|
+
Subagent["Subagent<br/>(status, run lease, stop/steer lifecycle)"]
|
|
59
59
|
ParentSnapshot["ParentSnapshot<br/>(frozen parent state)"]
|
|
60
60
|
Workspace["workspace<br/>(provider seam: child cwd + teardown)"]
|
|
61
61
|
end
|
|
@@ -69,12 +69,15 @@ flowchart TB
|
|
|
69
69
|
subgraph tools["Tools domain"]
|
|
70
70
|
direction TB
|
|
71
71
|
AgentTool["subagent tool<br/>(dispatch)"]
|
|
72
|
+
QueryTool["query_subagent_session<br/>(bounded read)"]
|
|
72
73
|
ResultRenderer["result-renderer<br/>(pure rendering)"]
|
|
73
74
|
SpawnConfig["spawn-config<br/>(resolve params)"]
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
Resume["resume_subagent"]
|
|
76
|
+
Stop["stop_subagent"]
|
|
77
|
+
List["list_subagents"]
|
|
76
78
|
GetResult["get_subagent_result"]
|
|
77
79
|
Steer["steer_subagent"]
|
|
80
|
+
Query["query_subagent_session"]
|
|
78
81
|
end
|
|
79
82
|
|
|
80
83
|
subgraph ui["UI domain"]
|
|
@@ -115,11 +118,11 @@ classDiagram
|
|
|
115
118
|
+subagentSession?: SubagentSession
|
|
116
119
|
+toolCallId?: string
|
|
117
120
|
+markRunning() delegates
|
|
118
|
-
+
|
|
119
|
-
+
|
|
120
|
-
+
|
|
121
|
-
+abort(): boolean
|
|
121
|
+
+launch()
|
|
122
|
+
+resume(prompt, mode, signal)
|
|
123
|
+
+requestStop(reason): boolean
|
|
122
124
|
+steer(message): Promise~SteerOutcome~
|
|
125
|
+
+settlement: Promise~void~
|
|
123
126
|
+isSessionReady(): boolean
|
|
124
127
|
+getConversation(): string | undefined
|
|
125
128
|
+getContextPercent(): number | null
|
|
@@ -163,11 +166,11 @@ classDiagram
|
|
|
163
166
|
|
|
164
167
|
class SubagentManager {
|
|
165
168
|
+spawn(snapshot, type, prompt, config)
|
|
166
|
-
+
|
|
167
|
-
+resume(id, prompt, signal)
|
|
169
|
+
+launch(snapshot, type, prompt, config)
|
|
170
|
+
+resume(id, prompt, mode, signal)
|
|
171
|
+
+stop(id, timeout): StopOutcome
|
|
168
172
|
+getRecord(id): Subagent
|
|
169
173
|
+listAgents(): Subagent[]
|
|
170
|
-
+abort(id)
|
|
171
174
|
}
|
|
172
175
|
|
|
173
176
|
class AgentTypeRegistry {
|
|
@@ -187,11 +190,13 @@ classDiagram
|
|
|
187
190
|
}
|
|
188
191
|
|
|
189
192
|
class SubagentsService {
|
|
190
|
-
+
|
|
193
|
+
+launch(type, prompt, options?): Promise~LaunchDelivery~
|
|
194
|
+
+resume(id, prompt, options?): Promise~ResumeDelivery~
|
|
195
|
+
+stop(id, timeout?): Promise~StopDelivery~
|
|
196
|
+
+steer(id, message): Promise~SteerDelivery~
|
|
197
|
+
+list(options?): SubagentRecord[]
|
|
198
|
+
+getResult(id): ResultDelivery
|
|
191
199
|
+getRecord(id): SubagentRecord
|
|
192
|
-
+listAgents(): SubagentRecord[]
|
|
193
|
-
+abort(id)
|
|
194
|
-
+steer(id, message)
|
|
195
200
|
+waitForAll()
|
|
196
201
|
+hasRunning(): boolean
|
|
197
202
|
}
|
|
@@ -208,32 +213,20 @@ classDiagram
|
|
|
208
213
|
|
|
209
214
|
```mermaid
|
|
210
215
|
stateDiagram-v2
|
|
211
|
-
[*] --> queued :
|
|
212
|
-
[*] --> running : spawn (foreground or under limit)
|
|
216
|
+
[*] --> queued : launch / resume through FIFO admission
|
|
213
217
|
queued --> running : capacity available
|
|
214
|
-
queued --> stopped :
|
|
215
|
-
running --> completed :
|
|
216
|
-
running -->
|
|
217
|
-
running -->
|
|
218
|
-
running --> stopped : max turns reached
|
|
219
|
-
running --> steered : steer message injected
|
|
220
|
-
steered --> running : continues with message
|
|
218
|
+
queued --> stopped : queued stop or joined cancellation
|
|
219
|
+
running --> completed : success or graceful turn limit
|
|
220
|
+
running --> stopped : explicit stop, parent cancellation, timeout, hard limit, lifecycle abort
|
|
221
|
+
running --> error : provider, execution, or workspace teardown failure
|
|
221
222
|
completed --> resume_wait : reserve resume
|
|
222
|
-
stopped --> resume_wait : reserve
|
|
223
|
+
stopped --> resume_wait : reserve resume
|
|
223
224
|
error --> resume_wait : reserve resume
|
|
224
|
-
aborted --> resume_wait : reserve resume
|
|
225
225
|
resume_wait --> running : prior execution settled + Pi idle
|
|
226
|
-
resume_wait --> stopped :
|
|
226
|
+
resume_wait --> stopped : stop during wind-down
|
|
227
227
|
completed --> [*]
|
|
228
|
-
error --> [*]
|
|
229
|
-
aborted --> [*]
|
|
230
228
|
stopped --> [*]
|
|
231
|
-
|
|
232
|
-
note right of running
|
|
233
|
-
markCompleted, markAborted,
|
|
234
|
-
markSteered, and markError
|
|
235
|
-
are no-ops when status is stopped
|
|
236
|
-
end note
|
|
229
|
+
error --> [*]
|
|
237
230
|
```
|
|
238
231
|
|
|
239
232
|
Note: `markStopped` always succeeds regardless of current status.
|
|
@@ -241,7 +234,7 @@ Other terminal transitions guard against overwriting `stopped` — once an agent
|
|
|
241
234
|
|
|
242
235
|
Resume admission is a record-owned lease. A genuinely running or already-reserved record rejects a second resume before reaching Pi. A stopped record may still own a winding-down prompt, and Pi may still be finishing post-run continuation after the domain result looks terminal; the lease therefore spans the prior execution promise and Pi's authoritative `agent_settled`/`isIdle` boundary. Retention, abort, result waiting, and manager shutdown all treat the lease as active.
|
|
243
236
|
|
|
244
|
-
Terminal outcomes also carry orthogonal consumption state.
|
|
237
|
+
Terminal outcomes also carry orthogonal consumption state. Joined delivery, `get_subagent_result`, and a queued detached completion notification mark the outcome consumed. Records remain available for the parent session; only their heavy live child sessions are released after the configured consumed or unconsumed retention window. Released records keep their result and persisted transcript pointer but cannot resume. Release detaches the session synchronously before awaiting teardown, so it cannot race a new resume.
|
|
245
238
|
|
|
246
239
|
Completion notifications are held while the parent agent run is active and flushed on `agent_settled`, rechecking consumption before enqueueing a follow-up. A blocking `get_subagent_result` request claims direct delivery before awaiting, so the same terminal outcome cannot also enqueue a completion follow-up. Child session creation shares the parent model runtime and leaves extension-tool registration open; a denylist removes disallowed built-ins and recursive orchestration tools across registry refreshes. Child teardown mirrors Pi's managed root lifecycle: it emits and awaits `session_shutdown` before `AgentSession.dispose()` revokes extension contexts, then publishes the child `disposed` event.
|
|
247
240
|
|
|
@@ -259,11 +252,11 @@ sequenceDiagram
|
|
|
259
252
|
participant Sub as SubagentSession
|
|
260
253
|
participant Child as Child session
|
|
261
254
|
|
|
262
|
-
LLM->>Tool: subagent(type, prompt, ...)
|
|
255
|
+
LLM->>Tool: subagent(type, prompt, mode, ...)
|
|
263
256
|
Tool->>Spawn: resolveSpawnConfig(params)
|
|
264
257
|
Spawn-->>Tool: ResolvedSpawnConfig
|
|
265
|
-
Tool->>Mgr:
|
|
266
|
-
Mgr->>Ag:
|
|
258
|
+
Tool->>Mgr: launch(snapshot, type, prompt, config)
|
|
259
|
+
Mgr->>Ag: schedule lease through FIFO admission
|
|
267
260
|
Ag->>Factory: createSubagentSession(params, deps)
|
|
268
261
|
Factory->>Asm: assembleSessionConfig(type, ctx, opts, env, registry, io)
|
|
269
262
|
Asm-->>Factory: SessionConfig
|
|
@@ -275,14 +268,14 @@ sequenceDiagram
|
|
|
275
268
|
Child-->>Sub: result text
|
|
276
269
|
Sub-->>Ag: TurnLoopResult
|
|
277
270
|
Ag-->>Mgr: update Subagent
|
|
278
|
-
Mgr-->>Tool:
|
|
279
|
-
Tool-->>LLM:
|
|
271
|
+
Mgr-->>Tool: detached identity or joined settled record
|
|
272
|
+
Tool-->>LLM: bounded result or delivery identity
|
|
280
273
|
Note over Mgr: retention releases heavy sessions but keeps terminal records and transcript pointers
|
|
281
274
|
```
|
|
282
275
|
|
|
283
276
|
## Module organization
|
|
284
277
|
|
|
285
|
-
The extension has
|
|
278
|
+
The extension has 67 source files organized into six domains plus entry-point wiring.
|
|
286
279
|
All eight domains have directories: `config/`, `session/`, `lifecycle/`, `observation/`, `service/`, `tools/`, `ui/`, and `handlers/`.
|
|
287
280
|
Issue #164 moved the 26 previously flat root-level files into five new domain directories, reducing the root to 5 files + 8 directories.
|
|
288
281
|
|
|
@@ -295,7 +288,7 @@ src/
|
|
|
295
288
|
├── types.ts shared type definitions
|
|
296
289
|
├── settings.ts SettingsManager (persistent operational settings)
|
|
297
290
|
├── debug.ts debug logging utility
|
|
298
|
-
├── layered-settings.ts loadLayeredSettings helper (published as @
|
|
291
|
+
├── layered-settings.ts loadLayeredSettings helper (published as @nklisch/pi-subagents/settings)
|
|
299
292
|
│
|
|
300
293
|
├── config/ agent type definitions and resolution
|
|
301
294
|
│ ├── agent-types.ts AgentTypeRegistry class
|
|
@@ -308,6 +301,8 @@ src/
|
|
|
308
301
|
│ ├── prompts.ts system prompt building
|
|
309
302
|
│ ├── content-items.ts shared message content parsing (tool-call names, assistant content)
|
|
310
303
|
│ ├── context.ts parent conversation extraction
|
|
304
|
+
│ ├── query.ts bounded live/file transcript projection and search
|
|
305
|
+
│ ├── query-source.ts shared JSONL adapter for query and native navigation
|
|
311
306
|
│ ├── conversation.ts render a session's messages as formatted text
|
|
312
307
|
│ ├── env.ts git/platform detection
|
|
313
308
|
│ ├── model-resolver.ts fuzzy model name resolution
|
|
@@ -318,11 +313,11 @@ src/
|
|
|
318
313
|
│ ├── create-subagent-session.ts assembly factory: session creation, binding, tool filtering
|
|
319
314
|
│ ├── subagent-session.ts born-complete child session: turn loop, steer, dispose
|
|
320
315
|
│ ├── turn-limits.ts normalizeMaxTurns (turn-count policy)
|
|
321
|
-
│ ├── subagent.ts
|
|
322
|
-
│ ├── subagent-state.ts
|
|
323
|
-
│ ├── run-listeners.ts per-run observer-
|
|
316
|
+
│ ├── subagent.ts authoritative run lease and stop/resume lifecycle
|
|
317
|
+
│ ├── subagent-state.ts coarse status, terminal reasons, and metrics
|
|
318
|
+
│ ├── run-listeners.ts per-run observer-unsubscribe handle
|
|
324
319
|
│ ├── workspace-bracket.ts child workspace prepare/dispose lifecycle
|
|
325
|
-
│ ├── concurrency-limiter.ts
|
|
320
|
+
│ ├── concurrency-limiter.ts cancellable FIFO admission gate for all run modes
|
|
326
321
|
│ ├── parent-snapshot.ts immutable spawn-time parent state
|
|
327
322
|
│ ├── child-lifecycle.ts child-execution lifecycle event publisher
|
|
328
323
|
│ ├── workspace.ts workspace provider seam (generative extension surface)
|
|
@@ -343,10 +338,12 @@ src/
|
|
|
343
338
|
│ ├── agent-tool.ts subagent tool definition, validation, dispatch
|
|
344
339
|
│ ├── result-renderer.ts pure per-status result rendering
|
|
345
340
|
│ ├── spawn-config.ts pure config resolution
|
|
346
|
-
│ ├──
|
|
347
|
-
│ ├──
|
|
341
|
+
│ ├── resume-tool.ts resume_subagent tool
|
|
342
|
+
│ ├── stop-tool.ts stop_subagent tool
|
|
343
|
+
│ ├── list-tool.ts list_subagents tool
|
|
348
344
|
│ ├── get-result-tool.ts get_subagent_result tool
|
|
349
|
-
│ ├──
|
|
345
|
+
│ ├── query-session-tool.ts query_subagent_session tool
|
|
346
|
+
│ ├── parent-tool-registry.ts authoritative parent-only tool names
|
|
350
347
|
│ ├── steer-tool.ts steer_subagent tool
|
|
351
348
|
│ └── helpers.ts shared tool utilities
|
|
352
349
|
│
|
|
@@ -356,7 +353,7 @@ src/
|
|
|
356
353
|
│ ├── display.ts pure formatters and shared types
|
|
357
354
|
│ ├── subagents-settings.ts /subagents:settings command handler
|
|
358
355
|
│ ├── session-navigation.ts pure session-selection and transcript-source logic
|
|
359
|
-
│ └── session-navigator.ts /subagents:sessions command handler
|
|
356
|
+
│ └── session-navigator.ts /subagents:sessions command handler and search overlay
|
|
360
357
|
│
|
|
361
358
|
└── handlers/ event handlers
|
|
362
359
|
├── index.ts barrel re-export
|
|
@@ -365,21 +362,43 @@ src/
|
|
|
365
362
|
└── tool-start.ts tool_execution_start handler
|
|
366
363
|
```
|
|
367
364
|
|
|
365
|
+
### Transcript query boundary
|
|
366
|
+
|
|
367
|
+
`query_subagent_session` is a parent-only, read-only pull surface. Its pure
|
|
368
|
+
`session/query.ts` projection correlates tool results to calls, searches every
|
|
369
|
+
complete visible field with literal case-insensitive matching, and returns
|
|
370
|
+
match-centered bounded excerpts with source-range metadata. Tool names and call
|
|
371
|
+
IDs remain complete only in the projection-local search/correlation data;
|
|
372
|
+
returned display values are bounded while stable entry IDs remain intact for the
|
|
373
|
+
overlay. Scope, ordering, 1–50 result limits, and stateless numeric offsets page
|
|
374
|
+
the ordered matching set; byte and line output bounds may shorten a page without
|
|
375
|
+
advancing beyond entries actually returned, but a non-empty page always emits a
|
|
376
|
+
bounded first entry. It reads a live child session when retained and otherwise
|
|
377
|
+
uses the same Pi JSONL/context adapter as native session navigation. No index,
|
|
378
|
+
cursor, or query state is persisted, and successful reads report complete
|
|
379
|
+
search rather than a partial-search state.
|
|
380
|
+
|
|
381
|
+
`/subagents:sessions` keeps Pi's native message, markdown, and tool-execution
|
|
382
|
+
components for the transcript body. Its overlay owns only ephemeral search
|
|
383
|
+
state and block-level match chrome; a release notification swaps the source to
|
|
384
|
+
the file snapshot, while an unavailable snapshot preserves the last readable
|
|
385
|
+
content and labels the degraded state.
|
|
386
|
+
|
|
368
387
|
### Observation model
|
|
369
388
|
|
|
370
389
|
Record statistics (tool uses, token usage, compaction counts) and live activity (active tools, response text, turn counts) are updated by `record-observer.ts`, which subscribes directly to session events.
|
|
371
390
|
This is the single per-child session subscription — all run state lives on the `Subagent` record.
|
|
372
391
|
|
|
373
|
-
The widget maintains a bounded reactive read model of active
|
|
392
|
+
The widget maintains a bounded reactive read model of active detached records and the small terminal linger set, populated by `SubagentManagerObserver` lifecycle callbacks. While active it refreshes that model at 500 ms; each refresh reads only those retained records and requests the normal Pi widget render, rather than cloning or sorting the manager's full terminal history. When only terminal linger records remain, it renders the completion state once and leaves the static widget registered without an interval until turn aging or clear removes it. The `/subagents:sessions` navigator reads messages via `Subagent.agentMessages`, falls back to the retained JSONL source after release, and subscribes to both session and record-release updates — no direct `AgentSession` reference (#277).
|
|
374
393
|
|
|
375
394
|
## Cross-extension architecture
|
|
376
395
|
|
|
377
396
|
```mermaid
|
|
378
397
|
flowchart TD
|
|
379
|
-
subgraph core["@
|
|
398
|
+
subgraph core["@nklisch/pi-subagents"]
|
|
380
399
|
direction TB
|
|
381
400
|
exports["SubagentsService API<br/>publish / getSubagentsService<br/>SubagentRecord, SubagentStatus"]
|
|
382
|
-
engine["Tools: subagent, get_subagent_result,<br/>
|
|
401
|
+
engine["Tools: subagent, resume_subagent, stop_subagent,<br/>list_subagents, get_subagent_result, steer_subagent,<br/>query_subagent_session<br/>SubagentManager, createSubagentSession, SubagentSession"]
|
|
383
402
|
ui_int["Internal UI: widget, session-navigator,<br/>subagents-settings"]
|
|
384
403
|
end
|
|
385
404
|
|
|
@@ -388,14 +407,14 @@ flowchart TD
|
|
|
388
407
|
core -- "Symbol.for on globalThis" --> future["any future extension"]
|
|
389
408
|
```
|
|
390
409
|
|
|
391
|
-
Consumers call `getSubagentsService()?.
|
|
410
|
+
Consumers call `getSubagentsService()?.launch(...)` at runtime.
|
|
392
411
|
They declare this package as an optional peer dependency and use dynamic import for compile-time types.
|
|
393
412
|
|
|
394
413
|
### What the core owns
|
|
395
414
|
|
|
396
|
-
- The
|
|
397
|
-
- `SubagentManager` —
|
|
398
|
-
- `ConcurrencyLimiter` —
|
|
415
|
+
- The parent-only tools: `subagent`, `resume_subagent`, `stop_subagent`, `list_subagents`, `get_subagent_result`, `steer_subagent`, and `query_subagent_session`.
|
|
416
|
+
- `SubagentManager` — launch, resume, cooperative stop, collection management, and observer wiring.
|
|
417
|
+
- `ConcurrencyLimiter` — cancellable FIFO admission gate shared by joined and detached runs.
|
|
399
418
|
- `createSubagentSession` — assembly factory: session creation and extension binding; returns a born-complete `SubagentSession`.
|
|
400
419
|
- `SubagentSession` — the born-complete child session: drives turn loops, exposes Pi's idle boundary, steers, and performs idempotent asynchronous teardown (`session_shutdown` → `AgentSession.dispose()` → child `disposed`).
|
|
401
420
|
- `child-lifecycle` — publishes the child-execution lifecycle (`spawning`, `session-created` before `bindExtensions()`, `completed`, `disposed`) on `pi.events`.
|
|
@@ -426,7 +445,7 @@ They declare this package as an optional peer dependency and use dynamic import
|
|
|
426
445
|
|
|
427
446
|
## SubagentsService
|
|
428
447
|
|
|
429
|
-
The `SubagentsService` interface, accessor functions, and serializable types are exported from `@
|
|
448
|
+
The `SubagentsService` interface, accessor functions, and serializable types are exported from `@nklisch/pi-subagents` via the root export.
|
|
430
449
|
No separate API package is needed.
|
|
431
450
|
|
|
432
451
|
Consumers declare this package as an optional peer dependency:
|
|
@@ -434,10 +453,10 @@ Consumers declare this package as an optional peer dependency:
|
|
|
434
453
|
```json
|
|
435
454
|
{
|
|
436
455
|
"peerDependencies": {
|
|
437
|
-
"@
|
|
456
|
+
"@nklisch/pi-subagents": ">=18.0.0"
|
|
438
457
|
},
|
|
439
458
|
"peerDependenciesMeta": {
|
|
440
|
-
"@
|
|
459
|
+
"@nklisch/pi-subagents": { "optional": true }
|
|
441
460
|
}
|
|
442
461
|
}
|
|
443
462
|
```
|
|
@@ -445,31 +464,31 @@ Consumers declare this package as an optional peer dependency:
|
|
|
445
464
|
At runtime, consumers use dynamic import for type-safe access to the accessor functions:
|
|
446
465
|
|
|
447
466
|
```typescript
|
|
448
|
-
const { getSubagentsService } = await import("@
|
|
467
|
+
const { getSubagentsService } = await import("@nklisch/pi-subagents");
|
|
449
468
|
const svc = getSubagentsService();
|
|
450
469
|
if (svc) {
|
|
451
|
-
svc.
|
|
470
|
+
void svc.launch("Explore", "Check for stale TODOs", { mode: "detached" });
|
|
452
471
|
}
|
|
453
472
|
```
|
|
454
473
|
|
|
455
474
|
Pi's extension loader creates a fresh `jiti` instance per extension with `moduleCache: false`, so module-scoped singletons don't survive across extensions.
|
|
456
|
-
The accessor functions use `Symbol.for("@
|
|
475
|
+
The accessor functions use `Symbol.for("@nklisch/pi-subagents:service")` on `globalThis`, which is process-global by spec, to bridge this gap.
|
|
457
476
|
The dynamic import provides compile-time types; the `Symbol.for()` key is the actual runtime channel.
|
|
458
477
|
|
|
459
478
|
### Interface
|
|
460
479
|
|
|
461
|
-
See `src/service.ts` for the canonical definition.
|
|
480
|
+
See `src/service/service.ts` for the canonical definition.
|
|
462
481
|
Key types:
|
|
463
482
|
|
|
464
|
-
- `SubagentsService` — `
|
|
465
|
-
- `SubagentRecord` — serializable agent snapshot
|
|
466
|
-
- `
|
|
483
|
+
- `SubagentsService` — `launch`, `resume`, `stop`, `steer`, `list`, `getResult`, `getRecord`, `waitForAll`, and `hasRunning`.
|
|
484
|
+
- `SubagentRecord` — serializable agent snapshot with run id, mode, status, terminal reason, active runtime, model, and thinking level.
|
|
485
|
+
- `LaunchOptions` — `description`, `model`, `maxTurns`, `thinkingLevel`, `inheritContext`, `mode`, `timeoutSeconds`, and `signal`.
|
|
467
486
|
- `SUBAGENT_EVENTS` — channel constants for `pi.events` subscriptions.
|
|
468
487
|
|
|
469
488
|
### Accessor pattern
|
|
470
489
|
|
|
471
490
|
```typescript
|
|
472
|
-
const SERVICE_KEY = Symbol.for("@
|
|
491
|
+
const SERVICE_KEY = Symbol.for("@nklisch/pi-subagents:service");
|
|
473
492
|
|
|
474
493
|
export function publishSubagentsService(service: SubagentsService): void {
|
|
475
494
|
(globalThis as Record<symbol, unknown>)[SERVICE_KEY] = service;
|
|
@@ -490,12 +509,12 @@ The core emits events on `pi.events` that any extension can observe:
|
|
|
490
509
|
|
|
491
510
|
| Channel | Payload | When |
|
|
492
511
|
| --------------------- | ----------------------------------------------------------------------------------- | --------------------------------------------- |
|
|
493
|
-
| `subagents:started` | `{ id, type, description }`
|
|
494
|
-
| `subagents:completed` | `{ id, type,
|
|
512
|
+
| `subagents:started` | `{ id, type, description, runId, mode }` | Agent begins running |
|
|
513
|
+
| `subagents:completed` | `{ id, type, runId, mode, status, terminalReason, result?, error?, toolUses, activeRuntimeMs, tokens? }` | Agent reaches a terminal state |
|
|
495
514
|
| `subagents:resumed` | same as `completed` (`buildEventData` shape) | A retained session's resumed turn finishes |
|
|
496
|
-
| `subagents:failed` | same as `completed` (`buildEventData` shape) | Agent ends in `error
|
|
515
|
+
| `subagents:failed` | same as `completed` (`buildEventData` shape) | Agent ends in `error` or `stopped` |
|
|
497
516
|
| `subagents:compacted` | `{ id, type, description, reason, tokensBefore, compactionCount }` | Child session compacts |
|
|
498
|
-
| `subagents:created` | `{ id, type, description,
|
|
517
|
+
| `subagents:created` | `{ id, type, description, runId, mode }` | Agent record created (pre-admission) |
|
|
499
518
|
| `subagents:steered` | `{ id, message }` | Steering message delivered to a running agent |
|
|
500
519
|
|
|
501
520
|
These are fire-and-forget broadcast events — no request IDs, no reply channels.
|
|
@@ -624,7 +643,7 @@ The axis that decides push versus pull is whether a need is reactive or discrete
|
|
|
624
643
|
- **Reactive** (ambient state that changes underneath you) → subscribe to the broadcast; be told.
|
|
625
644
|
The state-owner announces; the consumer maintains its own read-model; nobody pulls.
|
|
626
645
|
- **Discrete** (a one-shot question: current value, full transcript) → pull a query.
|
|
627
|
-
`get_subagent_result`, opening a transcript, and the external `SubagentsService.getRecord` are queries by nature and stay pull, in-package or not.
|
|
646
|
+
`get_subagent_result`, `query_subagent_session`, opening a transcript, and the external `SubagentsService.getRecord` are queries by nature and stay pull, in-package or not.
|
|
628
647
|
|
|
629
648
|
Behavior is a third interface: **tell by id, with outcomes**.
|
|
630
649
|
`steer` and `abort` own their own rules — a non-running agent rejects a steer from inside `steer`, not via a caller's status pre-check — so coordinators never ask-then-tell.
|
|
@@ -676,8 +695,8 @@ Bags with 10+ fields are the highest priority for decomposition.
|
|
|
676
695
|
|
|
677
696
|
| Interface | Fields | Consumers | Severity |
|
|
678
697
|
| ----------------------------- | ------------------------------------------------------------ | ------------------------------------------------- | --------- |
|
|
679
|
-
| `ResolvedSpawnConfig` | 3 nested |
|
|
680
|
-
| `AgentSpawnConfig` |
|
|
698
|
+
| `ResolvedSpawnConfig` | 3 nested | spawn-config, agent-tool | ✓ done |
|
|
699
|
+
| `AgentSpawnConfig` | execution options + parent identity | subagent-manager (internal) | ✓ done |
|
|
681
700
|
| `CreateSubagentSessionParams` | 6 (snapshot, type, cwd, parentSession, model, thinkingLevel) | create-subagent-session | ✓ done |
|
|
682
701
|
| `TurnLoopOptions` | 4 (maxTurns, defaultMaxTurns, graceTurns, signal) | subagent-session | ✓ done |
|
|
683
702
|
| `SessionConfig` | 6 (flat fields; extensions/noSkills/extras removed in #264) | session-config (output of assembler) | ✓ done |
|
|
@@ -704,7 +723,7 @@ Files with highest commit frequency × complexity:
|
|
|
704
723
|
| 27.1 | `index.ts` | 109 | ▼ cooling |
|
|
705
724
|
| 9.6 | `tools/agent-tool.ts` | 56 | ▼ cooling |
|
|
706
725
|
| 8.8 | `ui/agent-widget.ts` | 22 | ▼ cooling |
|
|
707
|
-
| 7.3 | `
|
|
726
|
+
| 7.3 | `lifecycle/subagent.ts` | 22 | ▼ cooling |
|
|
708
727
|
| 6.6 | `service/service-adapter.ts` | 15 | ▲ accelerating |
|
|
709
728
|
| 6.3 | `config/custom-agents.ts` | 13 | ▼ cooling |
|
|
710
729
|
|
|
@@ -712,9 +731,8 @@ Files with highest commit frequency × complexity:
|
|
|
712
731
|
|
|
713
732
|
### Production duplication
|
|
714
733
|
|
|
715
|
-
The prior clone group between
|
|
716
|
-
The
|
|
717
|
-
The final 11-line internal clone group within `agent-config-editor.ts` was eliminated in Phase 19 Step 6 ([#441]) when the file itself was deleted; production duplication is 0 lines.
|
|
734
|
+
The prior clone group between the execution and formatting paths was resolved in #172.
|
|
735
|
+
The definition-management clone groups were removed with the `/agents` terminal cut in Phase 19 ([#441]); the supporting file-writer module was removed with them. Production duplication remains 0 lines.
|
|
718
736
|
|
|
719
737
|
### Session encapsulation debt (Law of Demeter) — resolved by [#277] ✔️
|
|
720
738
|
|
|
@@ -725,11 +743,10 @@ The intent-revealing replacements added by [#277]:
|
|
|
725
743
|
| Reach-through | Sites | Replacement |
|
|
726
744
|
| ---------------------------------------- | ---------------------------------------------------------------------------------- | -------------------------------------------------- |
|
|
727
745
|
| Steer buffer-or-deliver (was duplicated) | `service-adapter.ts`, `steer-tool.ts` | `Subagent.steer(message)` |
|
|
728
|
-
| Conversation viewing | `
|
|
746
|
+
| Conversation viewing | `session-navigation.ts`, `session-navigator.ts` | `Subagent.agentMessages` / transcript sources |
|
|
729
747
|
| Session-readiness guard | `agent-tool.ts`, `subagent-manager.ts` | `Subagent.isSessionReady()` |
|
|
730
|
-
| Context-window stats | `steer-tool.ts`, `get-result-tool.ts`, `notification.ts
|
|
731
|
-
| Live updates (subscription) | `
|
|
732
|
-
| Observer callback session param | `background-spawner.ts`, `foreground-runner.ts` | `subagent.subagentSession` (narrowed callback) |
|
|
748
|
+
| Context-window stats | `steer-tool.ts`, `get-result-tool.ts`, `notification.ts` | `Subagent.getContextPercent()` |
|
|
749
|
+
| Live updates (subscription) | `session-navigator.ts` | `Subagent.subscribeToUpdates(fn)` |
|
|
733
750
|
| Session disposal | `subagent-manager.ts` | `SubagentSession.dispose()` — resolved by [#265] |
|
|
734
751
|
|
|
735
752
|
### Proposed bag decompositions
|
|
@@ -756,7 +773,8 @@ interface SpawnExecution {
|
|
|
756
773
|
effectiveMaxTurns: number | undefined;
|
|
757
774
|
thinking: ThinkingLevel | undefined;
|
|
758
775
|
inheritContext: boolean;
|
|
759
|
-
|
|
776
|
+
mode: SubagentMode;
|
|
777
|
+
timeoutSeconds?: number;
|
|
760
778
|
agentInvocation: AgentInvocation;
|
|
761
779
|
}
|
|
762
780
|
|
|
@@ -768,8 +786,8 @@ interface SpawnPresentation {
|
|
|
768
786
|
}
|
|
769
787
|
```
|
|
770
788
|
|
|
771
|
-
`
|
|
772
|
-
|
|
789
|
+
`agent-tool` consumes all three to build the internal `AgentSpawnConfig` and the result text.
|
|
790
|
+
The joined/detached mode lives in `SpawnExecution`; no separate foreground/background runner exists.
|
|
773
791
|
After decomposition, each consumer declares its real dependencies explicitly.
|
|
774
792
|
|
|
775
793
|
#### AgentSpawnConfig — ParentSessionInfo extracted (done, [#166][166])
|
|
@@ -800,8 +818,7 @@ export interface RunContext {
|
|
|
800
818
|
}
|
|
801
819
|
```
|
|
802
820
|
|
|
803
|
-
The
|
|
804
|
-
`RunOptions` now has 9 fields: 1 nested `context: RunContext` (2 per-call fields) plus 8 flat execution fields.
|
|
821
|
+
The current execution seam is `SubagentExecution` in `lifecycle/subagent.ts`; it carries the immutable parent snapshot, joined/detached mode, runtime deadline, session factory, and lifecycle collaborators directly. The old runner-specific `RunOptions` bag is no longer part of the source tree.
|
|
805
822
|
|
|
806
823
|
#### SessionConfig (11 fields → extract ToolFilterConfig) — done ([#168][168])
|
|
807
824
|
|
|
@@ -809,7 +826,7 @@ The tool-filtering cluster (`toolNames`, `disallowedSet`, `extensions`) was extr
|
|
|
809
826
|
`filterActiveTools` now accepts a single `ToolFilterConfig` argument instead of three positional parameters.
|
|
810
827
|
`SessionConfig` reduced from 10 to 8 top-level fields.
|
|
811
828
|
|
|
812
|
-
####
|
|
829
|
+
#### Session factory IO (9 methods → 2 focused interfaces) — done ([#167][167])
|
|
813
830
|
|
|
814
831
|
The IO boundary was split into two focused interfaces:
|
|
815
832
|
|
|
@@ -834,13 +851,9 @@ export interface SessionFactoryIO {
|
|
|
834
851
|
) => Promise<{ session: AgentSession }>;
|
|
835
852
|
assemblerIO: AssemblerIO;
|
|
836
853
|
}
|
|
837
|
-
|
|
838
|
-
/** Backward-compatible intersection of the two focused interfaces. */
|
|
839
|
-
export type RunnerIO = EnvironmentIO & SessionFactoryIO;
|
|
840
854
|
```
|
|
841
855
|
|
|
842
|
-
`
|
|
843
|
-
All existing consumers satisfy both sub-interfaces via structural typing with no call-site changes.
|
|
856
|
+
The factory consumes the `EnvironmentIO & SessionFactoryIO` boundary directly; no runner implementation or compatibility alias remains.
|
|
844
857
|
|
|
845
858
|
## Phase 11 (complete)
|
|
846
859
|
|
|
@@ -924,6 +937,10 @@ See [phase-19-implement-ui-decisions.md](history/phase-19-implement-ui-decisions
|
|
|
924
937
|
|
|
925
938
|
## Phase 20 improvement roadmap
|
|
926
939
|
|
|
940
|
+
> Planning note: this roadmap records the pre-execution-control baseline. The
|
|
941
|
+
> joined/detached execution-control work below supersedes any obsolete runner,
|
|
942
|
+
> unbounded-result, and foreground/background vocabulary in these notes.
|
|
943
|
+
|
|
927
944
|
Phase 20 realizes the last un-extracted domain from the [first-principles refinement](#first-principles-refinement-and-the-deeper-target) — **result delivery** — and clears the residual boundary and complexity debt discovery surfaced around it.
|
|
928
945
|
|
|
929
946
|
Discovery findings (fallow + entry-point trace + test-constructibility audit, 2026-07-03):
|
|
@@ -969,9 +986,8 @@ Target files:
|
|
|
969
986
|
|
|
970
987
|
Outcome: `execute` ≤ 30 lines with cyclomatic < 10; off the fallow high-complexity list.
|
|
971
988
|
|
|
972
|
-
Landed:
|
|
973
|
-
`
|
|
974
|
-
`get-result-tool.execute` is off the HIGH-CRAP list (3 → 2 remaining: `service-adapter.spawn`, the notification renderer arrow).
|
|
989
|
+
Landed: bounded result formatting was extracted while the earlier result-delivery design was active. The later execution-control clean break removed the standalone report module and its unbounded wait path; `GetResultTool` now owns a nonblocking, bounded status/result projection.
|
|
990
|
+
`get-result-tool.execute` remains a focused lookup-and-render boundary.
|
|
975
991
|
|
|
976
992
|
`Release: batch "result-delivery"`
|
|
977
993
|
|
|
@@ -1016,8 +1032,6 @@ Target files:
|
|
|
1016
1032
|
|
|
1017
1033
|
- `src/ui/agent-widget.ts` — replace `tui: any` with a lean local interface (`terminal.columns`, `requestRender()`); shrink the 4-rule file-level disable.
|
|
1018
1034
|
- `src/tools/agent-tool.ts` — type `renderCall`/`renderResult` params (`theme`, `result`) with lean local interfaces; shrink the 6-rule file-level disable to the genuinely SDK-gapped lines.
|
|
1019
|
-
- `src/tools/foreground-runner.ts` — retire the line-level `details as any` cast if the SDK surface allows.
|
|
1020
|
-
|
|
1021
1035
|
Some disables are irreducible SDK export gaps; the goal is line-level precision, not zero.
|
|
1022
1036
|
|
|
1023
1037
|
Outcome: file-level eslint-disable headers 5 → ≤ 2; remaining suppressions are line-level with named rules.
|
|
@@ -6,7 +6,7 @@ The source tree was reviewed against `@gotgenes/pi-subagents` 19.2.1 and `@tinti
|
|
|
6
6
|
|
|
7
7
|
## Shared core
|
|
8
8
|
|
|
9
|
-
All three implementations provide in-process
|
|
9
|
+
All three implementations provide in-process subagents, custom agent definitions, concurrency control, steering, result retrieval, session resume, model selection, thinking control, and completion notifications. This fork exposes joined and detached delivery rather than separate foreground/background APIs.
|
|
10
10
|
|
|
11
11
|
The direct `gotgenes` lineage and this fork also share a focused-core architecture:
|
|
12
12
|
|
|
@@ -34,8 +34,8 @@ A mechanical rebase is unsafe because direct upstream may change or remove these
|
|
|
34
34
|
|
|
35
35
|
This fork selectively carries the useful 18.1–19.2 reliability work:
|
|
36
36
|
|
|
37
|
-
- queued and resumed runs
|
|
38
|
-
-
|
|
37
|
+
- queued and resumed runs settle through the current run lease;
|
|
38
|
+
- `get_subagent_result` is bounded and nonblocking, so status inspection never waits on child execution;
|
|
39
39
|
- queued stops follow the terminal lifecycle and state that no work started;
|
|
40
40
|
- consumption-aware retention keeps terminal records for the parent session while releasing heavy live sessions on separate consumed and unconsumed windows;
|
|
41
41
|
- completion notifications wait for the parent `agent_settled` boundary and recheck consumption;
|