@kenkaiiii/ggcoder 5.26.2 → 5.26.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/dist/app-sidecar.js +54 -47
- package/dist/app-sidecar.js.map +1 -1
- package/dist/core/agent-session-marker-anchors.test.js +181 -2
- package/dist/core/agent-session-marker-anchors.test.js.map +1 -1
- package/dist/core/agent-session-slash-restore.test.d.ts +2 -0
- package/dist/core/agent-session-slash-restore.test.d.ts.map +1 -0
- package/dist/core/agent-session-slash-restore.test.js +121 -0
- package/dist/core/agent-session-slash-restore.test.js.map +1 -0
- package/dist/core/agent-session.d.ts +26 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +92 -29
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/compactor.d.ts +21 -0
- package/dist/core/compaction/compactor.d.ts.map +1 -1
- package/dist/core/compaction/compactor.js +16 -0
- package/dist/core/compaction/compactor.js.map +1 -1
- package/dist/core/compaction/compactor.test.js +91 -0
- package/dist/core/compaction/compactor.test.js.map +1 -1
- package/dist/core/session-history.d.ts +61 -4
- package/dist/core/session-history.d.ts.map +1 -1
- package/dist/core/session-history.js +144 -15
- package/dist/core/session-history.js.map +1 -1
- package/dist/core/session-history.test.js +50 -1
- package/dist/core/session-history.test.js.map +1 -1
- package/dist/core/session-manager.d.ts +30 -5
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +37 -9
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-manager.test.js +14 -2
- package/dist/core/session-manager.test.js.map +1 -1
- package/package.json +4 -4
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
import { STEERING_PREFIX } from "./steering.js";
|
|
2
2
|
import { AUTOPILOT_INJECTION_PREAMBLE } from "./autopilot-cycle.js";
|
|
3
|
+
/**
|
|
4
|
+
* Move a transcript anchor (`afterMessageCount`) from the pre-compaction
|
|
5
|
+
* message list onto the compacted one.
|
|
6
|
+
*
|
|
7
|
+
* Compaction folds the leading `summarizedCount` non-system messages into a
|
|
8
|
+
* `prefixCount`-message summary block and keeps the rest verbatim. Anchors
|
|
9
|
+
* inside the collapsed region land right after the summary (their surrounding
|
|
10
|
+
* conversation no longer exists); anchors in the retained tail shift by the
|
|
11
|
+
* difference. Without this, re-persisted markers keep indices from a much
|
|
12
|
+
* longer transcript — they then replay far too late, or past the end, which is
|
|
13
|
+
* what bunches old Ken bubbles and error rows at the bottom on resume.
|
|
14
|
+
*/
|
|
15
|
+
export function remapAnchorForCompaction(anchor, remap) {
|
|
16
|
+
const moved = anchor <= remap.summarizedCount
|
|
17
|
+
? Math.min(anchor, remap.prefixCount)
|
|
18
|
+
: anchor - remap.summarizedCount + remap.prefixCount;
|
|
19
|
+
// The retained tail can be shorter than the collapse implies (tool-pairing
|
|
20
|
+
// repair, trailing-assistant pop), so clamp to the real end of the new list.
|
|
21
|
+
return Math.min(moved, remap.newNonSystemCount);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Drop the read-only file-order position before writing a marker back to disk.
|
|
25
|
+
* It describes where a marker sat in the file it was READ from, so persisting
|
|
26
|
+
* it into a rewritten file would bake in a position that no longer applies —
|
|
27
|
+
* the next load recomputes it anyway.
|
|
28
|
+
*/
|
|
29
|
+
export function stripRecordedPosition(payload) {
|
|
30
|
+
const { recordedAfterMessageCount: _ignored, ...rest } = payload;
|
|
31
|
+
return rest;
|
|
32
|
+
}
|
|
3
33
|
function markerKey(marker) {
|
|
4
34
|
return JSON.stringify({
|
|
5
35
|
phase: marker.phase,
|
|
@@ -11,25 +41,64 @@ function markerKey(marker) {
|
|
|
11
41
|
export function autopilotMarkerCopySeed(marker) {
|
|
12
42
|
return `${marker.phase}\0${marker.afterMessageCount}\0${marker.reason ?? ""}\0${marker.body ?? ""}`;
|
|
13
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Resolve the replay position for one persisted marker.
|
|
46
|
+
*
|
|
47
|
+
* A marker's anchor counts messages that were ALREADY on disk when it was
|
|
48
|
+
* recorded, and markers are appended after those messages — so a correctly
|
|
49
|
+
* written marker can never sit at a file position lower than its own anchor.
|
|
50
|
+
* File order is therefore a hard ceiling, and an anchor above it is provably
|
|
51
|
+
* stale. Two historical paths produced exactly that:
|
|
52
|
+
*
|
|
53
|
+
* - compaction re-persisted markers into the continuation file while they
|
|
54
|
+
* still carried indices from the much longer pre-compaction transcript;
|
|
55
|
+
* - older sessions anchored against the in-memory message list, which runs
|
|
56
|
+
* ahead of the file whenever a run fails before its messages are flushed.
|
|
57
|
+
*
|
|
58
|
+
* Both make markers replay far too late — bunched at the bottom of a reopened
|
|
59
|
+
* session, or dropped entirely when the anchor overshoots the end. Clamping to
|
|
60
|
+
* the file position fixes both. The clamp only ever moves an anchor DOWN;
|
|
61
|
+
* markers written before their messages landed (fire-and-forget persistence)
|
|
62
|
+
* legitimately sit below their file position and are left alone.
|
|
63
|
+
*
|
|
64
|
+
* `ceilingOffset` covers markers deliberately anchored ahead of the file — the
|
|
65
|
+
* user_hint that attaches to the user message a prompt is about to push.
|
|
66
|
+
* Returns null when even the clamped anchor falls outside the transcript.
|
|
67
|
+
*/
|
|
68
|
+
function resolveAnchor(marker, maxAfterMessageCount, ceilingOffset = 0) {
|
|
69
|
+
const ceiling = marker.recordedAfterMessageCount === undefined
|
|
70
|
+
? Number.POSITIVE_INFINITY
|
|
71
|
+
: marker.recordedAfterMessageCount + ceilingOffset;
|
|
72
|
+
const anchor = Math.min(marker.afterMessageCount, ceiling);
|
|
73
|
+
return anchor <= maxAfterMessageCount ? anchor : null;
|
|
74
|
+
}
|
|
14
75
|
/**
|
|
15
76
|
* Normalize persisted autopilot markers for transcript replay.
|
|
16
77
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* at EOF
|
|
20
|
-
*
|
|
78
|
+
* Stale anchors are pulled back to where the marker was actually written (see
|
|
79
|
+
* {@link resolveAnchor}); anything still outside the restored transcript is
|
|
80
|
+
* dropped rather than replayed at EOF, which is what bunched old Ken all-clear
|
|
81
|
+
* bubbles at the bottom. Exact duplicate payloads from old rewrite/re-persist
|
|
82
|
+
* paths are deduped.
|
|
21
83
|
*/
|
|
22
84
|
export function normalizeAutopilotMarkersForHistory(markers, maxAfterMessageCount) {
|
|
23
85
|
const seen = new Set();
|
|
24
86
|
const normalized = [];
|
|
25
87
|
for (const marker of markers) {
|
|
26
|
-
|
|
88
|
+
const anchor = resolveAnchor(marker, maxAfterMessageCount);
|
|
89
|
+
if (anchor === null)
|
|
27
90
|
continue;
|
|
28
91
|
const key = markerKey(marker);
|
|
29
92
|
if (seen.has(key))
|
|
30
93
|
continue;
|
|
31
94
|
seen.add(key);
|
|
32
|
-
|
|
95
|
+
// The copy seed stays tied to the PERSISTED anchor so the all-clear wording
|
|
96
|
+
// a resumed session shows matches the one the live run broadcast.
|
|
97
|
+
normalized.push({
|
|
98
|
+
...marker,
|
|
99
|
+
afterMessageCount: anchor,
|
|
100
|
+
copySeed: autopilotMarkerCopySeed(marker),
|
|
101
|
+
});
|
|
33
102
|
}
|
|
34
103
|
return normalized;
|
|
35
104
|
}
|
|
@@ -43,7 +112,10 @@ export function normalizeAppMarkersForHistory(markers, maxAfterMessageCount) {
|
|
|
43
112
|
const seen = new Set();
|
|
44
113
|
const normalized = [];
|
|
45
114
|
for (const marker of markers) {
|
|
46
|
-
|
|
115
|
+
// user_hint is anchored +1 on purpose so it decorates the user row a prompt
|
|
116
|
+
// is about to add; everything else must not exceed its file position.
|
|
117
|
+
const anchor = resolveAnchor(marker, maxAfterMessageCount, marker.kind === "user_hint" ? 1 : 0);
|
|
118
|
+
if (anchor === null)
|
|
47
119
|
continue;
|
|
48
120
|
const key = JSON.stringify({
|
|
49
121
|
kind: marker.kind,
|
|
@@ -53,7 +125,7 @@ export function normalizeAppMarkersForHistory(markers, maxAfterMessageCount) {
|
|
|
53
125
|
if (seen.has(key))
|
|
54
126
|
continue;
|
|
55
127
|
seen.add(key);
|
|
56
|
-
normalized.push(marker);
|
|
128
|
+
normalized.push(anchor === marker.afterMessageCount ? marker : { ...marker, afterMessageCount: anchor });
|
|
57
129
|
}
|
|
58
130
|
return normalized;
|
|
59
131
|
}
|
|
@@ -72,9 +144,10 @@ export function normalizeKenTurnsForHistory(turns, maxAfterMessageCount) {
|
|
|
72
144
|
if (seen.has(key))
|
|
73
145
|
continue;
|
|
74
146
|
seen.add(key);
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
147
|
+
// File order first, EOF clamp only as a last resort — clamping is exactly
|
|
148
|
+
// what stacked resumed Ken exchanges at the bottom of the transcript.
|
|
149
|
+
const anchor = resolveAnchor(turn, maxAfterMessageCount) ?? maxAfterMessageCount;
|
|
150
|
+
normalized.push(anchor === turn.afterMessageCount ? turn : { ...turn, afterMessageCount: anchor });
|
|
78
151
|
}
|
|
79
152
|
return normalized;
|
|
80
153
|
}
|
|
@@ -101,10 +174,16 @@ function stripSteering(text) {
|
|
|
101
174
|
* on resume the raw session message must render the same clean instruction, not
|
|
102
175
|
* the machine-facing preamble. */
|
|
103
176
|
function stripAutopilotPreamble(text) {
|
|
104
|
-
return text
|
|
177
|
+
return hasAutopilotPreamble(text)
|
|
105
178
|
? text.slice(AUTOPILOT_INJECTION_PREAMBLE.length).trimStart()
|
|
106
179
|
: text;
|
|
107
180
|
}
|
|
181
|
+
/** Whether a persisted user message was injected by autopilot rather than typed
|
|
182
|
+
* by a human. frameAutopilotInjection adds this preamble to every injected
|
|
183
|
+
* build run, and nothing else produces it. */
|
|
184
|
+
function hasAutopilotPreamble(text) {
|
|
185
|
+
return text.startsWith(AUTOPILOT_INJECTION_PREAMBLE);
|
|
186
|
+
}
|
|
108
187
|
function stripAttachedFilesBlock(text) {
|
|
109
188
|
if (text.startsWith(ATTACHED_FILES_HEADER))
|
|
110
189
|
return "";
|
|
@@ -114,15 +193,18 @@ function stripAttachedFilesBlock(text) {
|
|
|
114
193
|
/** Rebuild the live user bubble from a persisted user message's content. */
|
|
115
194
|
export function restoreUserRow(content) {
|
|
116
195
|
if (typeof content === "string") {
|
|
196
|
+
const unsteered = stripSteering(content);
|
|
117
197
|
return {
|
|
118
|
-
text: stripAttachedFilesBlock(stripAutopilotPreamble(
|
|
198
|
+
text: stripAttachedFilesBlock(stripAutopilotPreamble(unsteered)).trim(),
|
|
119
199
|
images: [],
|
|
120
200
|
videoWarning: false,
|
|
201
|
+
autopilotInjected: hasAutopilotPreamble(unsteered),
|
|
121
202
|
};
|
|
122
203
|
}
|
|
123
204
|
const images = [];
|
|
124
205
|
const textParts = [];
|
|
125
206
|
let videoWarning = false;
|
|
207
|
+
let autopilotInjected = false;
|
|
126
208
|
for (const c of content) {
|
|
127
209
|
if (c.type === "image") {
|
|
128
210
|
images.push(`data:${c.mediaType};base64,${c.data}`);
|
|
@@ -130,7 +212,10 @@ export function restoreUserRow(content) {
|
|
|
130
212
|
}
|
|
131
213
|
if (c.type !== "text" || typeof c.text !== "string")
|
|
132
214
|
continue;
|
|
133
|
-
const
|
|
215
|
+
const unsteered = stripSteering(c.text);
|
|
216
|
+
if (hasAutopilotPreamble(unsteered))
|
|
217
|
+
autopilotInjected = true;
|
|
218
|
+
const stripped = stripAutopilotPreamble(unsteered);
|
|
134
219
|
if (stripped.startsWith("[User attached a video file"))
|
|
135
220
|
videoWarning = true;
|
|
136
221
|
if (ATTACHMENT_NOTE_PATTERNS.some((re) => re.test(stripped)))
|
|
@@ -139,7 +224,51 @@ export function restoreUserRow(content) {
|
|
|
139
224
|
if (cleaned.trim())
|
|
140
225
|
textParts.push(cleaned);
|
|
141
226
|
}
|
|
142
|
-
return { text: textParts.join("\n\n").trim(), images, videoWarning };
|
|
227
|
+
return { text: textParts.join("\n\n").trim(), images, videoWarning, autopilotInjected };
|
|
228
|
+
}
|
|
229
|
+
// ── Slash-command reconstruction ──────────────────────────────
|
|
230
|
+
// A `/name` command is expanded before it reaches the model, so the persisted
|
|
231
|
+
// user message is the FULL template body — not the short chip the user saw.
|
|
232
|
+
/** Separator AgentSession.prompt() inserts between a command's prompt body and
|
|
233
|
+
* the user's trailing args. Must stay in sync with the expansion there. */
|
|
234
|
+
const COMMAND_ARGS_SEP = "\n\n## User Instructions\n\n";
|
|
235
|
+
/**
|
|
236
|
+
* Reverse a prompt-template command's expansion by matching the restored body
|
|
237
|
+
* against the known templates.
|
|
238
|
+
*
|
|
239
|
+
* Best-effort only: it works while a template is byte-identical to the one that
|
|
240
|
+
* produced the message, and templates drift (edited `.gg/commands/*.md`,
|
|
241
|
+
* reworded built-ins, app-vs-CLI phrasing). Prefer the invocation recorded at
|
|
242
|
+
* send time — see {@link resolveRestoredCommand}. Returns null when the text
|
|
243
|
+
* isn't a known command body (an ordinary user message).
|
|
244
|
+
*/
|
|
245
|
+
export function detectPromptCommand(text, candidates) {
|
|
246
|
+
for (const c of candidates) {
|
|
247
|
+
if (!c.prompt)
|
|
248
|
+
continue;
|
|
249
|
+
if (text === c.prompt)
|
|
250
|
+
return `/${c.name}`;
|
|
251
|
+
if (text.startsWith(c.prompt + COMMAND_ARGS_SEP)) {
|
|
252
|
+
const args = text.slice(c.prompt.length + COMMAND_ARGS_SEP.length).trim();
|
|
253
|
+
return args ? `/${c.name} ${args}` : `/${c.name}`;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* The `/name [args]` chip a restored user row should show, or null for an
|
|
260
|
+
* ordinary message.
|
|
261
|
+
*
|
|
262
|
+
* The invocation persisted with the prompt wins: it's exactly what the user
|
|
263
|
+
* typed and survives any later template edit. Sessions recorded before that was
|
|
264
|
+
* persisted fall back to matching the expanded body, which is why an edited
|
|
265
|
+
* command used to resume as its raw multi-KB template.
|
|
266
|
+
*/
|
|
267
|
+
export function resolveRestoredCommand(persistedCommand, text, candidates) {
|
|
268
|
+
if (typeof persistedCommand === "string" && persistedCommand.trim()) {
|
|
269
|
+
return persistedCommand.trim();
|
|
270
|
+
}
|
|
271
|
+
return detectPromptCommand(text, candidates);
|
|
143
272
|
}
|
|
144
273
|
/**
|
|
145
274
|
* Split a persisted assistant message into per-bubble texts. Live streaming
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-history.js","sourceRoot":"","sources":["../../src/core/session-history.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"session-history.js","sourceRoot":"","sources":["../../src/core/session-history.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
import { STEERING_PREFIX } from "./steering.js";
|
|
3
3
|
import { frameAutopilotInjection } from "./autopilot-cycle.js";
|
|
4
|
-
import { normalizeAutopilotMarkersForHistory, normalizeAppMarkersForHistory, normalizeKenTurnsForHistory, restoreUserRow, restoreAssistantTexts, } from "./session-history.js";
|
|
4
|
+
import { normalizeAutopilotMarkersForHistory, normalizeAppMarkersForHistory, normalizeKenTurnsForHistory, restoreUserRow, restoreAssistantTexts, detectPromptCommand, resolveRestoredCommand, } from "./session-history.js";
|
|
5
5
|
describe("normalizeAutopilotMarkersForHistory", () => {
|
|
6
6
|
it("drops out-of-range compacted-session markers and dedupes exact all-clear rows", () => {
|
|
7
7
|
const markers = [
|
|
@@ -60,6 +60,22 @@ describe("restoreUserRow", () => {
|
|
|
60
60
|
expect(row.text).toBe("Add a test for the login flow.");
|
|
61
61
|
expect(row.text).not.toContain("[Autopilot]");
|
|
62
62
|
});
|
|
63
|
+
it("flags autopilot-injected turns so resume can skip the bubble live never showed", () => {
|
|
64
|
+
const injected = restoreUserRow(frameAutopilotInjection("Fix the failing test."));
|
|
65
|
+
expect(injected.autopilotInjected).toBe(true);
|
|
66
|
+
// The same body typed by a human keeps its user bubble.
|
|
67
|
+
expect(restoreUserRow("Fix the failing test.").autopilotInjected).toBe(false);
|
|
68
|
+
});
|
|
69
|
+
it("detects the autopilot preamble under a steering wrapper and in block content", () => {
|
|
70
|
+
const steered = restoreUserRow(`${STEERING_PREFIX}${frameAutopilotInjection("Retry the deploy.")}`);
|
|
71
|
+
expect(steered.autopilotInjected).toBe(true);
|
|
72
|
+
expect(steered.text).toBe("Retry the deploy.");
|
|
73
|
+
const blocks = restoreUserRow([
|
|
74
|
+
{ type: "text", text: frameAutopilotInjection("Retry the deploy.") },
|
|
75
|
+
]);
|
|
76
|
+
expect(blocks.autopilotInjected).toBe(true);
|
|
77
|
+
expect(blocks.text).toBe("Retry the deploy.");
|
|
78
|
+
});
|
|
63
79
|
it("drops attachment notes and the attached-files block, keeps typed text + images", () => {
|
|
64
80
|
const row = restoreUserRow([
|
|
65
81
|
{
|
|
@@ -85,6 +101,39 @@ describe("restoreUserRow", () => {
|
|
|
85
101
|
expect(row.videoWarning).toBe(true);
|
|
86
102
|
});
|
|
87
103
|
});
|
|
104
|
+
describe("resolveRestoredCommand", () => {
|
|
105
|
+
const candidates = [
|
|
106
|
+
{ name: "release", prompt: "# Release\n\nShip the thing." },
|
|
107
|
+
{ name: "commit", prompt: "# Commit\n\nWrite a commit." },
|
|
108
|
+
];
|
|
109
|
+
it("reverses an expanded template body back to its /name chip", () => {
|
|
110
|
+
expect(detectPromptCommand("# Release\n\nShip the thing.", candidates)).toBe("/release");
|
|
111
|
+
expect(resolveRestoredCommand(null, "# Release\n\nShip the thing.", candidates)).toBe("/release");
|
|
112
|
+
});
|
|
113
|
+
it("keeps the user's trailing args", () => {
|
|
114
|
+
const body = "# Release\n\nShip the thing.\n\n## User Instructions\n\npatch only";
|
|
115
|
+
expect(resolveRestoredCommand(null, body, candidates)).toBe("/release patch only");
|
|
116
|
+
});
|
|
117
|
+
it("leaves an ordinary message alone", () => {
|
|
118
|
+
expect(resolveRestoredCommand(null, "just a normal question", candidates)).toBeNull();
|
|
119
|
+
});
|
|
120
|
+
// The reported bug: editing a command template (or the app-vs-CLI wording of a
|
|
121
|
+
// built-in) made the body match fail, so reopening the session rendered the
|
|
122
|
+
// whole raw template instead of the `/name` chip.
|
|
123
|
+
it("uses the persisted invocation when the template has drifted since", () => {
|
|
124
|
+
const bodyFromOldTemplate = "# Release\n\nShip the thing the OLD way.";
|
|
125
|
+
// Body matching alone can no longer recognise it.
|
|
126
|
+
expect(detectPromptCommand(bodyFromOldTemplate, candidates)).toBeNull();
|
|
127
|
+
// The invocation recorded at send time still restores the chip.
|
|
128
|
+
expect(resolveRestoredCommand("/release", bodyFromOldTemplate, candidates)).toBe("/release");
|
|
129
|
+
});
|
|
130
|
+
it("prefers the persisted invocation over a body match, args included", () => {
|
|
131
|
+
expect(resolveRestoredCommand("/release patch only", "# Release\n\nShip the thing.", candidates)).toBe("/release patch only");
|
|
132
|
+
});
|
|
133
|
+
it("ignores a blank persisted invocation and falls back to the body", () => {
|
|
134
|
+
expect(resolveRestoredCommand(" ", "# Commit\n\nWrite a commit.", candidates)).toBe("/commit");
|
|
135
|
+
});
|
|
136
|
+
});
|
|
88
137
|
describe("restoreAssistantTexts", () => {
|
|
89
138
|
it("keeps server-tool text splits as separate bubbles", () => {
|
|
90
139
|
expect(restoreAssistantTexts([
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-history.test.js","sourceRoot":"","sources":["../../src/core/session-history.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAM9C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EACL,mCAAmC,EACnC,6BAA6B,EAC7B,2BAA2B,EAC3B,cAAc,EACd,qBAAqB,
|
|
1
|
+
{"version":3,"file":"session-history.test.js","sourceRoot":"","sources":["../../src/core/session-history.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -70,6 +70,25 @@ export interface KenTurnPayload {
|
|
|
70
70
|
question: string;
|
|
71
71
|
reply: string;
|
|
72
72
|
afterMessageCount: number;
|
|
73
|
+
/** Read-only: branch messages that preceded this entry in FILE order. Never
|
|
74
|
+
* persisted — see {@link RecordedPosition}. */
|
|
75
|
+
recordedAfterMessageCount?: number;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Read-time position rescue for transcript markers.
|
|
79
|
+
*
|
|
80
|
+
* `afterMessageCount` is authoritative, but historical sessions were rewritten
|
|
81
|
+
* by compaction without rebasing it (markers were re-persisted carrying indices
|
|
82
|
+
* from the much longer pre-compaction transcript). Those anchors then replay far
|
|
83
|
+
* too late or past the end — the "everything bunched at the bottom" symptom.
|
|
84
|
+
*
|
|
85
|
+
* File order gives an independent, always-in-range estimate: the number of
|
|
86
|
+
* branch messages already written when the marker line was appended. It's only
|
|
87
|
+
* consulted when the stored anchor is out of range, so healthy sessions are
|
|
88
|
+
* untouched.
|
|
89
|
+
*/
|
|
90
|
+
export interface RecordedPosition {
|
|
91
|
+
recordedAfterMessageCount?: number;
|
|
73
92
|
}
|
|
74
93
|
/** Custom-entry kind for an autopilot verdict marker. Mirrors `ken_turn`:
|
|
75
94
|
* persisted as a `custom` entry with `parentId: null` so it's never on the
|
|
@@ -79,7 +98,7 @@ export interface KenTurnPayload {
|
|
|
79
98
|
* the exact same Ken bubble the live run showed — never the raw verdict
|
|
80
99
|
* keyword (e.g. `ALL_CLEAR`) the model actually replied with. */
|
|
81
100
|
export declare const AUTOPILOT_MARKER_CUSTOM_KIND = "autopilot_marker";
|
|
82
|
-
export interface AutopilotMarkerPayload {
|
|
101
|
+
export interface AutopilotMarkerPayload extends RecordedPosition {
|
|
83
102
|
version: 1;
|
|
84
103
|
phase: "prompted" | "done" | "human" | "capped" | "plan_approved";
|
|
85
104
|
reason?: string;
|
|
@@ -92,7 +111,7 @@ export interface AutopilotMarkerPayload {
|
|
|
92
111
|
* so the LLM never sees it, anchored by `afterMessageCount` so the host can
|
|
93
112
|
* interleave it back into the transcript on resume. */
|
|
94
113
|
export declare const APP_MARKER_CUSTOM_KIND = "app_transcript_marker";
|
|
95
|
-
export interface AppMarkerPayload {
|
|
114
|
+
export interface AppMarkerPayload extends RecordedPosition {
|
|
96
115
|
version: 1;
|
|
97
116
|
kind: "plan" | "task" | "error" | "user_hint" | "compaction" | "agent_handoff"
|
|
98
117
|
/** Mid-session model/provider change; `data` carries { from, to, provider }. */
|
|
@@ -206,17 +225,23 @@ export declare class SessionManager {
|
|
|
206
225
|
*/
|
|
207
226
|
getMessages(entries: SessionEntry[], leafId?: string | null): Message[];
|
|
208
227
|
getDisplayItems(entries: SessionEntry[], _leafId?: string | null): CompletedItem[];
|
|
228
|
+
/**
|
|
229
|
+
* Walk entries in file order, tracking how many branch (non-system) messages
|
|
230
|
+
* have been written so far, and hand each custom entry that count. This is
|
|
231
|
+
* the independent position estimate behind {@link RecordedPosition}.
|
|
232
|
+
*/
|
|
233
|
+
private mapCustomEntriesInFileOrder;
|
|
209
234
|
/** Read all persisted Ken turns in file order. Returns them regardless of
|
|
210
235
|
* branch (Ken turns are not chained into the DAG), validated + normalized. */
|
|
211
|
-
getKenTurns(entries: SessionEntry[]): KenTurnPayload[];
|
|
236
|
+
getKenTurns(entries: SessionEntry[], leafId?: string | null): KenTurnPayload[];
|
|
212
237
|
/** Read all persisted app transcript markers in file order, validated +
|
|
213
238
|
* normalized (same not-on-the-DAG treatment as Ken turns). */
|
|
214
|
-
getAppMarkers(entries: SessionEntry[]): AppMarkerPayload[];
|
|
239
|
+
getAppMarkers(entries: SessionEntry[], leafId?: string | null): AppMarkerPayload[];
|
|
215
240
|
/** Read validated per-turn usage and timing records in file order. */
|
|
216
241
|
getTurnMetrics(entries: SessionEntry[]): TurnMetricPayload[];
|
|
217
242
|
/** Read all persisted autopilot markers in file order, validated + normalized
|
|
218
243
|
* (same not-on-the-DAG treatment as Ken turns). */
|
|
219
|
-
getAutopilotMarkers(entries: SessionEntry[]): AutopilotMarkerPayload[];
|
|
244
|
+
getAutopilotMarkers(entries: SessionEntry[], leafId?: string | null): AutopilotMarkerPayload[];
|
|
220
245
|
/**
|
|
221
246
|
* Ensure every assistant message with tool_use blocks is followed by a tool
|
|
222
247
|
* message containing matching tool_result entries. Inserts synthetic
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/core/session-manager.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,OAAO,EACZ,KAAK,QAAQ,EACb,KAAK,KAAK,EACX,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAG3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAcL,KAAK,2BAA2B,EACjC,MAAM,sBAAsB,CAAC;AAI9B,UAAU,SAAS;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAa,SAAQ,SAAS;IAC7C,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,gBAAiB,SAAQ,SAAS;IACjD,IAAI,EAAE,cAAc,CAAC;IACrB,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,wBAAyB,SAAQ,SAAS;IACzD,IAAI,EAAE,uBAAuB,CAAC;IAC9B,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAgB,SAAQ,SAAS;IAChD,IAAI,EAAE,YAAY,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAW,SAAQ,SAAS;IAC3C,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAY,SAAQ,SAAS;IAC5C,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;CACf;AAED,eAAO,MAAM,wBAAwB,iBAAiB,CAAC;AACvD,eAAO,MAAM,uBAAuB,gBAAgB,CAAC;AAErD,MAAM,MAAM,cAAc,GACtB;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACrE;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE9C,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,CAAC,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,KAAK,CAAC;IACb,MAAM,EAAE,eAAe,CAAC;IACxB,IAAI,EAAE,cAAc,CAAC;CACtB;AAoDD;;;;;;;wEAOwE;AACxE,eAAO,MAAM,oBAAoB,aAAa,CAAC;AAE/C,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,CAAC,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/core/session-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -540,11 +540,36 @@ export class SessionManager {
|
|
|
540
540
|
return isCompletedItemLike(item) ? [item] : [];
|
|
541
541
|
});
|
|
542
542
|
}
|
|
543
|
+
/**
|
|
544
|
+
* Walk entries in file order, tracking how many branch (non-system) messages
|
|
545
|
+
* have been written so far, and hand each custom entry that count. This is
|
|
546
|
+
* the independent position estimate behind {@link RecordedPosition}.
|
|
547
|
+
*/
|
|
548
|
+
mapCustomEntriesInFileOrder(entries, leafId, project) {
|
|
549
|
+
// Only branch messages count — an off-branch fork's entries are not part of
|
|
550
|
+
// the restored transcript the anchors are measured against.
|
|
551
|
+
const onBranch = leafId
|
|
552
|
+
? new Set(this.getBranch(entries, leafId).map((e) => e.id))
|
|
553
|
+
: new Set(entries.map((e) => e.id));
|
|
554
|
+
const out = [];
|
|
555
|
+
let messagesSoFar = 0;
|
|
556
|
+
for (const entry of entries) {
|
|
557
|
+
if (entry.type === "message") {
|
|
558
|
+
if (onBranch.has(entry.id) && entry.message.role !== "system")
|
|
559
|
+
messagesSoFar++;
|
|
560
|
+
continue;
|
|
561
|
+
}
|
|
562
|
+
if (entry.type !== "custom")
|
|
563
|
+
continue;
|
|
564
|
+
out.push(...project(entry, messagesSoFar));
|
|
565
|
+
}
|
|
566
|
+
return out;
|
|
567
|
+
}
|
|
543
568
|
/** Read all persisted Ken turns in file order. Returns them regardless of
|
|
544
569
|
* branch (Ken turns are not chained into the DAG), validated + normalized. */
|
|
545
|
-
getKenTurns(entries) {
|
|
546
|
-
return
|
|
547
|
-
if (entry.
|
|
570
|
+
getKenTurns(entries, leafId) {
|
|
571
|
+
return this.mapCustomEntriesInFileOrder(entries, leafId, (entry, recordedAfterMessageCount) => {
|
|
572
|
+
if (entry.kind !== KEN_TURN_CUSTOM_KIND)
|
|
548
573
|
return [];
|
|
549
574
|
const p = entry.data;
|
|
550
575
|
if (p?.version === 1 && typeof p.question === "string" && typeof p.reply === "string") {
|
|
@@ -554,6 +579,7 @@ export class SessionManager {
|
|
|
554
579
|
question: p.question,
|
|
555
580
|
reply: p.reply,
|
|
556
581
|
afterMessageCount: typeof p.afterMessageCount === "number" ? p.afterMessageCount : 0,
|
|
582
|
+
recordedAfterMessageCount,
|
|
557
583
|
},
|
|
558
584
|
];
|
|
559
585
|
}
|
|
@@ -562,9 +588,9 @@ export class SessionManager {
|
|
|
562
588
|
}
|
|
563
589
|
/** Read all persisted app transcript markers in file order, validated +
|
|
564
590
|
* normalized (same not-on-the-DAG treatment as Ken turns). */
|
|
565
|
-
getAppMarkers(entries) {
|
|
566
|
-
return
|
|
567
|
-
if (entry.
|
|
591
|
+
getAppMarkers(entries, leafId) {
|
|
592
|
+
return this.mapCustomEntriesInFileOrder(entries, leafId, (entry, recordedAfterMessageCount) => {
|
|
593
|
+
if (entry.kind !== APP_MARKER_CUSTOM_KIND)
|
|
568
594
|
return [];
|
|
569
595
|
const p = entry.data;
|
|
570
596
|
const kind = p?.kind;
|
|
@@ -582,6 +608,7 @@ export class SessionManager {
|
|
|
582
608
|
kind,
|
|
583
609
|
afterMessageCount: typeof p.afterMessageCount === "number" ? p.afterMessageCount : 0,
|
|
584
610
|
data: typeof p.data === "object" && p.data !== null ? p.data : {},
|
|
611
|
+
recordedAfterMessageCount,
|
|
585
612
|
},
|
|
586
613
|
];
|
|
587
614
|
}
|
|
@@ -599,9 +626,9 @@ export class SessionManager {
|
|
|
599
626
|
}
|
|
600
627
|
/** Read all persisted autopilot markers in file order, validated + normalized
|
|
601
628
|
* (same not-on-the-DAG treatment as Ken turns). */
|
|
602
|
-
getAutopilotMarkers(entries) {
|
|
603
|
-
return
|
|
604
|
-
if (entry.
|
|
629
|
+
getAutopilotMarkers(entries, leafId) {
|
|
630
|
+
return this.mapCustomEntriesInFileOrder(entries, leafId, (entry, recordedAfterMessageCount) => {
|
|
631
|
+
if (entry.kind !== AUTOPILOT_MARKER_CUSTOM_KIND)
|
|
605
632
|
return [];
|
|
606
633
|
const p = entry.data;
|
|
607
634
|
const phase = p?.phase;
|
|
@@ -618,6 +645,7 @@ export class SessionManager {
|
|
|
618
645
|
...(typeof p.reason === "string" ? { reason: p.reason } : {}),
|
|
619
646
|
...(typeof p.body === "string" ? { body: p.body } : {}),
|
|
620
647
|
afterMessageCount: typeof p.afterMessageCount === "number" ? p.afterMessageCount : 0,
|
|
648
|
+
recordedAfterMessageCount,
|
|
621
649
|
},
|
|
622
650
|
];
|
|
623
651
|
}
|