@nklisch/pi-enhanced 0.2.7 → 0.3.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 +10 -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 +19 -0
- package/node_modules/@nklisch/pi-plugins/node_modules/@nklisch/pi-subagents/README.md +75 -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 +111 -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 +327 -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 +330 -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/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,36 @@ 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, caps searchable
|
|
369
|
+
fields and excerpts, and applies literal case-insensitive matching, scope,
|
|
370
|
+
ordering, and a 1–50 result limit on every call. It reads a live child session
|
|
371
|
+
when retained and otherwise uses the same Pi JSONL/context adapter as native
|
|
372
|
+
session navigation. No index or query state is persisted.
|
|
373
|
+
|
|
374
|
+
`/subagents:sessions` keeps Pi's native message, markdown, and tool-execution
|
|
375
|
+
components for the transcript body. Its overlay owns only ephemeral search
|
|
376
|
+
state and block-level match chrome; a release notification swaps the source to
|
|
377
|
+
the file snapshot, while an unavailable snapshot preserves the last readable
|
|
378
|
+
content and labels the degraded state.
|
|
379
|
+
|
|
368
380
|
### Observation model
|
|
369
381
|
|
|
370
382
|
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
383
|
This is the single per-child session subscription — all run state lives on the `Subagent` record.
|
|
372
384
|
|
|
373
|
-
The widget maintains a bounded reactive read model of active
|
|
385
|
+
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
386
|
|
|
375
387
|
## Cross-extension architecture
|
|
376
388
|
|
|
377
389
|
```mermaid
|
|
378
390
|
flowchart TD
|
|
379
|
-
subgraph core["@
|
|
391
|
+
subgraph core["@nklisch/pi-subagents"]
|
|
380
392
|
direction TB
|
|
381
393
|
exports["SubagentsService API<br/>publish / getSubagentsService<br/>SubagentRecord, SubagentStatus"]
|
|
382
|
-
engine["Tools: subagent, get_subagent_result,<br/>
|
|
394
|
+
engine["Tools: subagent, resume_subagent, stop_subagent,<br/>list_subagents, get_subagent_result, steer_subagent,<br/>query_subagent_session<br/>SubagentManager, createSubagentSession, SubagentSession"]
|
|
383
395
|
ui_int["Internal UI: widget, session-navigator,<br/>subagents-settings"]
|
|
384
396
|
end
|
|
385
397
|
|
|
@@ -388,14 +400,14 @@ flowchart TD
|
|
|
388
400
|
core -- "Symbol.for on globalThis" --> future["any future extension"]
|
|
389
401
|
```
|
|
390
402
|
|
|
391
|
-
Consumers call `getSubagentsService()?.
|
|
403
|
+
Consumers call `getSubagentsService()?.launch(...)` at runtime.
|
|
392
404
|
They declare this package as an optional peer dependency and use dynamic import for compile-time types.
|
|
393
405
|
|
|
394
406
|
### What the core owns
|
|
395
407
|
|
|
396
|
-
- The
|
|
397
|
-
- `SubagentManager` —
|
|
398
|
-
- `ConcurrencyLimiter` —
|
|
408
|
+
- The parent-only tools: `subagent`, `resume_subagent`, `stop_subagent`, `list_subagents`, `get_subagent_result`, `steer_subagent`, and `query_subagent_session`.
|
|
409
|
+
- `SubagentManager` — launch, resume, cooperative stop, collection management, and observer wiring.
|
|
410
|
+
- `ConcurrencyLimiter` — cancellable FIFO admission gate shared by joined and detached runs.
|
|
399
411
|
- `createSubagentSession` — assembly factory: session creation and extension binding; returns a born-complete `SubagentSession`.
|
|
400
412
|
- `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
413
|
- `child-lifecycle` — publishes the child-execution lifecycle (`spawning`, `session-created` before `bindExtensions()`, `completed`, `disposed`) on `pi.events`.
|
|
@@ -426,7 +438,7 @@ They declare this package as an optional peer dependency and use dynamic import
|
|
|
426
438
|
|
|
427
439
|
## SubagentsService
|
|
428
440
|
|
|
429
|
-
The `SubagentsService` interface, accessor functions, and serializable types are exported from `@
|
|
441
|
+
The `SubagentsService` interface, accessor functions, and serializable types are exported from `@nklisch/pi-subagents` via the root export.
|
|
430
442
|
No separate API package is needed.
|
|
431
443
|
|
|
432
444
|
Consumers declare this package as an optional peer dependency:
|
|
@@ -434,10 +446,10 @@ Consumers declare this package as an optional peer dependency:
|
|
|
434
446
|
```json
|
|
435
447
|
{
|
|
436
448
|
"peerDependencies": {
|
|
437
|
-
"@
|
|
449
|
+
"@nklisch/pi-subagents": ">=18.0.0"
|
|
438
450
|
},
|
|
439
451
|
"peerDependenciesMeta": {
|
|
440
|
-
"@
|
|
452
|
+
"@nklisch/pi-subagents": { "optional": true }
|
|
441
453
|
}
|
|
442
454
|
}
|
|
443
455
|
```
|
|
@@ -445,31 +457,31 @@ Consumers declare this package as an optional peer dependency:
|
|
|
445
457
|
At runtime, consumers use dynamic import for type-safe access to the accessor functions:
|
|
446
458
|
|
|
447
459
|
```typescript
|
|
448
|
-
const { getSubagentsService } = await import("@
|
|
460
|
+
const { getSubagentsService } = await import("@nklisch/pi-subagents");
|
|
449
461
|
const svc = getSubagentsService();
|
|
450
462
|
if (svc) {
|
|
451
|
-
svc.
|
|
463
|
+
void svc.launch("Explore", "Check for stale TODOs", { mode: "detached" });
|
|
452
464
|
}
|
|
453
465
|
```
|
|
454
466
|
|
|
455
467
|
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("@
|
|
468
|
+
The accessor functions use `Symbol.for("@nklisch/pi-subagents:service")` on `globalThis`, which is process-global by spec, to bridge this gap.
|
|
457
469
|
The dynamic import provides compile-time types; the `Symbol.for()` key is the actual runtime channel.
|
|
458
470
|
|
|
459
471
|
### Interface
|
|
460
472
|
|
|
461
|
-
See `src/service.ts` for the canonical definition.
|
|
473
|
+
See `src/service/service.ts` for the canonical definition.
|
|
462
474
|
Key types:
|
|
463
475
|
|
|
464
|
-
- `SubagentsService` — `
|
|
465
|
-
- `SubagentRecord` — serializable agent snapshot
|
|
466
|
-
- `
|
|
476
|
+
- `SubagentsService` — `launch`, `resume`, `stop`, `steer`, `list`, `getResult`, `getRecord`, `waitForAll`, and `hasRunning`.
|
|
477
|
+
- `SubagentRecord` — serializable agent snapshot with run id, mode, status, terminal reason, active runtime, model, and thinking level.
|
|
478
|
+
- `LaunchOptions` — `description`, `model`, `maxTurns`, `thinkingLevel`, `inheritContext`, `mode`, `timeoutSeconds`, and `signal`.
|
|
467
479
|
- `SUBAGENT_EVENTS` — channel constants for `pi.events` subscriptions.
|
|
468
480
|
|
|
469
481
|
### Accessor pattern
|
|
470
482
|
|
|
471
483
|
```typescript
|
|
472
|
-
const SERVICE_KEY = Symbol.for("@
|
|
484
|
+
const SERVICE_KEY = Symbol.for("@nklisch/pi-subagents:service");
|
|
473
485
|
|
|
474
486
|
export function publishSubagentsService(service: SubagentsService): void {
|
|
475
487
|
(globalThis as Record<symbol, unknown>)[SERVICE_KEY] = service;
|
|
@@ -490,12 +502,12 @@ The core emits events on `pi.events` that any extension can observe:
|
|
|
490
502
|
|
|
491
503
|
| Channel | Payload | When |
|
|
492
504
|
| --------------------- | ----------------------------------------------------------------------------------- | --------------------------------------------- |
|
|
493
|
-
| `subagents:started` | `{ id, type, description }`
|
|
494
|
-
| `subagents:completed` | `{ id, type,
|
|
505
|
+
| `subagents:started` | `{ id, type, description, runId, mode }` | Agent begins running |
|
|
506
|
+
| `subagents:completed` | `{ id, type, runId, mode, status, terminalReason, result?, error?, toolUses, activeRuntimeMs, tokens? }` | Agent reaches a terminal state |
|
|
495
507
|
| `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
|
|
508
|
+
| `subagents:failed` | same as `completed` (`buildEventData` shape) | Agent ends in `error` or `stopped` |
|
|
497
509
|
| `subagents:compacted` | `{ id, type, description, reason, tokensBefore, compactionCount }` | Child session compacts |
|
|
498
|
-
| `subagents:created` | `{ id, type, description,
|
|
510
|
+
| `subagents:created` | `{ id, type, description, runId, mode }` | Agent record created (pre-admission) |
|
|
499
511
|
| `subagents:steered` | `{ id, message }` | Steering message delivered to a running agent |
|
|
500
512
|
|
|
501
513
|
These are fire-and-forget broadcast events — no request IDs, no reply channels.
|
|
@@ -624,7 +636,7 @@ The axis that decides push versus pull is whether a need is reactive or discrete
|
|
|
624
636
|
- **Reactive** (ambient state that changes underneath you) → subscribe to the broadcast; be told.
|
|
625
637
|
The state-owner announces; the consumer maintains its own read-model; nobody pulls.
|
|
626
638
|
- **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.
|
|
639
|
+
`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
640
|
|
|
629
641
|
Behavior is a third interface: **tell by id, with outcomes**.
|
|
630
642
|
`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 +688,8 @@ Bags with 10+ fields are the highest priority for decomposition.
|
|
|
676
688
|
|
|
677
689
|
| Interface | Fields | Consumers | Severity |
|
|
678
690
|
| ----------------------------- | ------------------------------------------------------------ | ------------------------------------------------- | --------- |
|
|
679
|
-
| `ResolvedSpawnConfig` | 3 nested |
|
|
680
|
-
| `AgentSpawnConfig` |
|
|
691
|
+
| `ResolvedSpawnConfig` | 3 nested | spawn-config, agent-tool | ✓ done |
|
|
692
|
+
| `AgentSpawnConfig` | execution options + parent identity | subagent-manager (internal) | ✓ done |
|
|
681
693
|
| `CreateSubagentSessionParams` | 6 (snapshot, type, cwd, parentSession, model, thinkingLevel) | create-subagent-session | ✓ done |
|
|
682
694
|
| `TurnLoopOptions` | 4 (maxTurns, defaultMaxTurns, graceTurns, signal) | subagent-session | ✓ done |
|
|
683
695
|
| `SessionConfig` | 6 (flat fields; extensions/noSkills/extras removed in #264) | session-config (output of assembler) | ✓ done |
|
|
@@ -704,7 +716,7 @@ Files with highest commit frequency × complexity:
|
|
|
704
716
|
| 27.1 | `index.ts` | 109 | ▼ cooling |
|
|
705
717
|
| 9.6 | `tools/agent-tool.ts` | 56 | ▼ cooling |
|
|
706
718
|
| 8.8 | `ui/agent-widget.ts` | 22 | ▼ cooling |
|
|
707
|
-
| 7.3 | `
|
|
719
|
+
| 7.3 | `lifecycle/subagent.ts` | 22 | ▼ cooling |
|
|
708
720
|
| 6.6 | `service/service-adapter.ts` | 15 | ▲ accelerating |
|
|
709
721
|
| 6.3 | `config/custom-agents.ts` | 13 | ▼ cooling |
|
|
710
722
|
|
|
@@ -712,9 +724,8 @@ Files with highest commit frequency × complexity:
|
|
|
712
724
|
|
|
713
725
|
### Production duplication
|
|
714
726
|
|
|
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.
|
|
727
|
+
The prior clone group between the execution and formatting paths was resolved in #172.
|
|
728
|
+
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
729
|
|
|
719
730
|
### Session encapsulation debt (Law of Demeter) — resolved by [#277] ✔️
|
|
720
731
|
|
|
@@ -725,11 +736,10 @@ The intent-revealing replacements added by [#277]:
|
|
|
725
736
|
| Reach-through | Sites | Replacement |
|
|
726
737
|
| ---------------------------------------- | ---------------------------------------------------------------------------------- | -------------------------------------------------- |
|
|
727
738
|
| Steer buffer-or-deliver (was duplicated) | `service-adapter.ts`, `steer-tool.ts` | `Subagent.steer(message)` |
|
|
728
|
-
| Conversation viewing | `
|
|
739
|
+
| Conversation viewing | `session-navigation.ts`, `session-navigator.ts` | `Subagent.agentMessages` / transcript sources |
|
|
729
740
|
| 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) |
|
|
741
|
+
| Context-window stats | `steer-tool.ts`, `get-result-tool.ts`, `notification.ts` | `Subagent.getContextPercent()` |
|
|
742
|
+
| Live updates (subscription) | `session-navigator.ts` | `Subagent.subscribeToUpdates(fn)` |
|
|
733
743
|
| Session disposal | `subagent-manager.ts` | `SubagentSession.dispose()` — resolved by [#265] |
|
|
734
744
|
|
|
735
745
|
### Proposed bag decompositions
|
|
@@ -756,7 +766,8 @@ interface SpawnExecution {
|
|
|
756
766
|
effectiveMaxTurns: number | undefined;
|
|
757
767
|
thinking: ThinkingLevel | undefined;
|
|
758
768
|
inheritContext: boolean;
|
|
759
|
-
|
|
769
|
+
mode: SubagentMode;
|
|
770
|
+
timeoutSeconds?: number;
|
|
760
771
|
agentInvocation: AgentInvocation;
|
|
761
772
|
}
|
|
762
773
|
|
|
@@ -768,8 +779,8 @@ interface SpawnPresentation {
|
|
|
768
779
|
}
|
|
769
780
|
```
|
|
770
781
|
|
|
771
|
-
`
|
|
772
|
-
|
|
782
|
+
`agent-tool` consumes all three to build the internal `AgentSpawnConfig` and the result text.
|
|
783
|
+
The joined/detached mode lives in `SpawnExecution`; no separate foreground/background runner exists.
|
|
773
784
|
After decomposition, each consumer declares its real dependencies explicitly.
|
|
774
785
|
|
|
775
786
|
#### AgentSpawnConfig — ParentSessionInfo extracted (done, [#166][166])
|
|
@@ -800,8 +811,7 @@ export interface RunContext {
|
|
|
800
811
|
}
|
|
801
812
|
```
|
|
802
813
|
|
|
803
|
-
The
|
|
804
|
-
`RunOptions` now has 9 fields: 1 nested `context: RunContext` (2 per-call fields) plus 8 flat execution fields.
|
|
814
|
+
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
815
|
|
|
806
816
|
#### SessionConfig (11 fields → extract ToolFilterConfig) — done ([#168][168])
|
|
807
817
|
|
|
@@ -809,7 +819,7 @@ The tool-filtering cluster (`toolNames`, `disallowedSet`, `extensions`) was extr
|
|
|
809
819
|
`filterActiveTools` now accepts a single `ToolFilterConfig` argument instead of three positional parameters.
|
|
810
820
|
`SessionConfig` reduced from 10 to 8 top-level fields.
|
|
811
821
|
|
|
812
|
-
####
|
|
822
|
+
#### Session factory IO (9 methods → 2 focused interfaces) — done ([#167][167])
|
|
813
823
|
|
|
814
824
|
The IO boundary was split into two focused interfaces:
|
|
815
825
|
|
|
@@ -834,13 +844,9 @@ export interface SessionFactoryIO {
|
|
|
834
844
|
) => Promise<{ session: AgentSession }>;
|
|
835
845
|
assemblerIO: AssemblerIO;
|
|
836
846
|
}
|
|
837
|
-
|
|
838
|
-
/** Backward-compatible intersection of the two focused interfaces. */
|
|
839
|
-
export type RunnerIO = EnvironmentIO & SessionFactoryIO;
|
|
840
847
|
```
|
|
841
848
|
|
|
842
|
-
`
|
|
843
|
-
All existing consumers satisfy both sub-interfaces via structural typing with no call-site changes.
|
|
849
|
+
The factory consumes the `EnvironmentIO & SessionFactoryIO` boundary directly; no runner implementation or compatibility alias remains.
|
|
844
850
|
|
|
845
851
|
## Phase 11 (complete)
|
|
846
852
|
|
|
@@ -924,6 +930,10 @@ See [phase-19-implement-ui-decisions.md](history/phase-19-implement-ui-decisions
|
|
|
924
930
|
|
|
925
931
|
## Phase 20 improvement roadmap
|
|
926
932
|
|
|
933
|
+
> Planning note: this roadmap records the pre-execution-control baseline. The
|
|
934
|
+
> joined/detached execution-control work below supersedes any obsolete runner,
|
|
935
|
+
> unbounded-result, and foreground/background vocabulary in these notes.
|
|
936
|
+
|
|
927
937
|
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
938
|
|
|
929
939
|
Discovery findings (fallow + entry-point trace + test-constructibility audit, 2026-07-03):
|
|
@@ -969,9 +979,8 @@ Target files:
|
|
|
969
979
|
|
|
970
980
|
Outcome: `execute` ≤ 30 lines with cyclomatic < 10; off the fallow high-complexity list.
|
|
971
981
|
|
|
972
|
-
Landed:
|
|
973
|
-
`
|
|
974
|
-
`get-result-tool.execute` is off the HIGH-CRAP list (3 → 2 remaining: `service-adapter.spawn`, the notification renderer arrow).
|
|
982
|
+
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.
|
|
983
|
+
`get-result-tool.execute` remains a focused lookup-and-render boundary.
|
|
975
984
|
|
|
976
985
|
`Release: batch "result-delivery"`
|
|
977
986
|
|
|
@@ -1016,8 +1025,6 @@ Target files:
|
|
|
1016
1025
|
|
|
1017
1026
|
- `src/ui/agent-widget.ts` — replace `tui: any` with a lean local interface (`terminal.columns`, `requestRender()`); shrink the 4-rule file-level disable.
|
|
1018
1027
|
- `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
1028
|
Some disables are irreducible SDK export gaps; the goal is line-level precision, not zero.
|
|
1022
1029
|
|
|
1023
1030
|
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;
|
|
@@ -5,6 +5,11 @@ date: 2026-06-18
|
|
|
5
5
|
|
|
6
6
|
# 0004 — Reconsider the UI direction from first principles
|
|
7
7
|
|
|
8
|
+
> Historical vocabulary note: this decision predates the joined/detached clean
|
|
9
|
+
> break. In current code, its "background-only widget" means detached-only;
|
|
10
|
+
> joined runs use their inline result surface. Historical delivery labels below
|
|
11
|
+
> are retained as decision history, not as current API contracts.
|
|
12
|
+
|
|
8
13
|
## Status
|
|
9
14
|
|
|
10
15
|
Accepted.
|