@esso0428/pi-subagents 0.17.1 → 0.17.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 +19 -0
- package/README.md +5 -4
- package/dist/agent-history.d.ts +6 -0
- package/dist/agent-history.d.ts.map +1 -1
- package/dist/agent-history.js +38 -0
- package/dist/agent-history.js.map +1 -1
- package/dist/agent-manager.d.ts +23 -6
- package/dist/agent-manager.d.ts.map +1 -1
- package/dist/agent-manager.js +165 -27
- package/dist/agent-manager.js.map +1 -1
- package/dist/agent-recovery.d.ts +37 -0
- package/dist/agent-recovery.d.ts.map +1 -0
- package/dist/agent-recovery.js +171 -0
- package/dist/agent-recovery.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +88 -25
- package/dist/index.js.map +1 -1
- package/dist/ui/agent-widget.d.ts +4 -0
- package/dist/ui/agent-widget.d.ts.map +1 -1
- package/dist/ui/agent-widget.js +100 -23
- package/dist/ui/agent-widget.js.map +1 -1
- package/dist/ui/conversation-timeline.d.ts.map +1 -1
- package/dist/ui/conversation-timeline.js +1 -1
- package/dist/ui/conversation-timeline.js.map +1 -1
- package/dist/ui/conversation-viewer.d.ts +6 -0
- package/dist/ui/conversation-viewer.d.ts.map +1 -1
- package/dist/ui/conversation-viewer.js +79 -7
- package/dist/ui/conversation-viewer.js.map +1 -1
- package/package.json +1 -1
- package/src/agent-history.ts +38 -0
- package/src/agent-manager.ts +170 -28
- package/src/agent-recovery.ts +185 -0
- package/src/index.ts +103 -23
- package/src/ui/agent-widget.ts +102 -23
- package/src/ui/conversation-timeline.ts +4 -1
- package/src/ui/conversation-viewer.ts +97 -7
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.17.3] - 2026-09-18
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **The Agents panel now uses a Pi-style right-hand scrollbar for clipped rosters**, reserving a stable track/thumb column and placing `↑ N more` directly below the heading when the viewport is scrolled, while retaining a downward hidden-row affordance at the bottom.
|
|
14
|
+
- **Read-only full tool previews now use the same right-hand track/thumb scrollbar and top/bottom hidden-line affordances**, without adding any transcript mutation or tool execution path.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- **Conversation viewer follow-ups use Pi's muted USER styling and local draft history**, with `Alt+Up`, `a-up`, and `alt+up` aliases recalling submitted steering drafts; the existing `e` composer remains read-only in history mode.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
- **Conversation Markdown bodies now apply the native user-message color while preserving native tool and code token styling**, so follow-up/user content no longer visually merges with assistant output.
|
|
21
|
+
|
|
22
|
+
## [0.17.2] - 2026-09-15
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
- **Agents navigator selection now survives returning to the text input**, restoring the selected agent and bounded viewport on re-entry; if a record disappears, the nearest valid roster position is used.
|
|
26
|
+
- **Running agents and Agent history menus retain their independent selected rows**, and closing a conversation viewer returns to the originating submenu instead of the top-level Agents menu.
|
|
27
|
+
- **Durable transcript results are reloaded on demand after in-memory cleanup**, and full results are no longer duplicated into the parent session branch when a durable transcript exists, reducing long-session heap growth.
|
|
28
|
+
|
|
10
29
|
## [0.17.1] - 2026-09-15
|
|
11
30
|
|
|
12
31
|
### Fixed
|
package/README.md
CHANGED
|
@@ -14,11 +14,12 @@ https://github.com/user-attachments/assets/8685261b-9338-4fea-8dfe-1c590d5df543
|
|
|
14
14
|
|
|
15
15
|
- **Claude Code look & feel** — same tool names, calling conventions, and UI patterns (`Agent`, `get_subagent_result`, `steer_subagent`) — feels native
|
|
16
16
|
- **Parallel background agents** — spawn multiple agents that run concurrently with automatic queuing (configurable concurrency limit, default 4) and smart group join (consolidated notifications)
|
|
17
|
-
- **Agents panel UI** — persistent above-editor widget with animated spinners, live tool activity, token counts, colored status icons, and one focus-gated navigator. It shows every agent by default; press `↓` at an empty prompt to activate the panel, `↑`/`↓` to select, `Enter` to open a live or read-only history viewer, and `Esc` to return. Configure via `/agents → Settings → Widget`: `all`, `background`, or `off`
|
|
18
|
-
- **Conversation viewer** — select any agent in `/agents` to open a live-scrolling overlay of its full conversation (auto-follows new content, scroll up to pause). Steer a running agent inline by pressing `
|
|
17
|
+
- **Agents panel UI** — persistent above-editor widget with animated spinners, live tool activity, token counts, colored status icons, and one focus-gated navigator. It shows every agent by default; press `↓` at an empty prompt to activate the panel, `↑`/`↓` to select, `Enter` to open a live or read-only history viewer, and `Esc` to return. Long rosters reserve a right-hand track/thumb scrollbar and show `↑ N more` or `↓ N more` at the clipped edge. Configure via `/agents → Settings → Widget`: `all`, `background`, or `off`
|
|
18
|
+
- **Conversation viewer** — select any agent in `/agents` to open a live-scrolling overlay of its full conversation (auto-follows new content, scroll up to pause). Steer a running agent inline by pressing `e` to open a Pi-native composer, typing, then `Enter` to send (`Esc` or an empty submit returns); the follow-up appears as a muted/gray USER message and redirects the agent after its current tool. `Alt+Up` (`a-up`/`alt+up`) recalls submitted follow-up drafts. Read-only tool previews use the same right-hand track/thumb scrollbar with top/bottom hidden-line affordances. Stop a still-running agent by pressing `x` (then `x` again to confirm) — both work for background agents too
|
|
19
19
|
- **Custom agent types** — define agents in `.pi/agents/<name>.md` or `.agents/agents/<name>.md` (project) or globally, with YAML frontmatter: custom system prompts, model selection, thinking levels, tool restrictions
|
|
20
20
|
- **Mid-run steering** — inject messages into running agents to redirect their work without restarting
|
|
21
21
|
- **Session resume** — pick up where an agent left off, preserving full conversation context
|
|
22
|
+
- **Durable interruption recovery** — catchable shutdowns preserve running/queued metadata and partial transcripts so interrupted agents remain indexed after reload; abrupt `SIGKILL` termination cannot be checkpointed
|
|
22
23
|
- **Graceful turn limits** — agents get a "wrap up" warning before hard abort, producing clean partial results instead of cut-off output
|
|
23
24
|
- **Case-insensitive agent types** — `"explore"`, `"Explore"`, `"EXPLORE"` all work. Unknown types fall back to general-purpose with a note
|
|
24
25
|
- **Fuzzy model selection** — specify models by name (`"haiku"`, `"sonnet"`) instead of full IDs, with automatic filtering to only available/configured models
|
|
@@ -123,7 +124,7 @@ While agents are running or have openable history, the single Agents panel rende
|
|
|
123
124
|
└─ +1 more (↓ 1 more; 1 finished)
|
|
124
125
|
```
|
|
125
126
|
|
|
126
|
-
At an **empty prompt**, press `↓` to activate the panel. The selected row is marked `●`; `↑`/`↓` move through the full bounded roster, `Enter` opens a running agent live or a terminal agent's read-only history. A queued agent remains selectable,
|
|
127
|
+
At an **empty prompt**, press `↓` to activate the panel. The selected row is marked `●`; `↑`/`↓` move through the full bounded roster, `Enter` opens a running agent live or a terminal agent's read-only history. A queued or interrupted agent remains selectable, and an interrupted agent's partial transcript can be opened read-only after reload. The widget remembers the selected agent and bounded viewport when you return from the prompt or a viewer; if that record disappears, it falls back to the nearest valid row. `Esc` returns to the prompt. `↑` while the first row is selected also returns to the prompt. Pressing `↑` at an inactive prompt, typing in a non-empty prompt, or using `j`/`k`/`←` behaves normally; the panel only captures the focus-gated arrow sequence described above. Disable it entirely via `/agents → Settings → Widget → off`.
|
|
127
128
|
|
|
128
129
|
Individual agent results render Claude Code-style in the conversation:
|
|
129
130
|
|
|
@@ -136,7 +137,7 @@ Individual agent results render Claude Code-style in the conversation:
|
|
|
136
137
|
| **Error** | `✗ ↻3 · 3 tool uses · 12.4k token (8%)` / `⎿ Error: timeout` |
|
|
137
138
|
| **Aborted** | `✗ ↻55≤50 · 55 tool uses · 102.3k token (95% · ⇊3)` / `⎿ Aborted (max turns exceeded)` |
|
|
138
139
|
|
|
139
|
-
Completed results can be expanded (ctrl+o in pi) to show the full agent output inline.
|
|
140
|
+
Completed results can be expanded (ctrl+o in pi) to show the full agent output inline. The viewer's tool preview is read-only; its scrollbar and `j`/`k`/wheel/page/top/bottom controls never modify the agent transcript.
|
|
140
141
|
|
|
141
142
|
By default, foreground and background agents each stream their full conversation to a per-subagent transcript — a JSON-lines file at `<os-tmpdir>/pi-subagents-<uid>/<cwd>/<session>/tasks/<agent-id>.output` (owner-only `0700`, cleared on reboot). Set `output_transcript: false` on a custom agent to write no transcript path or file for it, or set `outputTranscript: false` in `subagents.json` to make transcripts opt-in for the whole project (frontmatter overrides the project default). This governs **only** the transcript: it is independent of `persist_session` (the pi session on disk), and it does not affect `isolation: worktree` (which commits the agent's work to a git branch) or `memory:` (durable files) — set those accordingly if the goal is to keep a run off disk entirely. Background agent completion notifications render as styled boxes:
|
|
142
143
|
|
package/dist/agent-history.d.ts
CHANGED
|
@@ -22,4 +22,10 @@ export declare function hasAgentHistory(cwd: string, locator: string | undefined
|
|
|
22
22
|
* damaged entry cannot hide the rest of a history.
|
|
23
23
|
*/
|
|
24
24
|
export declare function readAgentHistory(cwd: string, locator: string): AgentSession["messages"] | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* Read the last assistant text from a durable transcript. Runtime records may
|
|
27
|
+
* release their in-memory result after the retention TTL; the transcript then
|
|
28
|
+
* becomes the source of truth for get_subagent_result.
|
|
29
|
+
*/
|
|
30
|
+
export declare function readAgentHistoryResult(cwd: string, locator: string): string | undefined;
|
|
25
31
|
//# sourceMappingURL=agent-history.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-history.d.ts","sourceRoot":"","sources":["../src/agent-history.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAI/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAMpE;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAe5D;AAED,uDAAuD;AACvD,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAM3E;AAED,4EAA4E;AAC5E,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAE5E;AAED,+EAA+E;AAC/E,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAWxF;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAIjF;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,YAAY,CAAC,UAAU,CAAC,GAAG,SAAS,CA2BnG"}
|
|
1
|
+
{"version":3,"file":"agent-history.d.ts","sourceRoot":"","sources":["../src/agent-history.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAI/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAMpE;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAe5D;AAED,uDAAuD;AACvD,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAM3E;AAED,4EAA4E;AAC5E,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAE5E;AAED,+EAA+E;AAC/E,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAWxF;AAED,0EAA0E;AAC1E,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAIjF;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,YAAY,CAAC,UAAU,CAAC,GAAG,SAAS,CA2BnG;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CA+BvF"}
|
package/dist/agent-history.js
CHANGED
|
@@ -101,4 +101,42 @@ export function readAgentHistory(cwd, locator) {
|
|
|
101
101
|
}
|
|
102
102
|
return messages.length > 0 ? messages : undefined;
|
|
103
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Read the last assistant text from a durable transcript. Runtime records may
|
|
106
|
+
* release their in-memory result after the retention TTL; the transcript then
|
|
107
|
+
* becomes the source of truth for get_subagent_result.
|
|
108
|
+
*/
|
|
109
|
+
export function readAgentHistoryResult(cwd, locator) {
|
|
110
|
+
const messages = readAgentHistory(cwd, locator);
|
|
111
|
+
if (!messages)
|
|
112
|
+
return undefined;
|
|
113
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
114
|
+
const message = messages[i];
|
|
115
|
+
if (message.role !== "assistant")
|
|
116
|
+
continue;
|
|
117
|
+
// AgentSession types currently model content as an array, but the
|
|
118
|
+
// persisted JSONL format may also contain a plain string. Cross the
|
|
119
|
+
// runtime/parser boundary through unknown so both shapes remain safe.
|
|
120
|
+
const content = message.content;
|
|
121
|
+
if (typeof content === "string") {
|
|
122
|
+
const text = content.trim();
|
|
123
|
+
if (text)
|
|
124
|
+
return text;
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (!Array.isArray(content))
|
|
128
|
+
continue;
|
|
129
|
+
const text = content
|
|
130
|
+
.filter((part) => typeof part === "object"
|
|
131
|
+
&& part !== null
|
|
132
|
+
&& part.type === "text"
|
|
133
|
+
&& typeof part.text === "string")
|
|
134
|
+
.map((part) => part.text)
|
|
135
|
+
.join("\n")
|
|
136
|
+
.trim();
|
|
137
|
+
if (text)
|
|
138
|
+
return text;
|
|
139
|
+
}
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
104
142
|
//# sourceMappingURL=agent-history.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-history.js","sourceRoot":"","sources":["../src/agent-history.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"agent-history.js","sourceRoot":"","sources":["../src/agent-history.ts"],"names":[],"mappings":"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"}
|
package/dist/agent-manager.d.ts
CHANGED
|
@@ -81,6 +81,8 @@ interface SpawnOptions {
|
|
|
81
81
|
}) => void;
|
|
82
82
|
/** Called when the session successfully compacts. */
|
|
83
83
|
onCompaction?: (info: CompactionInfo) => void;
|
|
84
|
+
/** Called synchronously after the record exists, before it is queued or started. */
|
|
85
|
+
onSpawned?: (id: string) => void;
|
|
84
86
|
}
|
|
85
87
|
export declare class AgentManager {
|
|
86
88
|
private agents;
|
|
@@ -92,14 +94,35 @@ export declare class AgentManager {
|
|
|
92
94
|
/** Base repos worktrees were created from — so dispose() can prune them all,
|
|
93
95
|
* not just the parent repo (caller-supplied cwd can target other repos). */
|
|
94
96
|
private worktreeRepos;
|
|
97
|
+
/** Project cwd for each record's durable checkpoint. */
|
|
98
|
+
private recoveryCwds;
|
|
95
99
|
/** Queue of background agents waiting to start. */
|
|
96
100
|
private queue;
|
|
97
101
|
/** Number of currently running background agents. */
|
|
98
102
|
private runningBackground;
|
|
103
|
+
/** Prevent late promise settlement from decrementing a replacement run. */
|
|
104
|
+
private runningBackgroundIds;
|
|
99
105
|
constructor(onComplete?: OnAgentComplete, maxConcurrent?: number, onStart?: OnAgentStart, onCompact?: OnAgentCompact);
|
|
100
106
|
/** Update the max concurrent background agents limit. */
|
|
101
107
|
setMaxConcurrent(n: number): void;
|
|
102
108
|
getMaxConcurrent(): number;
|
|
109
|
+
private finishBackground;
|
|
110
|
+
private checkpointStatus;
|
|
111
|
+
private makeCheckpoint;
|
|
112
|
+
private checkpoint;
|
|
113
|
+
private flushOutput;
|
|
114
|
+
/** Set the durable transcript locator and checkpoint the current state. */
|
|
115
|
+
setTranscript(id: string, historyFile: string, transcriptPath: string, cwd?: string): void;
|
|
116
|
+
/** Checkpoint one record explicitly (used after transcript setup). */
|
|
117
|
+
checkpointRecord(id: string): void;
|
|
118
|
+
/**
|
|
119
|
+
* Reload durable records from this project's checkpoint directory. A
|
|
120
|
+
* running/queued checkpoint means the process was killed before it could
|
|
121
|
+
* write its stopped state; treat it as stopped and retain its transcript.
|
|
122
|
+
* SIGKILL cannot run a final flush/checkpoint, so this active snapshot is
|
|
123
|
+
* necessarily the last recoverable state.
|
|
124
|
+
*/
|
|
125
|
+
restoreRecovered(cwd: string): void;
|
|
103
126
|
/**
|
|
104
127
|
* Spawn an agent and return its ID immediately (for background use).
|
|
105
128
|
* If the concurrency limit is reached, the agent is queued.
|
|
@@ -109,12 +132,6 @@ export declare class AgentManager {
|
|
|
109
132
|
private startAgent;
|
|
110
133
|
/** Start queued agents up to the concurrency limit. */
|
|
111
134
|
private drainQueue;
|
|
112
|
-
/**
|
|
113
|
-
* Called synchronously right after spawn, before onSessionCreated fires.
|
|
114
|
-
* Lets the caller set up the output file path on the record.
|
|
115
|
-
* The record is guaranteed to be in this.agents at this point.
|
|
116
|
-
*/
|
|
117
|
-
private onSpawned?;
|
|
118
135
|
/**
|
|
119
136
|
* Spawn an agent and wait for completion (foreground use).
|
|
120
137
|
* Foreground agents bypass the concurrency queue.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-manager.d.ts","sourceRoot":"","sources":["../src/agent-manager.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"agent-manager.d.ts","sourceRoot":"","sources":["../src/agent-manager.ts"],"names":[],"mappings":"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"}
|
package/dist/agent-manager.js
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
import { randomUUID } from "node:crypto";
|
|
9
9
|
import { statSync } from "node:fs";
|
|
10
10
|
import { isAbsolute } from "node:path";
|
|
11
|
+
import { readAgentHistory } from "./agent-history.js";
|
|
12
|
+
import { readAgentRecoveryCheckpoints, removeAgentRecoveryCheckpoint, writeAgentRecoveryCheckpoint, } from "./agent-recovery.js";
|
|
11
13
|
import { resumeAgent, runAgent } from "./agent-runner.js";
|
|
12
14
|
import { addUsage } from "./usage.js";
|
|
13
15
|
import { cleanupWorktree, createWorktree, pruneWorktrees, } from "./worktree.js";
|
|
@@ -134,10 +136,14 @@ export class AgentManager {
|
|
|
134
136
|
/** Base repos worktrees were created from — so dispose() can prune them all,
|
|
135
137
|
* not just the parent repo (caller-supplied cwd can target other repos). */
|
|
136
138
|
worktreeRepos = new Set();
|
|
139
|
+
/** Project cwd for each record's durable checkpoint. */
|
|
140
|
+
recoveryCwds = new Map();
|
|
137
141
|
/** Queue of background agents waiting to start. */
|
|
138
142
|
queue = [];
|
|
139
143
|
/** Number of currently running background agents. */
|
|
140
144
|
runningBackground = 0;
|
|
145
|
+
/** Prevent late promise settlement from decrementing a replacement run. */
|
|
146
|
+
runningBackgroundIds = new Set();
|
|
141
147
|
constructor(onComplete, maxConcurrent = DEFAULT_MAX_CONCURRENT, onStart, onCompact) {
|
|
142
148
|
this.onComplete = onComplete;
|
|
143
149
|
this.onStart = onStart;
|
|
@@ -156,6 +162,101 @@ export class AgentManager {
|
|
|
156
162
|
getMaxConcurrent() {
|
|
157
163
|
return this.maxConcurrent;
|
|
158
164
|
}
|
|
165
|
+
finishBackground(id) {
|
|
166
|
+
if (!this.runningBackgroundIds.delete(id))
|
|
167
|
+
return;
|
|
168
|
+
this.runningBackground = Math.max(0, this.runningBackground - 1);
|
|
169
|
+
}
|
|
170
|
+
checkpointStatus(record) {
|
|
171
|
+
return record.status;
|
|
172
|
+
}
|
|
173
|
+
makeCheckpoint(record) {
|
|
174
|
+
const checkpoint = {
|
|
175
|
+
version: 1,
|
|
176
|
+
id: record.id,
|
|
177
|
+
type: record.type,
|
|
178
|
+
description: record.description,
|
|
179
|
+
status: this.checkpointStatus(record),
|
|
180
|
+
startedAt: record.startedAt,
|
|
181
|
+
toolUses: record.toolUses,
|
|
182
|
+
lifetimeUsage: { ...record.lifetimeUsage },
|
|
183
|
+
compactionCount: record.compactionCount,
|
|
184
|
+
...(record.completedAt !== undefined && { completedAt: record.completedAt }),
|
|
185
|
+
// A durable transcript is the source of truth for partial/full output.
|
|
186
|
+
// Avoid duplicating potentially sensitive or very large result text.
|
|
187
|
+
...(!record.transcriptPath && record.result !== undefined && { result: record.result }),
|
|
188
|
+
...(record.error !== undefined && { error: record.error }),
|
|
189
|
+
...(record.transcriptPath !== undefined && { transcriptPath: record.transcriptPath }),
|
|
190
|
+
...(record.invocation !== undefined && { invocation: cloneInvocation(record.invocation) }),
|
|
191
|
+
};
|
|
192
|
+
return checkpoint;
|
|
193
|
+
}
|
|
194
|
+
checkpoint(record) {
|
|
195
|
+
const cwd = this.recoveryCwds.get(record.id);
|
|
196
|
+
if (!cwd)
|
|
197
|
+
return;
|
|
198
|
+
writeAgentRecoveryCheckpoint(cwd, this.makeCheckpoint(record));
|
|
199
|
+
}
|
|
200
|
+
flushOutput(record) {
|
|
201
|
+
if (!record.outputCleanup)
|
|
202
|
+
return;
|
|
203
|
+
try {
|
|
204
|
+
record.outputCleanup();
|
|
205
|
+
}
|
|
206
|
+
catch { /* recovery must remain best effort */ }
|
|
207
|
+
record.outputCleanup = undefined;
|
|
208
|
+
}
|
|
209
|
+
/** Set the durable transcript locator and checkpoint the current state. */
|
|
210
|
+
setTranscript(id, historyFile, transcriptPath, cwd) {
|
|
211
|
+
const record = this.agents.get(id);
|
|
212
|
+
if (!record)
|
|
213
|
+
return;
|
|
214
|
+
record.historyFile = historyFile;
|
|
215
|
+
record.transcriptPath = transcriptPath;
|
|
216
|
+
if (cwd)
|
|
217
|
+
this.recoveryCwds.set(id, cwd);
|
|
218
|
+
this.checkpoint(record);
|
|
219
|
+
}
|
|
220
|
+
/** Checkpoint one record explicitly (used after transcript setup). */
|
|
221
|
+
checkpointRecord(id) {
|
|
222
|
+
const record = this.agents.get(id);
|
|
223
|
+
if (record)
|
|
224
|
+
this.checkpoint(record);
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Reload durable records from this project's checkpoint directory. A
|
|
228
|
+
* running/queued checkpoint means the process was killed before it could
|
|
229
|
+
* write its stopped state; treat it as stopped and retain its transcript.
|
|
230
|
+
* SIGKILL cannot run a final flush/checkpoint, so this active snapshot is
|
|
231
|
+
* necessarily the last recoverable state.
|
|
232
|
+
*/
|
|
233
|
+
restoreRecovered(cwd) {
|
|
234
|
+
for (const checkpoint of readAgentRecoveryCheckpoints(cwd)) {
|
|
235
|
+
if (!checkpoint.transcriptPath || !readAgentHistory(cwd, checkpoint.transcriptPath))
|
|
236
|
+
continue;
|
|
237
|
+
const status = checkpoint.status === "running" || checkpoint.status === "queued"
|
|
238
|
+
? "stopped"
|
|
239
|
+
: checkpoint.status;
|
|
240
|
+
const completedAt = checkpoint.completedAt ?? Date.now();
|
|
241
|
+
const existing = this.agents.get(checkpoint.id);
|
|
242
|
+
if (existing) {
|
|
243
|
+
// Parent-branch records can still carry an unread in-memory result.
|
|
244
|
+
// Never replace that richer record with the checkpoint's transcript
|
|
245
|
+
// stub during the same session. Merge only durable locator metadata.
|
|
246
|
+
if (!existing.transcriptPath && checkpoint.transcriptPath) {
|
|
247
|
+
existing.transcriptPath = checkpoint.transcriptPath;
|
|
248
|
+
}
|
|
249
|
+
this.recoveryCwds.set(checkpoint.id, cwd);
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
this.agents.set(checkpoint.id, this.createRestoredRecord({
|
|
253
|
+
...checkpoint,
|
|
254
|
+
status,
|
|
255
|
+
completedAt,
|
|
256
|
+
}));
|
|
257
|
+
this.recoveryCwds.set(checkpoint.id, cwd);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
159
260
|
/**
|
|
160
261
|
* Spawn an agent and return its ID immediately (for background use).
|
|
161
262
|
* If the concurrency limit is reached, the agent is queued.
|
|
@@ -186,6 +287,20 @@ export class AgentManager {
|
|
|
186
287
|
invocation: options.invocation,
|
|
187
288
|
};
|
|
188
289
|
this.agents.set(id, record);
|
|
290
|
+
this.recoveryCwds.set(id, ctx.cwd);
|
|
291
|
+
// Give callers a chance to create the durable transcript before the first
|
|
292
|
+
// checkpoint. This closes the small spawn→attach window in which a queued
|
|
293
|
+
// or running agent could be left recoverable only as metadata.
|
|
294
|
+
try {
|
|
295
|
+
options.onSpawned?.(id);
|
|
296
|
+
this.checkpoint(record);
|
|
297
|
+
}
|
|
298
|
+
catch (err) {
|
|
299
|
+
this.agents.delete(id);
|
|
300
|
+
this.recoveryCwds.delete(id);
|
|
301
|
+
removeAgentRecoveryCheckpoint(ctx.cwd, id);
|
|
302
|
+
throw err;
|
|
303
|
+
}
|
|
189
304
|
const args = { pi, ctx, type, prompt, options };
|
|
190
305
|
if (options.isBackground && !options.bypassQueue && this.runningBackground >= this.maxConcurrent) {
|
|
191
306
|
// Queue it — will be started when a running agent completes
|
|
@@ -199,6 +314,8 @@ export class AgentManager {
|
|
|
199
314
|
}
|
|
200
315
|
catch (err) {
|
|
201
316
|
this.agents.delete(id);
|
|
317
|
+
this.recoveryCwds.delete(id);
|
|
318
|
+
removeAgentRecoveryCheckpoint(ctx.cwd, id);
|
|
202
319
|
throw err;
|
|
203
320
|
}
|
|
204
321
|
return id;
|
|
@@ -235,8 +352,11 @@ export class AgentManager {
|
|
|
235
352
|
}
|
|
236
353
|
record.status = "running";
|
|
237
354
|
record.startedAt = Date.now();
|
|
238
|
-
|
|
355
|
+
this.checkpoint(record);
|
|
356
|
+
if (options.isBackground) {
|
|
239
357
|
this.runningBackground++;
|
|
358
|
+
this.runningBackgroundIds.add(id);
|
|
359
|
+
}
|
|
240
360
|
this.onStart?.(record);
|
|
241
361
|
// Wire parent abort signal to stop the subagent when the parent is interrupted
|
|
242
362
|
let detachParentSignal;
|
|
@@ -294,9 +414,14 @@ export class AgentManager {
|
|
|
294
414
|
record.pendingSteers = undefined;
|
|
295
415
|
}
|
|
296
416
|
options.onSessionCreated?.(session);
|
|
417
|
+
this.checkpoint(record);
|
|
297
418
|
},
|
|
298
419
|
})
|
|
299
420
|
.then(({ responseText, session, aborted, steered, failure }) => {
|
|
421
|
+
// A disposed manager no longer owns this run. Avoid late callbacks
|
|
422
|
+
// mutating a dead session or emitting completion side effects.
|
|
423
|
+
if (this.agents.get(id) !== record)
|
|
424
|
+
return responseText;
|
|
300
425
|
// Don't overwrite status if externally stopped via abort()
|
|
301
426
|
if (record.status !== "stopped") {
|
|
302
427
|
// Precedence: a hard abort keeps "aborted"; then a failed final turn
|
|
@@ -337,6 +462,7 @@ export class AgentManager {
|
|
|
337
462
|
`\n\n---\nChanges saved to branch \`${wtResult.branch}\`${repoNote}. Merge with: \`git merge ${wtResult.branch}\`${customCwd !== undefined ? ` (run in \`${baseCwd}\`)` : ""}`;
|
|
338
463
|
}
|
|
339
464
|
}
|
|
465
|
+
this.checkpoint(record);
|
|
340
466
|
// Fire onComplete for foreground agents too — lifecycle symmetry.
|
|
341
467
|
// Mark resultConsumed so the callback skips notifications (result returned inline).
|
|
342
468
|
if (!options.isBackground) {
|
|
@@ -347,7 +473,7 @@ export class AgentManager {
|
|
|
347
473
|
catch { /* ignore completion side-effect errors */ }
|
|
348
474
|
}
|
|
349
475
|
else {
|
|
350
|
-
this.
|
|
476
|
+
this.finishBackground(id);
|
|
351
477
|
try {
|
|
352
478
|
this.onComplete?.(record);
|
|
353
479
|
}
|
|
@@ -357,6 +483,10 @@ export class AgentManager {
|
|
|
357
483
|
return responseText;
|
|
358
484
|
})
|
|
359
485
|
.catch((err) => {
|
|
486
|
+
// A disposed manager no longer owns this run. Avoid late callbacks
|
|
487
|
+
// mutating a dead session or emitting completion side effects.
|
|
488
|
+
if (this.agents.get(id) !== record)
|
|
489
|
+
return "";
|
|
360
490
|
// Don't overwrite status if externally stopped via abort()
|
|
361
491
|
if (record.status !== "stopped") {
|
|
362
492
|
record.status = "error";
|
|
@@ -380,6 +510,7 @@ export class AgentManager {
|
|
|
380
510
|
}
|
|
381
511
|
catch { /* ignore cleanup errors */ }
|
|
382
512
|
}
|
|
513
|
+
this.checkpoint(record);
|
|
383
514
|
// Fire onComplete for foreground agents too — lifecycle symmetry.
|
|
384
515
|
// Mark resultConsumed so the callback skips notifications (result returned inline).
|
|
385
516
|
if (!options.isBackground) {
|
|
@@ -387,17 +518,13 @@ export class AgentManager {
|
|
|
387
518
|
this.onComplete?.(record);
|
|
388
519
|
}
|
|
389
520
|
else {
|
|
390
|
-
this.
|
|
521
|
+
this.finishBackground(id);
|
|
391
522
|
this.onComplete?.(record);
|
|
392
523
|
this.drainQueue();
|
|
393
524
|
}
|
|
394
525
|
return "";
|
|
395
526
|
});
|
|
396
527
|
record.promise = promise;
|
|
397
|
-
// Notify caller that spawn is complete (record is in the map, promise is set).
|
|
398
|
-
// Called synchronously — onSessionCreated fires asynchronously inside runAgent.
|
|
399
|
-
// Used by spawnAndWait to let the caller set up output files before streaming starts.
|
|
400
|
-
this.onSpawned?.(id);
|
|
401
528
|
}
|
|
402
529
|
/** Start queued agents up to the concurrency limit. */
|
|
403
530
|
drainQueue() {
|
|
@@ -415,16 +542,11 @@ export class AgentManager {
|
|
|
415
542
|
record.status = "error";
|
|
416
543
|
record.error = err instanceof Error ? err.message : String(err);
|
|
417
544
|
record.completedAt = Date.now();
|
|
545
|
+
this.checkpoint(record);
|
|
418
546
|
this.onComplete?.(record);
|
|
419
547
|
}
|
|
420
548
|
}
|
|
421
549
|
}
|
|
422
|
-
/**
|
|
423
|
-
* Called synchronously right after spawn, before onSessionCreated fires.
|
|
424
|
-
* Lets the caller set up the output file path on the record.
|
|
425
|
-
* The record is guaranteed to be in this.agents at this point.
|
|
426
|
-
*/
|
|
427
|
-
onSpawned;
|
|
428
550
|
/**
|
|
429
551
|
* Spawn an agent and wait for completion (foreground use).
|
|
430
552
|
* Foreground agents bypass the concurrency queue.
|
|
@@ -434,18 +556,14 @@ export class AgentManager {
|
|
|
434
556
|
* Use this to set record.outputFile so streamToOutputFile can pick it up.
|
|
435
557
|
*/
|
|
436
558
|
async spawnAndWait(pi, ctx, type, prompt, options, onSpawned) {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
}
|
|
446
|
-
finally {
|
|
447
|
-
this.onSpawned = prevOnSpawned;
|
|
448
|
-
}
|
|
559
|
+
const id = this.spawn(pi, ctx, type, prompt, {
|
|
560
|
+
...options,
|
|
561
|
+
isBackground: false,
|
|
562
|
+
onSpawned,
|
|
563
|
+
});
|
|
564
|
+
const record = this.agents.get(id);
|
|
565
|
+
await record.promise;
|
|
566
|
+
return { id, record };
|
|
449
567
|
}
|
|
450
568
|
/**
|
|
451
569
|
* Resume an existing agent session with a new prompt.
|
|
@@ -465,6 +583,7 @@ export class AgentManager {
|
|
|
465
583
|
...(resumedModel && { effectiveModelName: resumedModel.name ?? resumedModel.id }),
|
|
466
584
|
effectiveThinking: record.session.thinkingLevel,
|
|
467
585
|
};
|
|
586
|
+
this.checkpoint(record);
|
|
468
587
|
try {
|
|
469
588
|
const { text, failure } = await resumeAgent(record.session, prompt, {
|
|
470
589
|
onToolActivity: (activity) => {
|
|
@@ -487,11 +606,13 @@ export class AgentManager {
|
|
|
487
606
|
record.error = failure;
|
|
488
607
|
record.result = text;
|
|
489
608
|
record.completedAt = Date.now();
|
|
609
|
+
this.checkpoint(record);
|
|
490
610
|
}
|
|
491
611
|
catch (err) {
|
|
492
612
|
record.status = "error";
|
|
493
613
|
record.error = err instanceof Error ? err.message : String(err);
|
|
494
614
|
record.completedAt = Date.now();
|
|
615
|
+
this.checkpoint(record);
|
|
495
616
|
}
|
|
496
617
|
return record;
|
|
497
618
|
}
|
|
@@ -556,7 +677,7 @@ export class AgentManager {
|
|
|
556
677
|
lifetimeUsage: record.lifetimeUsage
|
|
557
678
|
? { ...record.lifetimeUsage }
|
|
558
679
|
: { input: 0, output: 0, cacheWrite: 0 },
|
|
559
|
-
compactionCount: 0,
|
|
680
|
+
compactionCount: record.compactionCount ?? 0,
|
|
560
681
|
};
|
|
561
682
|
}
|
|
562
683
|
abort(id) {
|
|
@@ -568,6 +689,7 @@ export class AgentManager {
|
|
|
568
689
|
this.queue = this.queue.filter(q => q.id !== id);
|
|
569
690
|
record.status = "stopped";
|
|
570
691
|
record.completedAt = Date.now();
|
|
692
|
+
this.checkpoint(record);
|
|
571
693
|
return true;
|
|
572
694
|
}
|
|
573
695
|
if (record.status !== "running")
|
|
@@ -575,6 +697,10 @@ export class AgentManager {
|
|
|
575
697
|
record.abortController?.abort();
|
|
576
698
|
record.status = "stopped";
|
|
577
699
|
record.completedAt = Date.now();
|
|
700
|
+
this.flushOutput(record);
|
|
701
|
+
this.checkpoint(record);
|
|
702
|
+
this.finishBackground(id);
|
|
703
|
+
this.drainQueue();
|
|
578
704
|
return true;
|
|
579
705
|
}
|
|
580
706
|
/** Dispose a record's session and remove it from the map. */
|
|
@@ -607,6 +733,10 @@ export class AgentManager {
|
|
|
607
733
|
record.outputCleanup = undefined;
|
|
608
734
|
record.outputFile = undefined;
|
|
609
735
|
record.historyFile = undefined;
|
|
736
|
+
// The durable transcript is the source of truth after the TTL. Keep
|
|
737
|
+
// only the small identity/status record in memory; get_subagent_result
|
|
738
|
+
// reloads the final answer from transcriptPath on demand.
|
|
739
|
+
record.result = undefined;
|
|
610
740
|
continue;
|
|
611
741
|
}
|
|
612
742
|
this.removeRecord(id, record);
|
|
@@ -640,16 +770,21 @@ export class AgentManager {
|
|
|
640
770
|
if (record) {
|
|
641
771
|
record.status = "stopped";
|
|
642
772
|
record.completedAt = Date.now();
|
|
773
|
+
this.checkpoint(record);
|
|
643
774
|
count++;
|
|
644
775
|
}
|
|
645
776
|
}
|
|
646
777
|
this.queue = [];
|
|
647
|
-
// Abort running agents
|
|
778
|
+
// Abort running agents. Flush before checkpointing so a catchable
|
|
779
|
+
// shutdown/session switch leaves the latest assistant message available.
|
|
648
780
|
for (const record of this.agents.values()) {
|
|
649
781
|
if (record.status === "running") {
|
|
650
782
|
record.abortController?.abort();
|
|
651
783
|
record.status = "stopped";
|
|
652
784
|
record.completedAt = Date.now();
|
|
785
|
+
this.flushOutput(record);
|
|
786
|
+
this.finishBackground(record.id);
|
|
787
|
+
this.checkpoint(record);
|
|
653
788
|
count++;
|
|
654
789
|
}
|
|
655
790
|
}
|
|
@@ -678,6 +813,9 @@ export class AgentManager {
|
|
|
678
813
|
record.session?.dispose();
|
|
679
814
|
}
|
|
680
815
|
this.agents.clear();
|
|
816
|
+
this.recoveryCwds.clear();
|
|
817
|
+
this.runningBackgroundIds.clear();
|
|
818
|
+
this.runningBackground = 0;
|
|
681
819
|
// Prune any orphaned git worktrees (crash recovery)
|
|
682
820
|
try {
|
|
683
821
|
pruneWorktrees(process.cwd());
|