@gotgenes/pi-subagents 16.6.0 → 17.0.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 +11 -0
- package/dist/public.d.ts +4 -1
- package/docs/architecture/architecture.md +32 -26
- package/docs/plans/0422-delete-activity-tracker-ui-observer.md +204 -0
- package/docs/plans/0423-widget-self-drive-from-lifecycle.md +264 -0
- package/docs/plans/0424-drop-widget-dep-from-subagent-tool.md +166 -0
- package/docs/plans/0425-reconcile-subagent-events-contract.md +144 -0
- package/docs/retro/0421-migrate-activity-readers-to-record-getters.md +49 -0
- package/docs/retro/0422-delete-activity-tracker-ui-observer.md +97 -0
- package/docs/retro/0423-widget-self-drive-from-lifecycle.md +112 -0
- package/docs/retro/0424-drop-widget-dep-from-subagent-tool.md +89 -0
- package/docs/retro/0425-reconcile-subagent-events-contract.md +46 -0
- package/package.json +1 -1
- package/src/index.ts +11 -3
- package/src/observation/composite-subagent-observer.ts +49 -0
- package/src/runtime.ts +0 -6
- package/src/service/service.ts +4 -1
- package/src/tools/agent-tool.ts +1 -36
- package/src/tools/background-spawner.ts +1 -25
- package/src/tools/foreground-runner.ts +1 -30
- package/src/types.ts +1 -1
- package/src/ui/agent-widget.ts +34 -14
- package/src/ui/agent-activity-tracker.ts +0 -84
- package/src/ui/ui-observer.ts +0 -61
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [17.0.0](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v16.6.0...pi-subagents-v17.0.0) (2026-06-18)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### ⚠ BREAKING CHANGES
|
|
12
|
+
|
|
13
|
+
* SUBAGENT_EVENTS.ACTIVITY ("subagents:activity") is removed. It was never emitted, so no consumer could act on it, and there is no replacement — the activity tier was removed in Phase 18. Consumers should subscribe to the now-declared FAILED, COMPACTED, CREATED, and STEERED channels instead.
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* reconcile SUBAGENT_EVENTS with emitted channels ([#425](https://github.com/gotgenes/pi-packages/issues/425)) ([ba0c48b](https://github.com/gotgenes/pi-packages/commit/ba0c48b294123c1498db2040b1037adcd7ad4e4e))
|
|
18
|
+
|
|
8
19
|
## [16.6.0](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v16.5.0...pi-subagents-v16.6.0) (2026-06-17)
|
|
9
20
|
|
|
10
21
|
|
package/dist/public.d.ts
CHANGED
|
@@ -154,7 +154,10 @@ interface SubagentsService {
|
|
|
154
154
|
declare const SUBAGENT_EVENTS: {
|
|
155
155
|
readonly STARTED: "subagents:started";
|
|
156
156
|
readonly COMPLETED: "subagents:completed";
|
|
157
|
-
readonly
|
|
157
|
+
readonly FAILED: "subagents:failed";
|
|
158
|
+
readonly COMPACTED: "subagents:compacted";
|
|
159
|
+
readonly CREATED: "subagents:created";
|
|
160
|
+
readonly STEERED: "subagents:steered";
|
|
158
161
|
};
|
|
159
162
|
/** Publish the SubagentsService on globalThis for cross-extension access. */
|
|
160
163
|
declare function publishSubagentsService(service: SubagentsService): void;
|
|
@@ -63,9 +63,8 @@ flowchart TB
|
|
|
63
63
|
|
|
64
64
|
subgraph observation["Observation domain"]
|
|
65
65
|
direction TB
|
|
66
|
-
RecordObserver["record-observer<br/>(stats via events)"]
|
|
66
|
+
RecordObserver["record-observer<br/>(stats + live activity via events)"]
|
|
67
67
|
Notification["notification<br/>(completion nudges)"]
|
|
68
|
-
UIObserver["ui-observer<br/>(streaming state)"]
|
|
69
68
|
end
|
|
70
69
|
|
|
71
70
|
subgraph tools["Tools domain"]
|
|
@@ -95,8 +94,8 @@ flowchart TB
|
|
|
95
94
|
SessionConfig --> Prompts & Env
|
|
96
95
|
AgentTypeRegistry --> DefaultAgents & CustomAgents
|
|
97
96
|
RecordObserver -.->|subscribes| SubagentSession
|
|
98
|
-
UIObserver -.->|subscribes| SubagentSession
|
|
99
97
|
Widget -.->|polls| SubagentManager
|
|
98
|
+
SubagentManager -.->|notifies| Widget
|
|
100
99
|
```
|
|
101
100
|
|
|
102
101
|
### Key domain types
|
|
@@ -258,7 +257,7 @@ sequenceDiagram
|
|
|
258
257
|
Asm-->>Factory: SessionConfig
|
|
259
258
|
Factory->>Child: create session + bind extensions
|
|
260
259
|
Factory-->>Ag: SubagentSession (born complete)
|
|
261
|
-
Note over Ag:
|
|
260
|
+
Note over Ag: record-observer subscribes to session events
|
|
262
261
|
Ag->>Sub: runTurnLoop(prompt, opts)
|
|
263
262
|
Sub->>Child: prompt + drive turn loop
|
|
264
263
|
Child-->>Sub: result text
|
|
@@ -322,6 +321,7 @@ src/
|
|
|
322
321
|
│ ├── notification.ts completion nudges
|
|
323
322
|
│ ├── notification-state.ts per-agent notification tracking
|
|
324
323
|
│ ├── renderer.ts notification TUI component
|
|
324
|
+
│ ├── composite-subagent-observer.ts fans manager notifications out to multiple observers
|
|
325
325
|
│ └── subagent-events-observer.ts manager lifecycle observer (event emission + persistence + notification)
|
|
326
326
|
│
|
|
327
327
|
├── service/ cross-extension API boundary
|
|
@@ -346,10 +346,8 @@ src/
|
|
|
346
346
|
│ ├── agent-creation-wizard.ts agent creation (AgentCreationWizard class)
|
|
347
347
|
│ ├── conversation-viewer.ts scrollable session overlay
|
|
348
348
|
│ ├── message-formatters.ts pure per-message-type formatters (extracted from conversation-viewer)
|
|
349
|
-
│ ├── agent-activity-tracker.ts live activity state tracker
|
|
350
349
|
│ ├── agent-file-ops.ts filesystem abstraction
|
|
351
350
|
│ ├── agent-file-writer.ts overwrite-guard + write + reload + notify helper
|
|
352
|
-
│ ├── ui-observer.ts session-event observer for streaming
|
|
353
351
|
│ └── display.ts pure formatters and shared types
|
|
354
352
|
│
|
|
355
353
|
└── handlers/ event handlers
|
|
@@ -361,11 +359,11 @@ src/
|
|
|
361
359
|
|
|
362
360
|
### Observation model
|
|
363
361
|
|
|
364
|
-
Record statistics (tool uses, token usage, compaction counts) are updated by `record-observer.ts`, which subscribes directly to session events.
|
|
365
|
-
|
|
366
|
-
Neither observer wraps or forwards the other — both subscribe directly to the session.
|
|
362
|
+
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.
|
|
363
|
+
This is the single per-child session subscription — all run state lives on the `Subagent` record.
|
|
367
364
|
|
|
368
|
-
The widget reads agent state by polling
|
|
365
|
+
The widget reads agent state by polling the records exposed via `SubagentManager.listAgents()` every 80 ms; that poll loop is now started by the manager's lifecycle notifications (the widget subscribes as a `SubagentManagerObserver` fanned out through `CompositeSubagentObserver`), not by inbound calls from the spawn tools.
|
|
366
|
+
The conversation viewer subscribes to session events via `Subagent.subscribeToUpdates()` and reads messages via `Subagent.messages` — no direct `AgentSession` reference (#277).
|
|
369
367
|
|
|
370
368
|
## Cross-extension architecture
|
|
371
369
|
|
|
@@ -483,11 +481,14 @@ If Pi gains a native service registry ([earendil-works/pi#4207]), these accessor
|
|
|
483
481
|
|
|
484
482
|
The core emits events on `pi.events` that any extension can observe:
|
|
485
483
|
|
|
486
|
-
| Channel | Payload
|
|
487
|
-
| --------------------- |
|
|
488
|
-
| `subagents:started` | `{ id, type, description }`
|
|
489
|
-
| `subagents:completed` | `{ id, type, status, result?, error? }`
|
|
490
|
-
| `subagents:
|
|
484
|
+
| Channel | Payload | When |
|
|
485
|
+
| --------------------- | ----------------------------------------------------------------------------------- | --------------------------------------------- |
|
|
486
|
+
| `subagents:started` | `{ id, type, description }` | Agent begins running |
|
|
487
|
+
| `subagents:completed` | `{ id, type, description, status, result?, error?, toolUses, durationMs, tokens? }` | Agent finishes successfully |
|
|
488
|
+
| `subagents:failed` | same as `completed` (`buildEventData` shape) | Agent ends in `error`/`stopped`/`aborted` |
|
|
489
|
+
| `subagents:compacted` | `{ id, type, description, reason, tokensBefore, compactionCount }` | Child session compacts |
|
|
490
|
+
| `subagents:created` | `{ id, type, description, isBackground }` | Background agent created (pre-admission) |
|
|
491
|
+
| `subagents:steered` | `{ id, message }` | Steering message delivered to a running agent |
|
|
491
492
|
|
|
492
493
|
These are fire-and-forget broadcast events — no request IDs, no reply channels.
|
|
493
494
|
|
|
@@ -965,25 +966,30 @@ Folding the live activity onto the record (the single owner of run state, consis
|
|
|
965
966
|
Smell: Category C (Law of Demeter).
|
|
966
967
|
Outcome: no consumer references `AgentActivityTracker`.
|
|
967
968
|
Landed: `WidgetAgent` folds the live-activity fields and a `contextPercent` projection; `AgentWidget` projects records; `ConversationViewer`, `AgentsMenuHandler`, `buildDetails`, and `buildNotificationDetails` read off the record; `NotificationSystem.cleanupCompleted` removed; `SubagentEventsObserver` returns early on consumed results; +8 tests (1058 → 1066).
|
|
968
|
-
3.
|
|
969
|
+
3. **✅ Delete `AgentActivityTracker` and `ui-observer`; drop the activity map from the runtime and spawn tools — complete.**
|
|
969
970
|
([#422]) Target: `ui/agent-activity-tracker.ts` (delete), `ui/ui-observer.ts` (delete), `runtime.ts`, `tools/foreground-runner.ts`, `tools/background-spawner.ts`.
|
|
970
971
|
The spawn tools stop constructing trackers, subscribing, and populating maps; `SubagentRuntime.agentActivity` is removed.
|
|
971
972
|
Smell: Category A + C. Outcome: −145 LOC, one session subscription per child, runtime holds zero UI state.
|
|
972
|
-
|
|
973
|
-
|
|
973
|
+
Landed: deleted `agent-activity-tracker.ts` (84) + `ui-observer.ts` (61) and their unit suites; dropped the `agentActivity` parameter from `runForeground`/`spawnBackground`, the `AgentActivityAccess` interface, and the `AgentToolRuntime`/`SubagentRuntime` activity-map fields; the foreground `observer.onSessionCreated` keeps `recordRef`/`fgId` binding and `widget.ensureTimer`; −34 tests (1066 → 1032).
|
|
974
|
+
4. **✅ Make the widget self-drive from lifecycle events — complete.**
|
|
975
|
+
([#423]) Target: `ui/agent-widget.ts`, `observation/composite-subagent-observer.ts` (new), `index.ts`.
|
|
974
976
|
The widget starts/stops its timer in response to started/created/completed notifications instead of tool calls; spawn tools no longer call `ensureTimer`/`update`/`markFinished`.
|
|
975
977
|
Smell: Category C (coupling direction).
|
|
976
978
|
Outcome: the widget is a reactive consumer; no inbound calls from core spawn tools.
|
|
977
|
-
|
|
979
|
+
Landed: `AgentWidget implements SubagentManagerObserver` (starts the 80 ms loop on `onSubagentStarted`/`onSubagentCreated`, re-renders on `onSubagentCompleted`/`onSubagentCompacted`); a new `CompositeSubagentObserver` fans the manager's single observer slot out to `[eventsObserver, widget]` (wired in `index.ts`, keeping `SubagentManager` unchanged); dropped the `widget` parameter and `ForegroundWidgetDeps`/`BackgroundWidgetDeps` interfaces from both spawners, deleted `AgentWidget.markFinished` (redundant with `seedFinishedAgents`), made `ensureTimer` private, and narrowed `AgentToolWidget` to `setUICtx`; +11 tests (1032 → 1043, then −4 with the dropped spawner widget-driving tests → 1039).
|
|
980
|
+
5. **✅ Drop the widget dependency from the `subagent` tool — complete.**
|
|
978
981
|
([#424]) Target: `tools/agent-tool.ts`, `test/helpers/make-deps.ts`.
|
|
979
|
-
`AgentTool` loses its `widget`
|
|
982
|
+
`AgentTool` loses its `widget` constructor param (UICtx capture stays in `ToolStartHandler`); `createToolDeps` sheds the widget stub.
|
|
983
|
+
The activity-map (`agentActivity`) dependency this step originally named was already removed from the tool and runtime in Step 3 ([#422]), so only `widget` remained to drop.
|
|
980
984
|
Smell: Category C/D.
|
|
981
|
-
Outcome: the LLM tool depends only on manager/runtime/settings/registry; fixture drops
|
|
982
|
-
|
|
985
|
+
Outcome: the LLM tool depends only on manager/runtime/settings/registry; fixture drops 1 field.
|
|
986
|
+
Landed: removed the `widget` constructor param and the redundant `this.widget.setUICtx(ctx.ui)` call from `AgentTool.execute`, deleted the `AgentToolWidget` interface and its `UICtx` import, updated the sole `index.ts` call site, and dropped the `widget` field/stub plus two now-obsolete tests (`agent-tool` UICtx capture, `make-deps` widget defaults) — UICtx capture is pinned by `handlers/tool-start.test.ts`; −2 tests (1039 → 1037).
|
|
987
|
+
6. **✅ Reconcile the public event contract — complete.**
|
|
983
988
|
([#425]) Target: `service/service.ts`, this document's lifecycle-events table.
|
|
984
989
|
Remove the vacant `ACTIVITY` channel (or emit a real broadcast for it) and add the emitted `failed`/`compacted`/`created` channels so declared constants match emitted events.
|
|
985
990
|
Smell: Category A/E.
|
|
986
991
|
Outcome: declared channels equal emitted channels; no vacant hook.
|
|
992
|
+
Landed: removed `SUBAGENT_EVENTS.ACTIVITY` (breaking) and added `FAILED`/`COMPACTED`/`CREATED`/`STEERED` — `subagents:steered` (from `steer-tool.ts`) was also emitted-but-undeclared, so all four emitted agent-lifecycle channels are now declared; corrected the stale `subagents:completed` payload in the lifecycle-events table to the real `buildEventData` shape; +1 test (1037 → 1038).
|
|
987
993
|
7. **Consolidate residual test clone families.**
|
|
988
994
|
([#426]) Target: `test/settings.test.ts` + `test/layered-settings.test.ts`, `test/lifecycle/create-subagent-session.test.ts`, `test/ui/agent-config-editor.test.ts`.
|
|
989
995
|
Extract shared fixtures for the clone families fallow reports that the spine does not already rewrite.
|
|
@@ -1010,10 +1016,10 @@ Folding the live activity onto the record (the single owner of run state, consis
|
|
|
1010
1016
|
flowchart TB
|
|
1011
1017
|
S1["1 — Fold metrics + activity onto record (#420) ✅"]
|
|
1012
1018
|
S2["2 — Migrate readers to record getters (#421) ✅"]
|
|
1013
|
-
S3["3 — Delete tracker + ui-observer, drop activity map (#422)"]
|
|
1014
|
-
S4["4 — Widget self-drives on events (#423)"]
|
|
1015
|
-
S5["5 — Drop widget dep from subagent tool (#424)"]
|
|
1016
|
-
S6["6 — Reconcile public event contract (#425)"]
|
|
1019
|
+
S3["3 — Delete tracker + ui-observer, drop activity map (#422) ✅"]
|
|
1020
|
+
S4["4 — Widget self-drives on events (#423) ✅"]
|
|
1021
|
+
S5["5 — Drop widget dep from subagent tool (#424) ✅"]
|
|
1022
|
+
S6["6 — Reconcile public event contract (#425) ✅"]
|
|
1017
1023
|
S7["7 — Consolidate test clone families (#426)"]
|
|
1018
1024
|
S8["8 — Reconsider UI direction, ADR (#427)"]
|
|
1019
1025
|
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
---
|
|
2
|
+
issue: 422
|
|
3
|
+
issue_title: "pi-subagents: delete AgentActivityTracker and ui-observer, drop the activity map from the core"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Delete AgentActivityTracker and ui-observer, drop the activity map from the core
|
|
7
|
+
|
|
8
|
+
## Problem Statement
|
|
9
|
+
|
|
10
|
+
The activity tier is the UI's live-streaming bookkeeping, but today it lives inside the core.
|
|
11
|
+
A `Map<string, AgentActivityTracker>` sits on the core composition root (`SubagentRuntime`), and the two spawn tools construct trackers, open a second session subscription (`subscribeUIObserver`), and populate or delete the map.
|
|
12
|
+
After Phase 18 Step 2 ([#421]) migrated every reader to the record getters, nothing reads the trackers or the map any longer — they are dead bookkeeping the core still maintains.
|
|
13
|
+
This is the third step of the Phase 18 spine (activity-tier disentanglement): delete `AgentActivityTracker` and `ui-observer`, and remove the activity map from `SubagentRuntime` and the spawn tools.
|
|
14
|
+
|
|
15
|
+
## Goals
|
|
16
|
+
|
|
17
|
+
- Delete `src/ui/agent-activity-tracker.ts` and `src/ui/ui-observer.ts` (~145 LOC).
|
|
18
|
+
- Remove `agentActivity` from `SubagentRuntime` (`src/runtime.ts`) and from the `AgentToolRuntime` slice (`src/tools/agent-tool.ts`).
|
|
19
|
+
- Stop constructing trackers, calling `subscribeUIObserver` / `setSession`, and populating or deleting the map in `src/tools/foreground-runner.ts` and `src/tools/background-spawner.ts`.
|
|
20
|
+
- Remove the now-unused `AgentActivityAccess` interface and the `agentActivity` parameter from both spawner functions.
|
|
21
|
+
- Leave each child session with exactly one session subscription (the core's own `record-observer`) and zero UI state on the runtime.
|
|
22
|
+
- Keep the existing test suite green at every commit.
|
|
23
|
+
|
|
24
|
+
This is **not** a breaking change.
|
|
25
|
+
`AgentActivityTracker`, `ui-observer`, and `SubagentRuntime.agentActivity` are internal symbols — none appear in the public service surface (`src/service/service.ts`) or the settings entry (`src/layered-settings.ts`).
|
|
26
|
+
Observable behavior is unchanged; commits use `refactor:` / `docs:`.
|
|
27
|
+
|
|
28
|
+
## Non-Goals
|
|
29
|
+
|
|
30
|
+
- Changing how the widget starts/stops its timer — the spawn tools still call `widget.ensureTimer` / `update` / `markFinished` after this step; that decoupling is Phase 18 Step 4 ([#423]).
|
|
31
|
+
- Dropping the `widget` or activity-map constructor params from the `subagent` tool — that is Phase 18 Step 5 ([#424]).
|
|
32
|
+
- Touching `record-observer.ts`, `SubagentState`, or the record getters added in Steps 1–2.
|
|
33
|
+
- Reconciling the public event contract (Step 6) or any UI-distribution decision (Step 8).
|
|
34
|
+
|
|
35
|
+
## Background
|
|
36
|
+
|
|
37
|
+
Relevant modules and their current relationships:
|
|
38
|
+
|
|
39
|
+
- `src/ui/agent-activity-tracker.ts` — `AgentActivityTracker` class (active tools, response text, turn count, session ref).
|
|
40
|
+
Constructed per-spawn in both spawner tools; written via transition methods; no longer read after [#421].
|
|
41
|
+
- `src/ui/ui-observer.ts` — `subscribeUIObserver(session, tracker, onUpdate?)` opens a second session subscription parallel to `record-observer` and streams events into the tracker.
|
|
42
|
+
- `src/runtime.ts` — `SubagentRuntime.agentActivity: Map<string, AgentActivityTracker>`, the UI streaming-state map on the core composition root.
|
|
43
|
+
- `src/tools/agent-tool.ts` — declares the `AgentActivityAccess` interface and the `AgentToolRuntime.agentActivity` field; passes `this.runtime.agentActivity` into both spawners.
|
|
44
|
+
- `src/tools/foreground-runner.ts` — constructs `fgState`, calls `setSession` + `subscribeUIObserver`, populates and deletes the map; its `streamUpdate` already reads activity off the record (`recordRef`), not the tracker.
|
|
45
|
+
- `src/tools/background-spawner.ts` — constructs `bgState`, calls `setSession` + `subscribeUIObserver` inside an `observer.onSessionCreated`, populates the map.
|
|
46
|
+
|
|
47
|
+
The architecture doc records this as Phase 18 Step 3 (`docs/architecture/architecture.md`, roadmap and step-dependency diagram), with the explicit outcome "−145 LOC, one session subscription per child, runtime holds zero UI state."
|
|
48
|
+
|
|
49
|
+
AGENTS.md constraints that apply:
|
|
50
|
+
|
|
51
|
+
- Run `pnpm fallow dead-code` locally before pushing — deleting modules can orphan sibling exports.
|
|
52
|
+
- pi-subagents is a narrow core with no UI policy; removing UI bookkeeping from the core moves it in the documented direction (dependency arrows point inward).
|
|
53
|
+
|
|
54
|
+
## Design Overview
|
|
55
|
+
|
|
56
|
+
This step is a deletion enabled by Step 2, not a new abstraction.
|
|
57
|
+
The two structural wins are removing an output-argument pattern (`agentActivity.set(...)` / `.delete(...)` writes into a received map) and narrowing two function signatures by dropping the `agentActivity` parameter.
|
|
58
|
+
|
|
59
|
+
### Foreground runner
|
|
60
|
+
|
|
61
|
+
The `observer.onSessionCreated` callback stays — it is still the only place `recordRef` and `fgId` are bound mid-flight (while `spawnAndWait` is in progress) and where `widget.ensureTimer()` fires.
|
|
62
|
+
Only the tracker lines are removed.
|
|
63
|
+
The post-change callback:
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
observer: {
|
|
67
|
+
onSessionCreated: (agent) => {
|
|
68
|
+
recordRef = agent;
|
|
69
|
+
fgId = agent.id;
|
|
70
|
+
widget.ensureTimer();
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The `fgState` construction, the `unsubUI` variable and its two `unsubUI?.()` cleanup calls, and `agentActivity.set` / `agentActivity.delete` all go.
|
|
76
|
+
`streamUpdate` is unchanged — it already reads `recordRef?.turnCount`, `recordRef?.activeTools`, `recordRef?.responseText`.
|
|
77
|
+
Re-renders are driven by the existing 80 ms spinner interval, which reads fresh record state populated by the core's `record-observer`.
|
|
78
|
+
|
|
79
|
+
### Background spawner
|
|
80
|
+
|
|
81
|
+
`onSessionCreated` in the background spawner did **only** tracker work (`bgState.setSession`, `subscribeUIObserver`), so the entire `observer` block is removed from the spawn opts.
|
|
82
|
+
The post-spawn `widget.ensureTimer()` and `widget.update()` calls (outside the observer) stay.
|
|
83
|
+
The `bgState` construction and `agentActivity.set(id, bgState)` go.
|
|
84
|
+
|
|
85
|
+
### Agent tool
|
|
86
|
+
|
|
87
|
+
`AgentTool` stops passing `this.runtime.agentActivity` to both spawners (Step "remove param").
|
|
88
|
+
The `AgentActivityAccess` interface, the `AgentToolRuntime.agentActivity` field, and the `import { AgentActivityTracker }` are removed once no caller references them.
|
|
89
|
+
|
|
90
|
+
### Runtime
|
|
91
|
+
|
|
92
|
+
`SubagentRuntime.agentActivity` and its `import type { AgentActivityTracker }` are removed, along with the field's doc comment.
|
|
93
|
+
The session-context methods and `createSubagentRuntime` are untouched.
|
|
94
|
+
|
|
95
|
+
## Module-Level Changes
|
|
96
|
+
|
|
97
|
+
Source:
|
|
98
|
+
|
|
99
|
+
- `src/tools/foreground-runner.ts` — remove `AgentActivityTracker` import, `subscribeUIObserver` import, `AgentActivityAccess` import, the `agentActivity` parameter, `fgState`, `unsubUI` (+ both `unsubUI?.()` calls), `agentActivity.set`, `agentActivity.delete`; trim the doc comment that lists "AgentActivityTracker creation, UI observer subscription".
|
|
100
|
+
- `src/tools/background-spawner.ts` — remove `AgentActivityTracker` import, `subscribeUIObserver` import, `AgentActivityAccess` import, the `agentActivity` parameter, `bgState`, the entire `observer` block, `agentActivity.set`; trim the doc comment.
|
|
101
|
+
- `src/tools/agent-tool.ts` — remove `AgentActivityAccess` interface, `AgentToolRuntime.agentActivity` field, `import { AgentActivityTracker }`, and the two `this.runtime.agentActivity` arguments to `spawnBackground` / `runForeground`.
|
|
102
|
+
- `src/runtime.ts` — remove `agentActivity` field (+ doc comment) and `import type { AgentActivityTracker }`.
|
|
103
|
+
- `src/types.ts` — reword the `SubscribableSession` doc comment from "Used by record-observer and ui-observer" to reference `record-observer` only.
|
|
104
|
+
- `src/ui/agent-activity-tracker.ts` — **delete**.
|
|
105
|
+
- `src/ui/ui-observer.ts` — **delete**.
|
|
106
|
+
|
|
107
|
+
Tests:
|
|
108
|
+
|
|
109
|
+
- `test/ui/agent-activity-tracker.test.ts` — **delete**.
|
|
110
|
+
- `test/ui/ui-observer.test.ts` — **delete**.
|
|
111
|
+
- `test/tools/foreground-runner.test.ts` — drop the `runtime.agentActivity` argument from every `runForeground(...)` call; remove the "registers activity tracker in agentActivity on session creation" test (redundant with the ensureTimer/markFinished test).
|
|
112
|
+
- `test/tools/background-spawner.test.ts` — drop the `runtime.agentActivity` argument from every `spawnBackground(...)` call; remove the "registers an AgentActivityTracker in agentActivity map" test and the `AgentActivityTracker` import.
|
|
113
|
+
- `test/tools/agent-tool.test.ts` — remove the "registers activity in agentActivity map" test.
|
|
114
|
+
- `test/runtime.test.ts` — remove the "agentActivity map is independently mutable" and "multiple instances are isolated" tests, the two `agentActivity` assertions in "returns correct defaults", and the `AgentActivityTracker` import.
|
|
115
|
+
- `test/helpers/make-deps.ts` — remove the `agentActivity` map construction, the `agentActivity` field on the runtime stub, and the `AgentActivityTracker` import; update the runtime doc comment.
|
|
116
|
+
- `test/helpers/make-deps.test.ts` — remove the "agentActivity is an empty Map on the runtime" test, the "runtime.agentActivity satisfies AgentActivityAccess" test, and the `AgentActivityTracker` import.
|
|
117
|
+
|
|
118
|
+
Docs:
|
|
119
|
+
|
|
120
|
+
- `docs/architecture/architecture.md`:
|
|
121
|
+
- File tree (around line 350) — remove the `agent-activity-tracker.ts` and `ui-observer.ts` entries.
|
|
122
|
+
- "Observation model" prose (around lines 365–368) — drop the "UI streaming … is handled by `ui/ui-observer.ts`" sentence and the stale "widget reads agent state by polling a shared `Map<string, AgentActivityTracker>`" sentence (the widget reads off records since [#421]).
|
|
123
|
+
- System diagram (around line 68) — remove the `ui-observer` node.
|
|
124
|
+
- Sequence-diagram note (around line 261) — drop "+ ui-observer" so it reads "agent-observer subscribes to session events".
|
|
125
|
+
- Phase 18 roadmap Step 3 entry — mark complete (✅) with a `Landed:` bullet, matching the Steps 1–2 format.
|
|
126
|
+
- Phase 18 health-metrics table — the "Activity-tier modules slated for removal" row becomes historical; leave the snapshot but ensure the Step 3 `Landed:` bullet records the realized LOC delta.
|
|
127
|
+
- `.pi/skills/package-pi-subagents/SKILL.md`:
|
|
128
|
+
- Module-dependency-flow block — remove `←─subscribes─ ui-observer` from the `record-observer ─subscribes─→ AgentSession` line.
|
|
129
|
+
- Domain table — UI directory count `12 → 10`; domain header "seven domains (59 files)" → "(57 files)".
|
|
130
|
+
|
|
131
|
+
Historical docs under `docs/plans/`, `docs/retro/`, and `docs/architecture/history/` reference these symbols as records of past work and are **not** edited.
|
|
132
|
+
|
|
133
|
+
## Test Impact Analysis
|
|
134
|
+
|
|
135
|
+
This is a deletion, not an extraction, so it enables no new lower-level tests.
|
|
136
|
+
|
|
137
|
+
1. New tests enabled: none — the deleted modules' behavior is gone, not relocated.
|
|
138
|
+
2. Tests that become redundant: the tracker/observer unit suites (`agent-activity-tracker.test.ts`, `ui-observer.test.ts`) test deleted code and are removed wholesale; the "registers in agentActivity map" tests across `foreground-runner`, `background-spawner`, `agent-tool`, `runtime`, and `make-deps` test removed state and are deleted.
|
|
139
|
+
3. Tests that must stay: the spawner result-text tests, the `ensureTimer` / `markFinished` / `update` widget-driving tests, the foreground streaming-`onUpdate` test, and the runtime session-context tests — they exercise behavior that survives this step.
|
|
140
|
+
|
|
141
|
+
## Invariants at risk
|
|
142
|
+
|
|
143
|
+
This step touches surfaces refactored by Phase 18 Steps 1–2.
|
|
144
|
+
The relevant prior `Landed:` invariants and the tests that pin them:
|
|
145
|
+
|
|
146
|
+
- "no consumer references `AgentActivityTracker`" (Step 2 outcome) — pinned by the type checker: after this step the symbol is deleted, so any surviving reference fails `pnpm run check`.
|
|
147
|
+
The foreground `streamUpdate` reading off `recordRef` (Step 2) must remain — covered by `test/tools/foreground-runner.test.ts` "calls onUpdate with streaming details while running".
|
|
148
|
+
- "`Subagent` is the single home for all run state; getters available" (Step 1 outcome) — unchanged here; the getters keep their existing coverage in `test/lifecycle/` and `test/observation/`.
|
|
149
|
+
- Foreground re-render after dropping the second subscription — pinned by the streaming-`onUpdate` test (spinner-driven tick), confirming re-renders survive without `subscribeUIObserver`.
|
|
150
|
+
|
|
151
|
+
No new test is required; the type checker plus the surviving streaming test cover the at-risk invariants.
|
|
152
|
+
|
|
153
|
+
## TDD Order
|
|
154
|
+
|
|
155
|
+
This is primarily code deletion; each step is a `refactor:`/`docs:` commit that keeps `pnpm run check` and the full suite green.
|
|
156
|
+
Steps are ordered so no commit leaves a dangling type reference.
|
|
157
|
+
|
|
158
|
+
1. **Remove tracker wiring + the `agentActivity` parameter from the spawners.**
|
|
159
|
+
Edit `foreground-runner.ts` and `background-spawner.ts` to drop tracker construction, `subscribeUIObserver`/`setSession`, map writes, and the `agentActivity` parameter; update the two `AgentTool` call sites; update `foreground-runner.test.ts` and `background-spawner.test.ts` (drop the arg, remove the "registers tracker" tests and the `AgentActivityTracker` import in the background test).
|
|
160
|
+
The parameter removal cascades to call sites and tests at the type level, so they land together.
|
|
161
|
+
Run `pnpm run check` immediately after — shared-signature change.
|
|
162
|
+
Commit: `refactor: stop wiring activity trackers in the spawn tools (#422)`.
|
|
163
|
+
|
|
164
|
+
2. **Remove the activity map from the runtime and the agent-tool slice.**
|
|
165
|
+
Delete `SubagentRuntime.agentActivity` (`runtime.ts`), the `AgentActivityAccess` interface, the `AgentToolRuntime.agentActivity` field, and the `AgentActivityTracker` import in `agent-tool.ts`; update `make-deps.ts` (drop the map + field), and all tests reading the field (`runtime.test.ts`, `make-deps.test.ts`, `agent-tool.test.ts`).
|
|
166
|
+
Removing the field and `AgentActivityAccess` export breaks every reader at the type level, so all consumer + test updates land in this commit.
|
|
167
|
+
Run `pnpm run check` immediately after.
|
|
168
|
+
Commit: `refactor: drop the activity map from the runtime and agent tool (#422)`.
|
|
169
|
+
|
|
170
|
+
3. **Delete the dead modules and their tests.**
|
|
171
|
+
Delete `src/ui/agent-activity-tracker.ts`, `src/ui/ui-observer.ts`, `test/ui/agent-activity-tracker.test.ts`, `test/ui/ui-observer.test.ts`; reword the `SubscribableSession` comment in `types.ts`.
|
|
172
|
+
Run `pnpm fallow dead-code` to confirm no sibling export (e.g. `SessionLike`, `SubscribableSession`) was orphaned.
|
|
173
|
+
Commit: `refactor: delete AgentActivityTracker and ui-observer (#422)`.
|
|
174
|
+
|
|
175
|
+
4. **Update the architecture doc and package skill.**
|
|
176
|
+
Apply the doc edits listed in Module-Level Changes (file tree, observation-model prose, system + sequence diagrams, Phase 18 Step 3 ✅ + `Landed:` bullet, SKILL.md flow diagram and domain counts).
|
|
177
|
+
Verify any touched Mermaid renders (load the `mermaid` skill).
|
|
178
|
+
Commit: `docs: mark Phase 18 Step 3 complete and remove activity-tier references (#422)`.
|
|
179
|
+
|
|
180
|
+
## Risks and Mitigations
|
|
181
|
+
|
|
182
|
+
- **Foreground re-render cadence.**
|
|
183
|
+
Dropping `subscribeUIObserver` removes event-driven re-renders; updates now rely solely on the 80 ms spinner poll.
|
|
184
|
+
The displayed content is identical within ≤80 ms latency (the poll reads the same record the core observer populates), and the spinner already ran at this cadence — no perceptible regression.
|
|
185
|
+
Pinned by the streaming-`onUpdate` test.
|
|
186
|
+
- **Stale doc references.**
|
|
187
|
+
The architecture doc and SKILL.md describe the activity map as current state.
|
|
188
|
+
Mitigation: Step 4 grep-driven sweep; the file tree, prose, and two diagrams are all listed explicitly.
|
|
189
|
+
- **Orphaned sibling exports.**
|
|
190
|
+
Deleting the modules could orphan `SessionLike` or `SubscribableSession`.
|
|
191
|
+
Verified during planning: both remain used (`SessionLike` by `subagent-session.ts`; `SubscribableSession` by `record-observer.ts`, `subagent-session.ts`, `types.ts`).
|
|
192
|
+
Mitigation: `pnpm fallow dead-code` in Step 3.
|
|
193
|
+
- **Commit ordering.**
|
|
194
|
+
Removing the field before the spawners stop passing it would break the build.
|
|
195
|
+
Mitigation: Step 1 (stop passing) strictly precedes Step 2 (remove field).
|
|
196
|
+
|
|
197
|
+
## Open Questions
|
|
198
|
+
|
|
199
|
+
None blocking.
|
|
200
|
+
Whether the widget should self-drive from lifecycle events (so the spawners no longer call `ensureTimer`/`update`/`markFinished`) is deferred to Phase 18 Step 4 ([#423]).
|
|
201
|
+
|
|
202
|
+
[#421]: https://github.com/gotgenes/pi-packages/issues/421
|
|
203
|
+
[#423]: https://github.com/gotgenes/pi-packages/issues/423
|
|
204
|
+
[#424]: https://github.com/gotgenes/pi-packages/issues/424
|