@gotgenes/pi-subagents 5.7.0 → 5.8.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 +13 -0
- package/docs/retro/0087-evolve-subagent-runtime-methods.md +42 -0
- package/package.json +1 -1
- package/src/handlers/index.ts +6 -0
- package/src/handlers/lifecycle.ts +62 -0
- package/src/handlers/tool-start.ts +32 -0
- package/src/index.ts +13 -21
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,19 @@ 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
|
+
## [5.8.0](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v5.7.0...pi-subagents-v5.8.0) (2026-05-20)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* add SessionLifecycleHandler ([d8d95fa](https://github.com/gotgenes/pi-packages/commit/d8d95fa92561e0068444c3c925f21b50825a741c))
|
|
14
|
+
* add ToolStartHandler ([c293e41](https://github.com/gotgenes/pi-packages/commit/c293e41e25d9742f807f85d0efe0a0e5605b29a6))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Documentation
|
|
18
|
+
|
|
19
|
+
* **retro:** add retro notes for issue [#87](https://github.com/gotgenes/pi-packages/issues/87) ([1701fe4](https://github.com/gotgenes/pi-packages/commit/1701fe41d582d7180b2622c2e03db954e8d2c2af))
|
|
20
|
+
|
|
8
21
|
## [5.7.0](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v5.6.0...pi-subagents-v5.7.0) (2026-05-20)
|
|
9
22
|
|
|
10
23
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
issue: 87
|
|
3
|
+
issue_title: "refactor: evolve SubagentRuntime from data bag to object with methods"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Retro: #87 — evolve SubagentRuntime from data bag to object with methods
|
|
7
|
+
|
|
8
|
+
## Final Retrospective (2026-05-20T18:00:00Z)
|
|
9
|
+
|
|
10
|
+
### Session summary
|
|
11
|
+
|
|
12
|
+
Planned, implemented, and shipped #87 — converting `SubagentRuntime` from a plain interface + factory into a class with session-context methods (`setSessionContext`, `clearSessionContext`) and widget delegation methods (`setUICtx`, `onTurnStart`, `markFinished`, `updateWidget`, `ensureTimer`).
|
|
13
|
+
All 10 call sites in `index.ts` were migrated, eliminating raw `currentCtx` field writes and `runtime.widget!` reach-throughs.
|
|
14
|
+
Released as `pi-subagents-v5.7.0`.
|
|
15
|
+
|
|
16
|
+
### Observations
|
|
17
|
+
|
|
18
|
+
#### What went well
|
|
19
|
+
|
|
20
|
+
- The 3-step TDD cycle executed cleanly with zero rework or deviations from the plan.
|
|
21
|
+
Test count went from 5 → 16 in `runtime.test.ts`; all 512 package tests stayed green throughout.
|
|
22
|
+
- The user identified a missing architecture update and a pre-existing hallucination (`@earendil-works/pi-subagents` → `@gotgenes/pi-subagents`) after the plan commit.
|
|
23
|
+
The fix was a single well-scoped commit (`ddee1a0`) that corrected 10 scope references, updated the dependency graph to include #87 as a precursor to #70, and fixed list numbering per phase heading.
|
|
24
|
+
- The plan's "Call sites to migrate" tables with exact line numbers and before/after code made step 3 (the refactoring commit) purely mechanical — no design decisions at implementation time.
|
|
25
|
+
|
|
26
|
+
#### What caused friction (agent side)
|
|
27
|
+
|
|
28
|
+
- `missing-context` — In TDD step 2, the new `describe` block used `vi.fn()` but the test file's import was `{ describe, expect, it }` without `vi`.
|
|
29
|
+
The first red run surfaced this immediately (`ReferenceError: vi is not defined`) and it was fixed before the green step.
|
|
30
|
+
Impact: one extra test run, no rework commits.
|
|
31
|
+
- `scope-drift` — The `/plan-issue` prompt does not instruct updating `architecture.md`, but the user noticed #87 was missing from the roadmap's dependency graph.
|
|
32
|
+
The agent hadn't checked `architecture.md` during planning even though #87 is explicitly listed as a precursor to #70 in the #70 plan.
|
|
33
|
+
Impact: user-caught; required a follow-up edit pass after the plan commit.
|
|
34
|
+
|
|
35
|
+
#### What caused friction (user side)
|
|
36
|
+
|
|
37
|
+
No friction observed.
|
|
38
|
+
The user's correction about `architecture.md` was well-targeted and caught a real gap.
|
|
39
|
+
|
|
40
|
+
### Changes made
|
|
41
|
+
|
|
42
|
+
1. Retro file created at `packages/pi-subagents/docs/retro/0087-evolve-subagent-runtime-methods.md`.
|
package/package.json
CHANGED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session lifecycle event handlers: session_start, session_before_switch, session_shutdown.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from index.ts so each handler can be tested in isolation
|
|
5
|
+
* with mocked narrow interfaces.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/** Narrow manager interface — only the methods lifecycle handlers call. */
|
|
9
|
+
export interface LifecycleManager {
|
|
10
|
+
clearCompleted(): void;
|
|
11
|
+
abortAll(): void;
|
|
12
|
+
dispose(): void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Narrow runtime interface — only the methods lifecycle handlers call. */
|
|
16
|
+
export interface LifecycleRuntime {
|
|
17
|
+
setSessionContext(pi: unknown, ctx: unknown): void;
|
|
18
|
+
clearSessionContext(): void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Handles session lifecycle events.
|
|
23
|
+
*
|
|
24
|
+
* Constructor deps:
|
|
25
|
+
* - `pi` — the ExtensionAPI instance, stored in runtime on session_start
|
|
26
|
+
* - `runtime` — owns session context state
|
|
27
|
+
* - `manager` — manages agent lifecycle (clear, abort, dispose)
|
|
28
|
+
* - `disposeNotifications` — tears down the notification system on shutdown
|
|
29
|
+
* - `unpublishService` — unpublishes the SubagentsService symbol on shutdown
|
|
30
|
+
*/
|
|
31
|
+
export class SessionLifecycleHandler {
|
|
32
|
+
constructor(
|
|
33
|
+
private readonly pi: unknown,
|
|
34
|
+
private readonly runtime: LifecycleRuntime,
|
|
35
|
+
private readonly manager: LifecycleManager,
|
|
36
|
+
private readonly disposeNotifications: () => void,
|
|
37
|
+
private readonly unpublishService: () => void,
|
|
38
|
+
) {}
|
|
39
|
+
|
|
40
|
+
handleSessionStart(_event: unknown, ctx: unknown): void {
|
|
41
|
+
this.runtime.setSessionContext(this.pi, ctx);
|
|
42
|
+
this.manager.clearCompleted();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
handleSessionBeforeSwitch(): void {
|
|
46
|
+
this.manager.clearCompleted();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Cleanup order matters:
|
|
50
|
+
// 1. Unpublish service — prevent new cross-extension calls
|
|
51
|
+
// 2. Clear session context — no more session state
|
|
52
|
+
// 3. Abort all agents — stop running work
|
|
53
|
+
// 4. Dispose notifications — cancel pending nudges/timers
|
|
54
|
+
// 5. Dispose manager — final cleanup
|
|
55
|
+
async handleSessionShutdown(): Promise<void> {
|
|
56
|
+
this.unpublishService();
|
|
57
|
+
this.runtime.clearSessionContext();
|
|
58
|
+
this.manager.abortAll();
|
|
59
|
+
this.disposeNotifications();
|
|
60
|
+
this.manager.dispose();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tool_execution_start event handler.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from index.ts so the handler can be tested in isolation
|
|
5
|
+
* with a mocked narrow runtime interface.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/** Narrow runtime interface — only the widget-delegation methods the handler calls. */
|
|
9
|
+
export interface ToolStartRuntime {
|
|
10
|
+
setUICtx(ctx: unknown): void;
|
|
11
|
+
onTurnStart(): void;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Minimal context shape for tool_execution_start — only the field the handler reads. */
|
|
15
|
+
interface ToolStartCtx {
|
|
16
|
+
ui: unknown;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Handles tool_execution_start events.
|
|
21
|
+
*
|
|
22
|
+
* Grabs UI context from the first tool execution of each turn
|
|
23
|
+
* and signals the widget to clear lingering state.
|
|
24
|
+
*/
|
|
25
|
+
export class ToolStartHandler {
|
|
26
|
+
constructor(private readonly runtime: ToolStartRuntime) {}
|
|
27
|
+
|
|
28
|
+
handleToolExecutionStart(_event: unknown, ctx: ToolStartCtx): void {
|
|
29
|
+
this.runtime.setUICtx(ctx.ui);
|
|
30
|
+
this.runtime.onTurnStart();
|
|
31
|
+
}
|
|
32
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -16,6 +16,7 @@ import { AgentManager } from "./agent-manager.js";
|
|
|
16
16
|
import { getAgentConversation, normalizeMaxTurns, resumeAgent, runAgent, steerAgent } from "./agent-runner.js";
|
|
17
17
|
import { getAvailableTypes, getDefaultAgentNames, getUserAgentNames, registerAgents, resolveAgentConfig, } from "./agent-types.js";
|
|
18
18
|
import { loadCustomAgents } from "./custom-agents.js";
|
|
19
|
+
import { SessionLifecycleHandler, ToolStartHandler } from "./handlers/index.js";
|
|
19
20
|
import { type ModelRegistry, resolveModel } from "./model-resolver.js";
|
|
20
21
|
import { buildEventData, createNotificationSystem } from "./notification.js";
|
|
21
22
|
import { createNotificationRenderer } from "./renderer.js";
|
|
@@ -122,33 +123,24 @@ export default function (pi: ExtensionAPI) {
|
|
|
122
123
|
});
|
|
123
124
|
publishSubagentsService(service);
|
|
124
125
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
});
|
|
126
|
+
const lifecycle = new SessionLifecycleHandler(
|
|
127
|
+
pi,
|
|
128
|
+
runtime,
|
|
129
|
+
manager,
|
|
130
|
+
() => notifications.dispose(),
|
|
131
|
+
unpublishSubagentsService,
|
|
132
|
+
);
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
pi.on("session_shutdown",
|
|
137
|
-
unpublishSubagentsService();
|
|
138
|
-
runtime.clearSessionContext();
|
|
139
|
-
manager.abortAll();
|
|
140
|
-
notifications.dispose();
|
|
141
|
-
manager.dispose();
|
|
142
|
-
});
|
|
134
|
+
pi.on("session_start", (event, ctx) => lifecycle.handleSessionStart(event, ctx));
|
|
135
|
+
pi.on("session_before_switch", () => lifecycle.handleSessionBeforeSwitch());
|
|
136
|
+
pi.on("session_shutdown", () => lifecycle.handleSessionShutdown());
|
|
143
137
|
|
|
144
138
|
// Live widget: show running agents above editor
|
|
145
139
|
runtime.widget = new AgentWidget(manager, runtime.agentActivity);
|
|
146
140
|
|
|
147
141
|
// Grab UI context from first tool execution + clear lingering widget on new turn
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
runtime.onTurnStart();
|
|
151
|
-
});
|
|
142
|
+
const toolStart = new ToolStartHandler(runtime);
|
|
143
|
+
pi.on("tool_execution_start", (event, ctx) => toolStart.handleToolExecutionStart(event, ctx));
|
|
152
144
|
|
|
153
145
|
/** Build the full type list text dynamically from the unified registry. */
|
|
154
146
|
const buildTypeListText = () => {
|