antechamber 0.2.11 → 0.2.13
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 +16 -0
- package/dist/pi-event-translation.js +2 -0
- package/dist/session-store.js +2 -0
- package/dist/session-tree.d.ts +10 -1
- package/dist/session-tree.js +40 -4
- package/dist/sessions.js +17 -1
- package/extensions/omo-dag/package.json +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,22 @@ and this project uses [Semantic Versioning](https://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.13] - 2026-10-16
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Show and resume turns that another OmO client, such as the terminal, appended to a session while the connector
|
|
15
|
+
was detached. Previously the connector stayed pinned to its last saved message. A committed revert's abandoned
|
|
16
|
+
branch stays hidden.
|
|
17
|
+
|
|
18
|
+
## [0.2.12] - 2026-10-16
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- Preserve recorded conversation progress when the agent process exits before
|
|
23
|
+
`agent_end`, and retain successful background compaction across revival.
|
|
24
|
+
Checkpoints respect reverted selections and do not switch to sibling branches.
|
|
25
|
+
|
|
10
26
|
## [0.2.11] - 2026-10-16
|
|
11
27
|
|
|
12
28
|
### Fixed
|
|
@@ -544,6 +544,7 @@ export class PiEventTranslator {
|
|
|
544
544
|
},
|
|
545
545
|
});
|
|
546
546
|
if (ev.aborted !== true && typeof result?.summary === "string" && typeof result.firstKeptEntryId === "string") {
|
|
547
|
+
recordTurn(s);
|
|
547
548
|
const messages = this.services.ensureMessages(s);
|
|
548
549
|
let key;
|
|
549
550
|
// compaction_end follows persistence, but its result omits the entry ID.
|
|
@@ -563,6 +564,7 @@ export class PiEventTranslator {
|
|
|
563
564
|
for (const part of message.parts)
|
|
564
565
|
this.emitPart(s, part);
|
|
565
566
|
}
|
|
567
|
+
this.services.persistMeta(s);
|
|
566
568
|
}
|
|
567
569
|
this.services.emit(s.info.directory, { type: "session.updated", properties: { info: s.info } });
|
|
568
570
|
if (s.compactingFromIdle) {
|
package/dist/session-store.js
CHANGED
|
@@ -305,6 +305,8 @@ function sessionTreeState(value) {
|
|
|
305
305
|
return false;
|
|
306
306
|
if (value.leafId !== undefined && value.leafId !== null && typeof value.leafId !== "string")
|
|
307
307
|
return false;
|
|
308
|
+
if (value.fileSize !== undefined && (typeof value.fileSize !== "number" || !Number.isFinite(value.fileSize)))
|
|
309
|
+
return false;
|
|
308
310
|
if (value.revert !== undefined) {
|
|
309
311
|
if (!record(value.revert) ||
|
|
310
312
|
typeof value.revert.messageID !== "string" ||
|
package/dist/session-tree.d.ts
CHANGED
|
@@ -18,6 +18,8 @@ export interface SessionTreeState {
|
|
|
18
18
|
messages: [OCMessageWithParts, OCMessageWithParts];
|
|
19
19
|
}>;
|
|
20
20
|
leafId?: string | null;
|
|
21
|
+
/** Session file size when this connector last saved a live runtime; growth past it came from another client. */
|
|
22
|
+
fileSize?: number;
|
|
21
23
|
revert?: {
|
|
22
24
|
messageID: string;
|
|
23
25
|
previousLeafId: string | null;
|
|
@@ -52,8 +54,15 @@ export declare class SessionTreeError extends Error {
|
|
|
52
54
|
export declare function durableShellTree(tree: SessionTreeState): SessionTreeState;
|
|
53
55
|
export declare function getEntries(pi: PiRpcClient, signal?: AbortSignal): Promise<Entries>;
|
|
54
56
|
export declare function readSessionTree(piPath: string): Entries;
|
|
55
|
-
/**
|
|
57
|
+
/** Checkpoint persisted progress after agent_end, successful compaction, or process exit. */
|
|
56
58
|
export declare function recordTurn(s: ManagedSession): void;
|
|
59
|
+
/**
|
|
60
|
+
* Another OmO client (e.g. the terminal) resumes at the file tail and appends there.
|
|
61
|
+
* Follow that tail when it descends from the saved selection and was written after
|
|
62
|
+
* this connector last saved, so a committed revert's abandoned branch stays hidden.
|
|
63
|
+
* Registries saved before the size marker existed follow any descendant tail.
|
|
64
|
+
*/
|
|
65
|
+
export declare function followExternalAppends(s: ManagedSession, piPath: string): void;
|
|
57
66
|
export declare function branchEntries(tree: Entries, leafId?: string | null): TreeEntry[];
|
|
58
67
|
/** Live ids belong to the UI; restored ids belong to JSONL offsets. Save both. */
|
|
59
68
|
export declare function bindMessageEntries(s: ManagedSession, tree: Entries): void;
|
package/dist/session-tree.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RPC_COMMAND_TIMEOUT_MS } from "./pi-rpc.js";
|
|
2
|
-
import { readFileSync } from "node:fs";
|
|
2
|
+
import { readFileSync, statSync } from "node:fs";
|
|
3
3
|
import { contextMessageID, nativePromptInput } from "./prompt-parts.js";
|
|
4
4
|
export class SessionTreeError extends Error {
|
|
5
5
|
}
|
|
@@ -44,10 +44,46 @@ export function readSessionTree(piPath) {
|
|
|
44
44
|
}
|
|
45
45
|
return { entries, leafId: entries.at(-1)?.id ?? null };
|
|
46
46
|
}
|
|
47
|
-
/**
|
|
47
|
+
/** Checkpoint persisted progress after agent_end, successful compaction, or process exit. */
|
|
48
48
|
export function recordTurn(s) {
|
|
49
|
-
if (s.piPath)
|
|
50
|
-
|
|
49
|
+
if (!s.piPath)
|
|
50
|
+
return;
|
|
51
|
+
const tree = readSessionTree(s.piPath);
|
|
52
|
+
// Disk order is not navigation: only a descendant can advance a saved selection.
|
|
53
|
+
// An ancestor, missing selection, or newer sibling must leave its bindings intact.
|
|
54
|
+
if (!s.tree.revert &&
|
|
55
|
+
s.tree.leafId !== undefined &&
|
|
56
|
+
s.tree.leafId !== null &&
|
|
57
|
+
!branchEntries(tree).some((entry) => entry.id === s.tree.leafId))
|
|
58
|
+
return;
|
|
59
|
+
bindMessageEntries(s, tree);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Another OmO client (e.g. the terminal) resumes at the file tail and appends there.
|
|
63
|
+
* Follow that tail when it descends from the saved selection and was written after
|
|
64
|
+
* this connector last saved, so a committed revert's abandoned branch stays hidden.
|
|
65
|
+
* Registries saved before the size marker existed follow any descendant tail.
|
|
66
|
+
*/
|
|
67
|
+
export function followExternalAppends(s, piPath) {
|
|
68
|
+
const saved = s.tree.leafId;
|
|
69
|
+
if (s.tree.revert || saved === undefined || saved === null)
|
|
70
|
+
return;
|
|
71
|
+
const size = statSync(piPath, { throwIfNoEntry: false })?.size;
|
|
72
|
+
if (size === undefined || (s.tree.fileSize !== undefined && size <= s.tree.fileSize))
|
|
73
|
+
return;
|
|
74
|
+
let tree;
|
|
75
|
+
try {
|
|
76
|
+
tree = readSessionTree(piPath);
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
// History parsing skips malformed lines; keep the saved selection rather than guess a tail.
|
|
80
|
+
if (error instanceof SessionTreeError)
|
|
81
|
+
return;
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
if (tree.leafId === saved || !branchEntries(tree).some((entry) => entry.id === saved))
|
|
85
|
+
return;
|
|
86
|
+
s.tree.leafId = tree.leafId;
|
|
51
87
|
}
|
|
52
88
|
export function branchEntries(tree, leafId = tree.leafId) {
|
|
53
89
|
const byId = new Map(tree.entries.map((entry) => [entry.id, entry]));
|
package/dist/sessions.js
CHANGED
|
@@ -14,7 +14,7 @@ import { SessionLifecycle } from "./lifecycle.js";
|
|
|
14
14
|
import { ApprovalBridge, extensionUiRequestFrom } from "./approvals.js";
|
|
15
15
|
import { getAgentName, getExposedAgentNames } from "./agent-name.js";
|
|
16
16
|
import { RequestBodyError } from "./http.js";
|
|
17
|
-
import { bindMessageEntries, durableShellTree, forkConversation, getEntries, navigate, readSessionTree, revertConversation, SessionTreeError, unrevertConversation, } from "./session-tree.js";
|
|
17
|
+
import { bindMessageEntries, durableShellTree, followExternalAppends, forkConversation, getEntries, navigate, recordTurn, readSessionTree, revertConversation, SessionTreeError, unrevertConversation, } from "./session-tree.js";
|
|
18
18
|
import { SubagentBridge } from "./subagents.js";
|
|
19
19
|
import { MonitorSessions } from "./monitor-sessions.js";
|
|
20
20
|
import { sessionDiff } from "./session-diff.js";
|
|
@@ -239,6 +239,13 @@ export class SessionManager {
|
|
|
239
239
|
name: "UnknownError",
|
|
240
240
|
data: { message: `pi process exited (code=${code})` },
|
|
241
241
|
});
|
|
242
|
+
try {
|
|
243
|
+
recordTurn(s);
|
|
244
|
+
this.persistMeta(s);
|
|
245
|
+
}
|
|
246
|
+
catch (error) {
|
|
247
|
+
this.reportPersistenceError(s, error);
|
|
248
|
+
}
|
|
242
249
|
delete s.interruptRequested;
|
|
243
250
|
this.subagents.stopParent(s.info.id);
|
|
244
251
|
this.monitors.stopParent(s.info.id);
|
|
@@ -1160,6 +1167,9 @@ export class SessionManager {
|
|
|
1160
1167
|
if (this.monitors.owns(s.info.id))
|
|
1161
1168
|
return this.monitors.messages(s.info.id);
|
|
1162
1169
|
if (s.messages === undefined) {
|
|
1170
|
+
// A dormant session may have been continued by another OmO client since the last save.
|
|
1171
|
+
if (s.pi === undefined && s.restored !== undefined)
|
|
1172
|
+
followExternalAppends(s, s.restored.piPath);
|
|
1163
1173
|
const admissions = s.tree.localShellTurns?.length;
|
|
1164
1174
|
s.messages = parsePiSessionFile(s, getAgentName());
|
|
1165
1175
|
this.subagents.discover(s, s.messages);
|
|
@@ -1327,6 +1337,12 @@ export class SessionManager {
|
|
|
1327
1337
|
const piSessionId = s.piSessionId ?? s.restored?.piSessionId;
|
|
1328
1338
|
if (piPath === undefined || piSessionId === undefined)
|
|
1329
1339
|
return;
|
|
1340
|
+
// Only a live runtime vouches for the file contents; dormant saves keep the previous marker.
|
|
1341
|
+
if (s.pi !== undefined) {
|
|
1342
|
+
const size = statSync(piPath, { throwIfNoEntry: false })?.size;
|
|
1343
|
+
if (size !== undefined)
|
|
1344
|
+
s.tree.fileSize = size;
|
|
1345
|
+
}
|
|
1330
1346
|
this.store.set(s.info.id, {
|
|
1331
1347
|
...(this.createdSessions.has(piSessionId) ? { connectorOwned: true } : {}),
|
|
1332
1348
|
tree: durableShellTree(s.tree),
|