@gotgenes/pi-subagents 6.18.1 → 6.18.3

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 CHANGED
@@ -5,6 +5,32 @@ 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
+ ## [6.18.3](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v6.18.2...pi-subagents-v6.18.3) (2026-05-24)
9
+
10
+
11
+ ### Performance Improvements
12
+
13
+ * reorder append-mode prompt for KV cache reuse ([#180](https://github.com/gotgenes/pi-packages/issues/180)) ([5f688bd](https://github.com/gotgenes/pi-packages/commit/5f688bd1d008e20987d28626c5f5d0df0f66b854))
14
+
15
+
16
+ ### Documentation
17
+
18
+ * plan reorder append-mode prompt for KV cache reuse ([#180](https://github.com/gotgenes/pi-packages/issues/180)) ([bb0ddec](https://github.com/gotgenes/pi-packages/commit/bb0ddec8a7beb37baace5698e4fa4d09e61497d6))
19
+ * **retro:** add planning stage notes for issue [#180](https://github.com/gotgenes/pi-packages/issues/180) ([3413158](https://github.com/gotgenes/pi-packages/commit/341315898baa09652df18731ad318c89861ec62c))
20
+ * **retro:** add retro notes for issue [#166](https://github.com/gotgenes/pi-packages/issues/166) ([fae30ce](https://github.com/gotgenes/pi-packages/commit/fae30cec3dd99bbac490a2764a8340aa12fc171c))
21
+ * **retro:** add TDD stage notes for issue [#180](https://github.com/gotgenes/pi-packages/issues/180) ([1560f2d](https://github.com/gotgenes/pi-packages/commit/1560f2d6f7029cbbe0cc7b1efe1aba2a243e8357))
22
+
23
+ ## [6.18.2](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v6.18.1...pi-subagents-v6.18.2) (2026-05-24)
24
+
25
+
26
+ ### Documentation
27
+
28
+ * plan extract ParentSessionInfo from AgentSpawnConfig ([#166](https://github.com/gotgenes/pi-packages/issues/166)) ([aff7b35](https://github.com/gotgenes/pi-packages/commit/aff7b35c98503fbb3da6a287631a2aa5c4d498fd))
29
+ * **retro:** add planning stage notes for issue [#166](https://github.com/gotgenes/pi-packages/issues/166) ([6138473](https://github.com/gotgenes/pi-packages/commit/613847313d56a9df8b479726d831679391bd0c1a))
30
+ * **retro:** add retro notes for issue [#165](https://github.com/gotgenes/pi-packages/issues/165) ([2a3e70d](https://github.com/gotgenes/pi-packages/commit/2a3e70dc6b903b4c053e7f6ebc09169bc3e34bf6))
31
+ * **retro:** add TDD stage notes for issue [#166](https://github.com/gotgenes/pi-packages/issues/166) ([2696da5](https://github.com/gotgenes/pi-packages/commit/2696da599de72f1a881577a4de8fedc57472a695))
32
+ * update architecture doc — AgentSpawnConfig step 3 complete ([125450b](https://github.com/gotgenes/pi-packages/commit/125450ba9ea5753b4cad07ed4d1675dcdbc7e319))
33
+
8
34
  ## [6.18.1](https://github.com/gotgenes/pi-packages/compare/pi-subagents-v6.18.0...pi-subagents-v6.18.1) (2026-05-24)
9
35
 
10
36
 
@@ -500,20 +500,20 @@ These are fire-and-forget broadcast events — no request IDs, no reply channels
500
500
  These interfaces carry hidden dependencies that obscure true coupling.
501
501
  Bags with 10+ fields are the highest priority for decomposition.
502
502
 
503
- | Interface | Fields | Consumers | Severity |
504
- | --------------------------- | --------- | ------------------------------------------------- | -------- |
505
- | `ResolvedSpawnConfig` | 15 | foreground-runner, background-spawner, agent-tool | Critical |
506
- | `AgentSpawnConfig` | 13 | agent-manager (internal) | Critical |
507
- | `RunOptions` | 12 | agent-runner | High |
508
- | `SessionConfig` | 11 | agent-runner (output of assembler) | High |
509
- | `NotificationDetails` | 10 | notification | Medium |
510
- | `ResourceLoaderOptions` | 10 | agent-runner (SDK bridge) | Medium |
511
- | `RunnerIO` | 9 methods | agent-runner | Medium |
512
- | `CreateSessionOptions` | 9 | agent-runner (SDK bridge) | Medium |
513
- | `AgentToolDeps` | 8 | agent-tool | Low |
514
- | `AgentMenuDeps` | 8 | agent-menu | Low |
515
- | `ConversationViewerOptions` | 8 | conversation-viewer | Low |
516
- | `AgentRecordInit` | 8 | agent-record | Low |
503
+ | Interface | Fields | Consumers | Severity |
504
+ | --------------------------- | ---------------------------------- | ------------------------------------------------- | -------- |
505
+ | `ResolvedSpawnConfig` | 3 nested | foreground-runner, background-spawner, agent-tool | done |
506
+ | `AgentSpawnConfig` | 13 → 13 (ParentSessionInfo nested) | agent-manager (internal) | done |
507
+ | `RunOptions` | 12 | agent-runner | High |
508
+ | `SessionConfig` | 11 | agent-runner (output of assembler) | High |
509
+ | `NotificationDetails` | 10 | notification | Medium |
510
+ | `ResourceLoaderOptions` | 10 | agent-runner (SDK bridge) | Medium |
511
+ | `RunnerIO` | 9 methods | agent-runner | Medium |
512
+ | `CreateSessionOptions` | 9 | agent-runner (SDK bridge) | Medium |
513
+ | `AgentToolDeps` | 8 | agent-tool | Low |
514
+ | `AgentMenuDeps` | 8 | agent-menu | Low |
515
+ | `ConversationViewerOptions` | 8 | conversation-viewer | Low |
516
+ | `AgentRecordInit` | 8 | agent-record | Low |
517
517
 
518
518
  ### Complexity hotspots
519
519
 
@@ -586,20 +586,20 @@ interface SpawnPresentation {
586
586
  `agent-tool` uses all three to build the `AgentSpawnConfig` and the result text.
587
587
  After decomposition, each consumer declares its real dependencies explicitly.
588
588
 
589
- #### AgentSpawnConfig (13 fields extract ParentSessionInfo)
589
+ #### AgentSpawnConfig ParentSessionInfo extracted (done, [#166][166])
590
590
 
591
- Several fields form a natural cluster around parent session identity:
591
+ The `parentSessionFile`, `parentSessionId`, and `toolCallId` fields were grouped into `ParentSessionInfo`:
592
592
 
593
593
  ```typescript
594
- /** Parent session identity — always travel together. */
595
- interface ParentSessionInfo {
594
+ /** Parent session identity — always travel together from the tool boundary. */
595
+ export interface ParentSessionInfo {
596
596
  parentSessionFile?: string;
597
597
  parentSessionId?: string;
598
598
  toolCallId?: string;
599
599
  }
600
600
  ```
601
601
 
602
- Extracting this from `AgentSpawnConfig` reduces it from 13 to 10 fields and introduces a named concept that currently exists only as scattered optional fields.
602
+ `AgentSpawnConfig` now carries `parentSession?: ParentSessionInfo` instead of three flat optional fields.
603
603
 
604
604
  #### RunOptions (12 fields → extract RunContext)
605
605
 
@@ -676,10 +676,10 @@ Split the 15-field bag into `SpawnIdentity`, `SpawnExecution`, and `SpawnPresent
676
676
  Each consumer declares its real dependencies.
677
677
  Enables Step 3 (narrowing AgentSpawnConfig, [#166][166]).
678
678
 
679
- ### Step 3: Extract ParentSessionInfo from AgentSpawnConfig ([#166][166])
679
+ ### Step 3: Extract ParentSessionInfo from AgentSpawnConfig ([#166][166]) — Complete
680
680
 
681
- Extract `parentSessionFile`, `parentSessionId`, `toolCallId` into a `ParentSessionInfo` value object.
682
- Reduces AgentSpawnConfig from 13 to 10 fields.
681
+ Extracted `parentSessionFile`, `parentSessionId`, `toolCallId` into `ParentSessionInfo`.
682
+ `AgentSpawnConfig`, `BackgroundParams`, `ForegroundParams`, and `RunOptions` all carry the nested group.
683
683
 
684
684
  ### Step 4: Narrow RunnerIO ([#167][167])
685
685
 
@@ -0,0 +1,231 @@
1
+ ---
2
+ issue: 166
3
+ issue_title: "refactor(pi-subagents): extract ParentSessionInfo from AgentSpawnConfig (13 fields)"
4
+ ---
5
+
6
+ # Extract ParentSessionInfo from AgentSpawnConfig
7
+
8
+ ## Problem Statement
9
+
10
+ `AgentSpawnConfig` in `agent-manager.ts` has 13 fields.
11
+ Three of those fields — `parentSessionFile`, `parentSessionId`, and `toolCallId` — form a natural cluster around parent session identity.
12
+ They always travel together through `agent-tool.ts` → `foreground-runner.ts` / `background-spawner.ts` → `AgentManager.spawn()`.
13
+ Extracting them into a named value object reduces `AgentSpawnConfig` from 13 to 11 fields (10 + 1 nested) and introduces the `ParentSessionInfo` domain concept.
14
+
15
+ ## Goals
16
+
17
+ - Extract `ParentSessionInfo` interface with `parentSessionFile`, `parentSessionId`, and `toolCallId`.
18
+ - Replace the three flat optional fields on `AgentSpawnConfig` with a single optional `parentSession?: ParentSessionInfo` field.
19
+ - Replace the flat fields on `BackgroundParams`, `ForegroundParams`, and `RunOptions` with the same grouped type.
20
+ - Update all callers (agent-tool, foreground-runner, background-spawner, agent-manager, agent-runner) and their tests.
21
+ - Non-breaking refactor — no public API changes (the `SubagentsService` boundary does not expose these fields).
22
+
23
+ ## Non-Goals
24
+
25
+ - Changing the `NotificationState` or `notification` module — they remain as-is; `toolCallId` is just extracted from the group at the `AgentManager.spawn` boundary.
26
+ - Further decomposition of `AgentSpawnConfig` (e.g., extracting execution or callback clusters) — tracked separately.
27
+ - Modifying `session-dir.ts` or `deriveSubagentSessionDir` — the function signature stays the same; callers just unwrap `parentSession.parentSessionFile` before calling it.
28
+
29
+ ## Background
30
+
31
+ Issue #165 (closed) decomposed `ResolvedSpawnConfig` into `SpawnIdentity`, `SpawnExecution`, and `SpawnPresentation`.
32
+ This issue continues that structural improvement by grouping the parent-session fields that flow from `agent-tool.ts` through to `agent-runner.ts`.
33
+
34
+ The three fields are:
35
+
36
+ - `parentSessionFile` — path to the parent session's JSONL file, used by `deriveSubagentSessionDir` to place child sessions next to the parent.
37
+ - `parentSessionId` — session ID of the parent agent, stored in the child session's `parentSession` header via `sessionManager.newSession()`.
38
+ - `toolCallId` — tool call ID for background notification wiring; when set, `AgentManager.spawn` creates a `NotificationState`.
39
+
40
+ All three originate in `agent-tool.ts`'s `execute` function and are threaded unchanged through intermediate modules.
41
+
42
+ ### Current flow
43
+
44
+ ```text
45
+ agent-tool execute → getSessionInfo() + toolCallId param
46
+ → BackgroundParams { parentSessionFile, parentSessionId, toolCallId }
47
+ → spawnBackground → manager.spawn(opts: AgentSpawnConfig { ...flat fields })
48
+ → AgentManager.spawn → options.toolCallId → NotificationState
49
+ → startAgent → runner.run(RunOptions { parentSessionFile, parentSessionId })
50
+ → deriveSessionDir(parentSessionFile, ...)
51
+ → sessionManager.newSession({ parentSession: parentSessionId })
52
+
53
+ → ForegroundParams { parentSessionFile, parentSessionId }
54
+ → runForeground → manager.spawnAndWait(opts: AgentSpawnConfig { ...flat fields })
55
+ → (same AgentManager path)
56
+ ```
57
+
58
+ ### After extraction
59
+
60
+ ```text
61
+ agent-tool execute → getSessionInfo() + toolCallId param
62
+ → parentSession: ParentSessionInfo { parentSessionFile, parentSessionId, toolCallId }
63
+ → BackgroundParams { parentSession }
64
+ → spawnBackground → manager.spawn(opts: AgentSpawnConfig { parentSession })
65
+ → AgentManager.spawn → parentSession.toolCallId → NotificationState
66
+ → startAgent → runner.run(RunOptions { parentSession })
67
+ → deriveSessionDir(parentSession?.parentSessionFile, ...)
68
+ → sessionManager.newSession({ parentSession: parentSession?.parentSessionId })
69
+
70
+ → ForegroundParams { parentSession }
71
+ → runForeground → manager.spawnAndWait(opts: AgentSpawnConfig { parentSession })
72
+ → (same AgentManager path)
73
+ ```
74
+
75
+ ## Design Overview
76
+
77
+ ### `ParentSessionInfo` interface
78
+
79
+ ```typescript
80
+ export interface ParentSessionInfo {
81
+ /** Path to the parent session's JSONL file (for deriving the subagent session directory). */
82
+ parentSessionFile?: string;
83
+ /** Session ID of the parent agent (stored in the child session's parentSession header). */
84
+ parentSessionId?: string;
85
+ /** Tool call ID for background notification wiring. When set, spawn attaches NotificationState. */
86
+ toolCallId?: string;
87
+ }
88
+ ```
89
+
90
+ All three fields remain optional — they are only available when spawning from an active session (the `SubagentsService` boundary omits them entirely).
91
+
92
+ The interface lives in `lifecycle/agent-manager.ts` alongside `AgentSpawnConfig` since that is the primary consumer.
93
+ If a future refactoring moves `AgentSpawnConfig` to its own file, `ParentSessionInfo` should move with it.
94
+
95
+ ### Consumer call-site sketch
96
+
97
+ ```typescript
98
+ // agent-tool.ts execute():
99
+ const parentSession: ParentSessionInfo = {
100
+ parentSessionFile: sessionInfo.parentSessionFile,
101
+ parentSessionId: sessionInfo.parentSessionId,
102
+ toolCallId,
103
+ };
104
+ // ...
105
+ spawnBackground(manager, widget, agentActivity, { config, snapshot, parentSession });
106
+ ```
107
+
108
+ The grouped object eliminates the three-field spread that was repeated in both `spawnBackground` and `runForeground` call sites.
109
+
110
+ ### `AgentSpawnConfig` change
111
+
112
+ ```typescript
113
+ export interface AgentSpawnConfig {
114
+ // ... existing fields (description, model, maxTurns, etc.)
115
+ /** Parent session identity — grouped fields that travel together from the tool boundary. */
116
+ parentSession?: ParentSessionInfo;
117
+ // Remove: parentSessionFile, parentSessionId, toolCallId
118
+ }
119
+ ```
120
+
121
+ ### `RunOptions` change
122
+
123
+ ```typescript
124
+ export interface RunOptions {
125
+ // ... existing fields
126
+ /** Parent session identity (file path + session ID). */
127
+ parentSession?: ParentSessionInfo;
128
+ // Remove: parentSessionFile, parentSessionId
129
+ }
130
+ ```
131
+
132
+ Note: `RunOptions` does not use `toolCallId` — it was never threaded to the runner.
133
+ The runner only reads `parentSessionFile` and `parentSessionId` from the group.
134
+
135
+ ### `getSessionInfo` return type update
136
+
137
+ The `getSessionInfo` callback in `AgentToolDeps` currently returns `{ parentSessionFile: string; parentSessionId: string }`.
138
+ It should remain unchanged — it does not include `toolCallId` (which comes from the `execute` callback's first argument).
139
+ The `agent-tool.ts` execute function constructs a `ParentSessionInfo` by merging `getSessionInfo()` output with `toolCallId`.
140
+
141
+ ## Module-Level Changes
142
+
143
+ ### New types
144
+
145
+ 1. `src/lifecycle/agent-manager.ts` — add `ParentSessionInfo` interface (exported).
146
+
147
+ ### Modified interfaces
148
+
149
+ 1. `src/lifecycle/agent-manager.ts` — `AgentSpawnConfig`: replace `parentSessionFile?`, `parentSessionId?`, `toolCallId?` with `parentSession?: ParentSessionInfo`.
150
+ 2. `src/lifecycle/agent-runner.ts` — `RunOptions`: replace `parentSessionFile?`, `parentSessionId?` with `parentSession?: ParentSessionInfo`.
151
+ 3. `src/tools/background-spawner.ts` — `BackgroundParams`: replace `parentSessionFile`, `parentSessionId`, `toolCallId` with `parentSession: ParentSessionInfo`.
152
+ 4. `src/tools/foreground-runner.ts` — `ForegroundParams`: replace `parentSessionFile`, `parentSessionId` with `parentSession: ParentSessionInfo`.
153
+
154
+ ### Modified implementations
155
+
156
+ 1. `src/lifecycle/agent-manager.ts` — `AgentManager.spawn()`: read `options.parentSession?.toolCallId` instead of `options.toolCallId`; pass `parentSession` to `RunOptions`.
157
+ 2. `src/lifecycle/agent-runner.ts` — `runAgent()`: read `options.parentSession?.parentSessionFile` and `options.parentSession?.parentSessionId`.
158
+ 3. `src/tools/agent-tool.ts` — `createAgentTool` execute: construct `ParentSessionInfo` from `getSessionInfo()` + `toolCallId`, pass as `parentSession` to both spawners.
159
+ 4. `src/tools/background-spawner.ts` — `spawnBackground()`: read `params.parentSession` and pass fields to `AgentSpawnConfig`.
160
+ 5. `src/tools/foreground-runner.ts` — `runForeground()`: read `params.parentSession` and pass fields to `AgentSpawnConfig`.
161
+
162
+ ### No changes needed
163
+
164
+ - `src/tools/agent-tool.ts` — `AgentToolDeps.getSessionInfo` return type stays the same.
165
+ - `src/session/session-dir.ts` — `deriveSubagentSessionDir` signature unchanged.
166
+ - `src/observation/notification-state.ts` — constructor signature unchanged.
167
+ - `src/service/service-adapter.ts` — does not pass parent session fields.
168
+ - `src/index.ts` — `getSessionInfo` callback unchanged.
169
+
170
+ ## Test Impact Analysis
171
+
172
+ ### New tests enabled
173
+
174
+ No new unit tests are enabled — this is a structural grouping, not new behavior.
175
+
176
+ ### Existing tests that need updates
177
+
178
+ 1. `test/lifecycle/agent-manager.test.ts` — update spawn calls from flat `parentSessionFile`/`parentSessionId`/`toolCallId` to nested `parentSession: { ... }` form; update assertions to read from `parentSession`.
179
+ 2. `test/lifecycle/agent-runner.test.ts` — update `RunOptions` construction from flat to nested `parentSession`.
180
+ 3. `test/tools/agent-tool.test.ts` — update assertion checking `toolCallId` on spawn opts to check `parentSession.toolCallId`.
181
+ 4. `test/tools/background-spawner.test.ts` — update `makeParams` factory from flat fields to `parentSession: { ... }`.
182
+ 5. `test/tools/foreground-runner.test.ts` — update params construction from flat fields to `parentSession: { ... }`.
183
+ 6. `test/helpers/make-deps.ts` — `getSessionInfo` mock stays unchanged (returns flat `{ parentSessionFile, parentSessionId }`).
184
+
185
+ ### Tests that stay as-is
186
+
187
+ - `test/session/session-dir.test.ts` — tests `deriveSubagentSessionDir` directly, no interface change.
188
+ - `test/observation/notification-state.test.ts` — tests `NotificationState` constructor directly.
189
+ - `test/observation/notification.test.ts` — tests notification formatting with `record.notification`, not spawn config.
190
+
191
+ ## TDD Order
192
+
193
+ 1. **Define `ParentSessionInfo` and update `AgentSpawnConfig`** — add interface, replace three flat fields with `parentSession?`.
194
+ Update `AgentManager.spawn` and `startAgent` to read from the nested group.
195
+ Update `agent-manager.test.ts` to use nested form.
196
+ Run `pnpm run check` to verify no downstream type errors remain.
197
+ Commit: `refactor: define ParentSessionInfo and nest in AgentSpawnConfig`
198
+
199
+ 2. **Update `RunOptions` in `agent-runner.ts`** — replace flat `parentSessionFile?`/`parentSessionId?` with `parentSession?`.
200
+ Update `runAgent` to read `options.parentSession?.parentSessionFile` and `options.parentSession?.parentSessionId`.
201
+ Update `agent-runner.test.ts`.
202
+ Commit: `refactor: nest ParentSessionInfo in RunOptions`
203
+
204
+ 3. **Update `BackgroundParams` and `spawnBackground`** — replace three flat fields with `parentSession: ParentSessionInfo`.
205
+ Update `spawnBackground` to pass `parentSession` to spawn opts.
206
+ Update `background-spawner.test.ts`.
207
+ Commit: `refactor: nest ParentSessionInfo in BackgroundParams`
208
+
209
+ 4. **Update `ForegroundParams` and `runForeground`** — replace two flat fields with `parentSession: ParentSessionInfo`.
210
+ Update `runForeground` to pass `parentSession` to spawn opts.
211
+ Update `foreground-runner.test.ts`.
212
+ Commit: `refactor: nest ParentSessionInfo in ForegroundParams`
213
+
214
+ 5. **Update `agent-tool.ts` execute** — construct `ParentSessionInfo` from `getSessionInfo()` + `toolCallId`, pass as `parentSession` to both spawner call sites.
215
+ Update `agent-tool.test.ts`.
216
+ Commit: `refactor: construct ParentSessionInfo in agent-tool execute`
217
+
218
+ 6. **Final verification** — run full test suite (`pnpm vitest run`) and type check (`pnpm run check`).
219
+ No separate commit unless adjustments are needed.
220
+
221
+ ## Risks and Mitigations
222
+
223
+ | Risk | Mitigation |
224
+ | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
225
+ | Deep-merge trap: test factories using `Partial<BackgroundParams>` spread may silently ignore nested overrides | Audit `makeParams` in `background-spawner.test.ts` — convert from flat-field spread to nested `parentSession` construction |
226
+ | `toolCallId` conditionally absent for foreground calls | `ParentSessionInfo.toolCallId` is optional; `ForegroundParams.parentSession` includes it but won't set it — matches current behavior |
227
+ | Type check passes but runtime breaks due to nested access on undefined | `parentSession?` is optional on `AgentSpawnConfig`; all reads use optional chaining (`options.parentSession?.toolCallId`) |
228
+
229
+ ## Open Questions
230
+
231
+ None — the extraction is mechanical and the issue description is unambiguous.
@@ -0,0 +1,100 @@
1
+ ---
2
+ issue: 180
3
+ issue_title: "perf(pi-subagents): reorder append-mode system prompt to enable KV cache reuse"
4
+ ---
5
+
6
+ # Reorder append-mode system prompt for KV cache reuse
7
+
8
+ ## Problem Statement
9
+
10
+ In append mode, `buildAgentPrompt()` places varying, agent-specific content (the `<active_agent>` tag and env block) *before* the large shared inherited system prompt (~8k tokens).
11
+ LLM KV caching works on prefixes — the cache is only reusable when the beginning of the prompt matches.
12
+ Every subagent spawn reprocesses the entire inherited prompt from scratch because the prefix differs per agent.
13
+
14
+ ## Goals
15
+
16
+ - Reorder the append-mode system prompt so shared/stable content comes first and varying content follows.
17
+ - Preserve the `<active_agent>` tag at any position — pi-permission-system's `ACTIVE_AGENT_TAG_REGEX.exec()` searches the full string.
18
+ - Keep replace-mode prompt ordering unchanged (it has no shared inherited content to cache).
19
+ - Update tests and JSDoc to reflect the new ordering.
20
+
21
+ ## Non-Goals
22
+
23
+ - Changing replace-mode prompt assembly (no shared prefix to cache).
24
+ - Modifying pi-permission-system (its regex parsing is already position-independent).
25
+ - Changing the *content* of any prompt section — only reordering.
26
+
27
+ ## Background
28
+
29
+ `buildAgentPrompt()` in `src/session/prompts.ts` assembles the system prompt for subagents.
30
+ In append mode, the current ordering is:
31
+
32
+ ```text
33
+ 1. <active_agent name="${name}"/> ← VARIES per agent
34
+ 2. # Environment ... ← VARIES per runtime
35
+ 3. <inherited_system_prompt> ← SHARED (~8k tokens)
36
+ 4. <sub_agent_context> ← SHARED (static)
37
+ 5. <agent_instructions> ← VARIES per agent
38
+ 6. memory / skills ← VARIES
39
+ ```
40
+
41
+ pi-permission-system's `getActiveAgentNameFromSystemPrompt()` in `src/active-agent.ts` uses `ACTIVE_AGENT_TAG_REGEX.exec(systemPrompt)` — a regex search that finds the tag at any position, confirmed by reading the source.
42
+
43
+ ## Design Overview
44
+
45
+ Move shared/stable sections to the front of the append-mode prompt:
46
+
47
+ ```text
48
+ 1. <inherited_system_prompt> ← SHARED (~8k tokens, NOW CACHEABLE)
49
+ 2. <sub_agent_context> ← SHARED (static)
50
+ 3. <active_agent name="${name}"/> ← VARIES (after cached prefix)
51
+ 4. # Environment ... ← VARIES
52
+ 5. <agent_instructions> ← VARIES per agent
53
+ 6. memory / skills ← VARIES
54
+ ```
55
+
56
+ This is a pure reordering — no content changes.
57
+ The `<active_agent>` tag remains in the system prompt for pi-permission-system to find via regex.
58
+ The env block and agent instructions still provide context to the model; their position relative to the inherited prompt is not semantically significant.
59
+
60
+ ## Module-Level Changes
61
+
62
+ ### `src/session/prompts.ts`
63
+
64
+ 1. Reorder the return statement in the `config.promptMode === "append"` branch to place `identity` (wrapped in `<inherited_system_prompt>`) and `bridge` before `activeAgentTag` and `envBlock`.
65
+ 2. Update the JSDoc comment on `buildAgentPrompt()` — replace "Both modes prepend" language with a description that notes the tag is included (not necessarily prepended) in append mode.
66
+
67
+ ### `test/session/prompts.test.ts`
68
+
69
+ 1. Update "prepends `<active_agent>` tag in append mode" — change from asserting `prompt.startsWith()` to asserting the tag appears *after* the inherited system prompt.
70
+ 2. Update "active_agent tag appears before envBlock in both modes" — the append-mode assertions change: the tag should still appear before the env block, but no longer at index 0.
71
+ The replace-mode assertions remain unchanged (`tagIdx === 0`).
72
+
73
+ ## Test Impact Analysis
74
+
75
+ - Two existing tests assert `<active_agent>` is prepended (index 0) in append mode — these must change to assert the new ordering.
76
+ - All other prompt tests use `toContain()` and are position-independent — they pass without changes.
77
+ - No new test files or test surfaces are needed; the existing test suite covers the reordering adequately once the positional assertions are updated.
78
+
79
+ ## TDD Order
80
+
81
+ 1. **Red: update positional assertions for append mode.**
82
+ Change the two append-mode tests to assert the new ordering: `<inherited_system_prompt>` appears before `<active_agent>`, and the tag appears before the env block but not at index 0.
83
+ Commit: `test: assert cache-friendly prompt ordering in append mode (#180)`
84
+
85
+ 2. **Green: reorder the append-mode return statement.**
86
+ Move `identity` + `<inherited_system_prompt>` wrapper and `bridge` before `activeAgentTag` + `envBlock` in the return expression.
87
+ Update the JSDoc on `buildAgentPrompt()`.
88
+ Commit: `perf: reorder append-mode prompt for KV cache reuse (#180)`
89
+
90
+ ## Risks and Mitigations
91
+
92
+ | Risk | Mitigation |
93
+ | -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
94
+ | pi-permission-system depends on tag position | Confirmed `ACTIVE_AGENT_TAG_REGEX.exec()` searches the full string — position-independent. |
95
+ | Model behavior changes with reordered prompt | The same content is present; only ordering changes. The inherited system prompt as the "base" followed by specialization is arguably more natural. |
96
+ | Replace mode accidentally affected | Replace mode has its own code path and is not touched by this change. |
97
+
98
+ ## Open Questions
99
+
100
+ None — the design is straightforward and confirmed safe by code inspection.
@@ -38,3 +38,41 @@ The decomposition touched 7 files (4 source, 3 test) and kept the test count fla
38
38
  - Step 1 breaking all consumers simultaneously was handled smoothly by completing all steps before pushing, as planned.
39
39
  No transitional alias was needed.
40
40
  - The `background-spawner.test.ts` description-override test was the only unexpected friction point — the flat spread issue wasn't caught by the plan.
41
+
42
+ ## Stage: Final Retrospective (2026-05-24T15:00:14Z)
43
+
44
+ ### Session summary
45
+
46
+ Shipped issue #165 (CI green, released as `pi-subagents-v6.18.1`) and ran the final retrospective.
47
+ The most impactful outcome across all three sessions was the skill description improvements (commit `51f52ef`), which addressed a recurring `instruction-violation` pattern.
48
+
49
+ ### Observations
50
+
51
+ #### What went well
52
+
53
+ - The user's probing question ("This is consistent, though.
54
+ Why?") turned a simple skill-loading skip into a generalizable improvement to three skill descriptions and two prompt instructions.
55
+ This is a good example of the user investing a redirecting question instead of a correction.
56
+ - TDD execution was clean — 4 cycles, no rework, no type errors at the end.
57
+ The plan's risk mitigation ("land steps 1–4 on the same branch") worked as intended.
58
+ - Ship stage had zero friction: push, CI, close, release-please merge, tag — all first-try.
59
+
60
+ #### What caused friction (agent side)
61
+
62
+ - `instruction-violation` — Skipped loading the `colgrep` skill during planning despite explicit instructions.
63
+ Root cause: skill descriptions that read like tool reference manuals get deprioritized because the agent perceives them as redundant with the tool schema already in context.
64
+ Impact: no rework on the plan itself, but triggered a productive detour to improve skill descriptions.
65
+ User-caught.
66
+ - `missing-context` — The plan didn't anticipate that `Partial<ResolvedSpawnConfig>` spread in test factories would silently break after nesting.
67
+ The `testing` skill already warns about spread-related pitfalls, but not this specific variant (flat keys ignored by top-level spread on a nested structure).
68
+ Impact: one test failure during step 4 that required a verbose inline fix (writing out the full `execution` sub-object).
69
+ Self-identified during implementation.
70
+
71
+ #### What caused friction (user side)
72
+
73
+ - None observed.
74
+ The user's intervention on the `colgrep` skill was well-timed and produced a higher-value outcome than skipping it would have.
75
+
76
+ ### Changes made
77
+
78
+ 1. Added a TDD planning rule to `.pi/skills/testing/SKILL.md` warning about `Partial<T>` spread not deep-merging into nested interfaces after a flat-to-nested refactor.
@@ -0,0 +1,66 @@
1
+ ---
2
+ issue: 166
3
+ issue_title: "refactor(pi-subagents): extract ParentSessionInfo from AgentSpawnConfig (13 fields)"
4
+ ---
5
+
6
+ # Retro: #166 — Extract ParentSessionInfo from AgentSpawnConfig
7
+
8
+ ## Stage: Planning (2026-05-24T16:00:00Z)
9
+
10
+ ### Session summary
11
+
12
+ Produced a 6-step TDD plan to extract `ParentSessionInfo` from `AgentSpawnConfig`.
13
+ The refactoring groups three co-traveling fields (`parentSessionFile`, `parentSessionId`, `toolCallId`) into a named value object, reducing `AgentSpawnConfig` from 13 to 11 fields.
14
+
15
+ ### Observations
16
+
17
+ - The `SubagentsService` boundary (`service-adapter.ts`) does not pass any of the three fields, so this is a purely internal refactoring with no public API impact.
18
+ - `getSessionInfo` in `AgentToolDeps` returns only `parentSessionFile` and `parentSessionId`; `toolCallId` comes from the `execute` callback's first argument — the plan keeps this separation and merges them at the `agent-tool.ts` boundary.
19
+ - `RunOptions` in `agent-runner.ts` never carried `toolCallId` (it was consumed in `AgentManager.spawn` before reaching the runner), so the nested `parentSession` on `RunOptions` only holds the two session fields.
20
+ - The deep-merge trap from the testing skill is relevant: `background-spawner.test.ts` has a `makeParams` factory that spreads flat fields — must be converted to nested `parentSession` construction.
21
+ - Issue #165 (decompose `ResolvedSpawnConfig`) is closed, so this plan builds on stable ground.
22
+
23
+ ## Stage: Implementation — TDD (2026-05-24T17:00:00Z)
24
+
25
+ ### Session summary
26
+
27
+ All 5 TDD cycles completed across `agent-manager.ts`, `agent-runner.ts`, `background-spawner.ts`, `foreground-runner.ts`, and `agent-tool.ts`.
28
+ Test count held steady at 805 (no net new tests — refactor only).
29
+ Type check and lint both clean after all steps.
30
+
31
+ ### Observations
32
+
33
+ - The `AgentSpawnConfig` field count went from 15 to 13 (not 13 → 10 as originally estimated) — the architecture doc quoted the issue's stale count; the actual pre-refactor interface had 15 fields (`bypassQueue` and others were already present).
34
+ The architecture doc was updated to reflect "done" with a note about the nested group rather than a specific before/after number.
35
+ - The deep-merge trap (noted in planning) did materialise: `background-spawner.test.ts`'s `makeParams` spread `Partial<BackgroundParams>` with flat fields.
36
+ Fixed by replacing the three flat fields with a single `parentSession` object at the factory level — top-level spread still works correctly since `parentSession` is one field.
37
+ - `RunOptions` in `agent-runner.ts` needed a new import of `ParentSessionInfo` from `agent-manager.ts`; no circular dependency since `agent-runner.ts` already imports from `agent-manager.ts`.
38
+ - `agent-tool.ts` still imports `AgentSpawnConfig` (needed by `AgentToolManager` interface) — the new `ParentSessionInfo` import was added alongside it.
39
+ - All 5 commits are clean `refactor:` messages; architecture doc update is a separate `docs:` commit.
40
+
41
+ ## Stage: Final Retrospective (2026-05-24T18:00:00Z)
42
+
43
+ ### Session summary
44
+
45
+ Planning, TDD implementation (5 steps), shipping, and CI verification all completed in a single session.
46
+ Released as `pi-subagents-v6.18.2`.
47
+ Zero rework — every TDD step went green on first attempt.
48
+
49
+ ### Observations
50
+
51
+ #### What went well
52
+
53
+ - The planning session's identification of the deep-merge trap in `background-spawner.test.ts`'s `makeParams` factory paid off — the TDD implementation handled it without friction because the risk was anticipated.
54
+ - The 5-step inside-out TDD order (manager → runner → background → foreground → agent-tool) was the right sequence.
55
+ Each step only introduced type errors in files that subsequent steps would fix, with no circular breakage.
56
+ - Clean mechanical execution — 805 tests before and after, zero rework commits, lint and type-check clean throughout.
57
+
58
+ #### What caused friction (agent side)
59
+
60
+ - `missing-context` — The plan repeated the issue body's stale "13 fields" count without verifying against the actual `AgentSpawnConfig` interface (which had 15 fields after `bypassQueue` was added in a prior issue).
61
+ The plan also inconsistently claimed the extraction would reduce the count to both "11" and "10" in different places.
62
+ Impact: required corrections in the architecture doc update, but no implementation rework.
63
+
64
+ #### What caused friction (user side)
65
+
66
+ - None observed — the user let the session run autonomously through all stages without intervention.
@@ -0,0 +1,33 @@
1
+ ---
2
+ issue: 180
3
+ issue_title: "perf(pi-subagents): reorder append-mode system prompt to enable KV cache reuse"
4
+ ---
5
+
6
+ # Retro: #180 — Reorder append-mode system prompt for KV cache reuse
7
+
8
+ ## Stage: Planning (2026-05-24T20:00:00Z)
9
+
10
+ ### Session summary
11
+
12
+ Produced a plan to reorder the append-mode system prompt in `buildAgentPrompt()` so the shared inherited content (~8k tokens) comes before the varying `<active_agent>` tag and env block, enabling LLM KV cache prefix reuse across subagent invocations.
13
+
14
+ ### Observations
15
+
16
+ - Confirmed pi-permission-system's `ACTIVE_AGENT_TAG_REGEX.exec()` is position-independent — no changes needed in that package despite the `pkg:pi-permission-system` label on the issue.
17
+ - Only two tests assert positional ordering in append mode (`startsWith` and `tagIdx === 0`); all other prompt tests use `toContain()` and are unaffected.
18
+ - Replace mode is a separate code path and is not touched.
19
+ - The TDD cycle is minimal: one red step (update two positional assertions), one green step (reorder the return statement + update JSDoc).
20
+
21
+ ## Stage: Implementation — TDD (2026-05-24T20:15:00Z)
22
+
23
+ ### Session summary
24
+
25
+ Completed both TDD cycles in `buildAgentPrompt()` in `src/session/prompts.ts`.
26
+ Two positional assertions in `test/session/prompts.test.ts` were updated to expect the new ordering (red), then the append-mode return statement was reordered and the JSDoc updated (green).
27
+ Test count unchanged at 805 across 50 files.
28
+
29
+ ### Observations
30
+
31
+ - The JSDoc bullet for append mode also described the old ordering ("env header + parent system prompt + ...") and was corrected as part of the green step.
32
+ - The `<active_agent>` tag is followed by a `\n\n`, so when it moves after `<sub_agent_context>`, a `\n\n` separator between the bridge and the tag was needed to maintain clean section boundaries.
33
+ - No deviations from the plan; both steps were exactly as described.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gotgenes/pi-subagents",
3
- "version": "6.18.1",
3
+ "version": "6.18.3",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./src/service.ts"
@@ -53,6 +53,15 @@ interface SpawnArgs {
53
53
  options: AgentSpawnConfig;
54
54
  }
55
55
 
56
+ export interface ParentSessionInfo {
57
+ /** Path to the parent session's JSONL file (for deriving the subagent session directory). */
58
+ parentSessionFile?: string;
59
+ /** Session ID of the parent agent (stored in the child session's parentSession header). */
60
+ parentSessionId?: string;
61
+ /** Tool call ID for background notification wiring. When set, spawn attaches NotificationState. */
62
+ toolCallId?: string;
63
+ }
64
+
56
65
  export interface AgentSpawnConfig {
57
66
  description: string;
58
67
  model?: Model<any>;
@@ -75,12 +84,8 @@ export interface AgentSpawnConfig {
75
84
  signal?: AbortSignal;
76
85
  /** Called when the agent session is created — receives the session and the agent's record. */
77
86
  onSessionCreated?: (session: AgentSession, record: AgentRecord) => void;
78
- /** Path to the parent session's JSONL file (for deriving the subagent session directory). */
79
- parentSessionFile?: string;
80
- /** Session ID of the parent agent (stored in the child session's parentSession header). */
81
- parentSessionId?: string;
82
- /** Tool call ID for background notification wiring. When set, spawn attaches NotificationState. */
83
- toolCallId?: string;
87
+ /** Parent session identity grouped fields that travel together from the tool boundary. */
88
+ parentSession?: ParentSessionInfo;
84
89
  }
85
90
 
86
91
  export class AgentManager {
@@ -158,8 +163,8 @@ export class AgentManager {
158
163
  });
159
164
  this.agents.set(id, record);
160
165
 
161
- if (options.toolCallId) {
162
- record.notification = new NotificationState(options.toolCallId);
166
+ if (options.parentSession?.toolCallId) {
167
+ record.notification = new NotificationState(options.parentSession.toolCallId);
163
168
  }
164
169
 
165
170
  if (options.isBackground) {
@@ -228,8 +233,7 @@ export class AgentManager {
228
233
  isolated: options.isolated,
229
234
  thinkingLevel: options.thinkingLevel,
230
235
  cwd: worktreeCwd,
231
- parentSessionFile: options.parentSessionFile,
232
- parentSessionId: options.parentSessionId,
236
+ parentSession: options.parentSession,
233
237
  signal: record.abortController!.signal,
234
238
  registry: this.registry,
235
239
  onSessionCreated: (session) => {
@@ -9,6 +9,7 @@ import {
9
9
  type SettingsManager,
10
10
  } from "@earendil-works/pi-coding-agent";
11
11
  import type { AgentConfigLookup } from "#src/config/agent-types";
12
+ import type { ParentSessionInfo } from "#src/lifecycle/agent-manager";
12
13
  import type { ParentSnapshot } from "#src/lifecycle/parent-snapshot";
13
14
  import { extractText } from "#src/session/context";
14
15
  import type { EnvInfo } from "#src/session/env";
@@ -146,10 +147,8 @@ export interface RunOptions {
146
147
  thinkingLevel?: ThinkingLevel;
147
148
  /** Override working directory (e.g. for worktree isolation). */
148
149
  cwd?: string;
149
- /** Path to the parent session's JSONL file (for deriving the subagent session directory). */
150
- parentSessionFile?: string;
151
- /** Session ID of the parent agent (stored in the child session's parentSession header). */
152
- parentSessionId?: string;
150
+ /** Parent session identity (file path + session ID). */
151
+ parentSession?: ParentSessionInfo;
153
152
  /** Called once after session creation — session delivery mechanism. */
154
153
  onSessionCreated?: (session: AgentSession) => void;
155
154
  /**
@@ -308,9 +307,9 @@ export async function runAgent(
308
307
  // Create a persisted SessionManager so transcripts are written in Pi's
309
308
  // official JSONL format. Falls back to a temp directory when the parent
310
309
  // session is not persisted (e.g. headless/API mode).
311
- const sessionDir = io.deriveSessionDir(options.parentSessionFile, cfg.effectiveCwd);
310
+ const sessionDir = io.deriveSessionDir(options.parentSession?.parentSessionFile, cfg.effectiveCwd);
312
311
  const sessionManager = io.createSessionManager(cfg.effectiveCwd, sessionDir);
313
- sessionManager.newSession({ parentSession: options.parentSessionId });
312
+ sessionManager.newSession({ parentSession: options.parentSession?.parentSessionId });
314
313
 
315
314
  const { session } = await io.createSession({
316
315
  cwd: cfg.effectiveCwd,
@@ -17,12 +17,14 @@ export interface PromptExtras {
17
17
  * Build the system prompt for an agent from its config.
18
18
  *
19
19
  * - "replace" mode: env header + config.systemPrompt (full control, no parent identity)
20
- * - "append" mode: env header + parent system prompt + sub-agent context + config.systemPrompt
20
+ * - "append" mode: parent system prompt + sub-agent context + env header + config.systemPrompt
21
21
  * - "append" with empty systemPrompt: pure parent clone
22
22
  *
23
- * Both modes prepend an `<active_agent name="${config.name}"/>` tag so downstream
23
+ * Both modes include an `<active_agent name="${config.name}"/>` tag so downstream
24
24
  * extensions (e.g. `@gotgenes/pi-permission-system`) can resolve per-agent policy
25
25
  * inside the child session by parsing the system prompt.
26
+ * In replace mode the tag is prepended; in append mode it follows the shared
27
+ * inherited content so the stable prefix is cacheable by the LLM's KV cache.
26
28
  *
27
29
  * @param parentSystemPrompt The parent agent's effective system prompt (for append mode).
28
30
  * @param extras Optional extra sections to inject (memory, preloaded skills).
@@ -76,13 +78,17 @@ You are operating as a sub-agent invoked to handle a specific task.
76
78
  ? `\n\n<agent_instructions>\n${config.systemPrompt}\n</agent_instructions>`
77
79
  : "";
78
80
 
81
+ // Place shared/stable content first so the LLM's KV cache can reuse the
82
+ // inherited prefix across all subagent invocations. The <active_agent> tag
83
+ // and env block vary per call and are placed after the cacheable prefix.
79
84
  return (
80
- activeAgentTag +
81
- envBlock +
82
- "\n\n<inherited_system_prompt>\n" +
85
+ "<inherited_system_prompt>\n" +
83
86
  identity +
84
87
  "\n</inherited_system_prompt>\n\n" +
85
88
  bridge +
89
+ "\n\n" +
90
+ activeAgentTag +
91
+ envBlock +
86
92
  customSection +
87
93
  extrasSuffix
88
94
  );
@@ -3,7 +3,7 @@ import type { AgentToolResult } from "@earendil-works/pi-coding-agent";
3
3
  import { Text } from "@earendil-works/pi-tui";
4
4
  import { Type } from "@sinclair/typebox";
5
5
  import { AgentTypeRegistry } from "#src/config/agent-types";
6
- import type { AgentSpawnConfig } from "#src/lifecycle/agent-manager";
6
+ import type { AgentSpawnConfig, ParentSessionInfo } from "#src/lifecycle/agent-manager";
7
7
  import type { ParentSnapshot } from "#src/lifecycle/parent-snapshot";
8
8
  import { spawnBackground } from "#src/tools/background-spawner";
9
9
  import { runForeground } from "#src/tools/foreground-runner";
@@ -303,6 +303,7 @@ Guidelines:
303
303
  // ---- Boundary extraction (after config so inheritContext is resolved) ----
304
304
  const snapshot = buildSnapshot(config.execution.inheritContext);
305
305
  const { parentSessionFile, parentSessionId } = getSessionInfo();
306
+ const parentSession: ParentSessionInfo = { parentSessionFile, parentSessionId, toolCallId };
306
307
 
307
308
  // ---- Resume existing agent ----
308
309
  if (params.resume) {
@@ -337,7 +338,7 @@ Guidelines:
337
338
  manager,
338
339
  widget,
339
340
  agentActivity,
340
- { config, snapshot, parentSessionFile, parentSessionId, toolCallId },
341
+ { config, snapshot, parentSession },
341
342
  );
342
343
  }
343
344
 
@@ -346,7 +347,7 @@ Guidelines:
346
347
  manager,
347
348
  widget,
348
349
  agentActivity,
349
- { config, snapshot, parentSessionFile, parentSessionId },
350
+ { config, snapshot, parentSession },
350
351
  signal,
351
352
  onUpdate,
352
353
  );
@@ -1,4 +1,4 @@
1
- import type { AgentSpawnConfig } from "#src/lifecycle/agent-manager";
1
+ import type { AgentSpawnConfig, ParentSessionInfo } from "#src/lifecycle/agent-manager";
2
2
  import type { ParentSnapshot } from "#src/lifecycle/parent-snapshot";
3
3
  import type { AgentActivityAccess } from "#src/tools/agent-tool";
4
4
  import { textResult } from "#src/tools/helpers";
@@ -24,9 +24,7 @@ export interface BackgroundWidgetDeps {
24
24
  export interface BackgroundParams {
25
25
  config: ResolvedSpawnConfig;
26
26
  snapshot: ParentSnapshot;
27
- parentSessionFile: string;
28
- parentSessionId: string;
29
- toolCallId: string;
27
+ parentSession: ParentSessionInfo;
30
28
  }
31
29
 
32
30
  /**
@@ -46,8 +44,7 @@ export function spawnBackground(
46
44
  let id: string;
47
45
  try {
48
46
  id = manager.spawn(params.snapshot, identity.subagentType, execution.prompt, {
49
- parentSessionFile: params.parentSessionFile,
50
- parentSessionId: params.parentSessionId,
47
+ parentSession: params.parentSession,
51
48
  description: execution.description,
52
49
  model: execution.model,
53
50
  maxTurns: execution.effectiveMaxTurns,
@@ -57,7 +54,6 @@ export function spawnBackground(
57
54
  isBackground: true,
58
55
  isolation: execution.isolation,
59
56
  invocation: execution.agentInvocation,
60
- toolCallId: params.toolCallId,
61
57
  onSessionCreated: (session) => {
62
58
  bgState.setSession(session);
63
59
  subscribeUIObserver(session, bgState);
@@ -1,5 +1,5 @@
1
1
  import type { AgentToolResult } from "@earendil-works/pi-coding-agent";
2
- import type { AgentSpawnConfig } from "#src/lifecycle/agent-manager";
2
+ import type { AgentSpawnConfig, ParentSessionInfo } from "#src/lifecycle/agent-manager";
3
3
  import type { ParentSnapshot } from "#src/lifecycle/parent-snapshot";
4
4
  import type { AgentActivityAccess } from "#src/tools/agent-tool";
5
5
  import {
@@ -39,8 +39,7 @@ export interface ForegroundWidgetDeps {
39
39
  export interface ForegroundParams {
40
40
  config: ResolvedSpawnConfig;
41
41
  snapshot: ParentSnapshot;
42
- parentSessionFile: string;
43
- parentSessionId: string;
42
+ parentSession: ParentSessionInfo;
44
43
  }
45
44
 
46
45
  /**
@@ -109,8 +108,7 @@ export async function runForeground(
109
108
  isolation: execution.isolation,
110
109
  invocation: execution.agentInvocation,
111
110
  signal,
112
- parentSessionFile: params.parentSessionFile,
113
- parentSessionId: params.parentSessionId,
111
+ parentSession: params.parentSession,
114
112
  onSessionCreated: (session, record) => {
115
113
  fgState.setSession(session);
116
114
  recordRef = record;