@spark-strategic/helix-core 0.2.3 → 0.2.5
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/__tests__/connector-chat-durability.test.d.ts +17 -0
- package/dist/__tests__/connector-chat-durability.test.d.ts.map +1 -0
- package/dist/__tests__/connector-chat-durability.test.js +259 -0
- package/dist/__tests__/connector-chat-durability.test.js.map +1 -0
- package/dist/chat/chat-reconcile.d.ts +44 -0
- package/dist/chat/chat-reconcile.d.ts.map +1 -0
- package/dist/chat/chat-reconcile.js +175 -0
- package/dist/chat/chat-reconcile.js.map +1 -0
- package/dist/chat/chat-store-context.d.ts +25 -0
- package/dist/chat/chat-store-context.d.ts.map +1 -0
- package/dist/chat/chat-store-context.js +94 -0
- package/dist/chat/chat-store-context.js.map +1 -0
- package/dist/chat/chat-store.d.ts +313 -0
- package/dist/chat/chat-store.d.ts.map +1 -0
- package/dist/chat/chat-store.js +638 -0
- package/dist/chat/chat-store.js.map +1 -0
- package/dist/connector.d.ts +9 -0
- package/dist/connector.d.ts.map +1 -1
- package/dist/connector.js +87 -3
- package/dist/connector.js.map +1 -1
- package/dist/protocol.d.ts +1 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +4 -0
- package/dist/protocol.js.map +1 -1
- package/package.json +5 -3
|
@@ -0,0 +1,638 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ============================================================================
|
|
3
|
+
// GENERATED — DO NOT EDIT.
|
|
4
|
+
// Vendored from @spark-strategic/helix-chat (auxiliary/helix-chat/src/chat-store.ts) by
|
|
5
|
+
// helix-core/scripts/vendor-helix-chat.js at build time. Edit the canonical file
|
|
6
|
+
// in @spark-strategic/helix-chat and rebuild; changes made directly here will be overwritten.
|
|
7
|
+
// ============================================================================
|
|
8
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
|
+
if (k2 === undefined) k2 = k;
|
|
10
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
11
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
12
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(o, k2, desc);
|
|
15
|
+
}) : (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
o[k2] = m[k];
|
|
18
|
+
}));
|
|
19
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
20
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
21
|
+
}) : function(o, v) {
|
|
22
|
+
o["default"] = v;
|
|
23
|
+
});
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.TurnRecordHandle = void 0;
|
|
43
|
+
exports.classifyIdentity = classifyIdentity;
|
|
44
|
+
exports.openTurnRecord = openTurnRecord;
|
|
45
|
+
exports.listTurnRecords = listTurnRecords;
|
|
46
|
+
exports.readTurnRecord = readTurnRecord;
|
|
47
|
+
exports.markAcked = markAcked;
|
|
48
|
+
exports.recordsForSession = recordsForSession;
|
|
49
|
+
exports.isReconcileGap = isReconcileGap;
|
|
50
|
+
exports.listTurnsNeedingReconcile = listTurnsNeedingReconcile;
|
|
51
|
+
exports.reconcileTurnRecord = reconcileTurnRecord;
|
|
52
|
+
exports.takeReconcileResidualForSession = takeReconcileResidualForSession;
|
|
53
|
+
exports.sweepExpired = sweepExpired;
|
|
54
|
+
/**
|
|
55
|
+
* Node-side chat turn store (spec §3.3 "store ownership" + §5.3 "local store inspection").
|
|
56
|
+
*
|
|
57
|
+
* The agent message's durable local store is owned NODE-SIDE — the runtime that
|
|
58
|
+
* produced the stream — not the browser. This module is that store: a per-turn
|
|
59
|
+
* record, file-backed under `dataDir`, written as the turn's events flow through
|
|
60
|
+
* `streamChatTurn` (the single choke point every chat frame passes). It records
|
|
61
|
+
* exactly the three coordinates §5.3 needs to localize a stall in one glance:
|
|
62
|
+
*
|
|
63
|
+
* - Sender identity: who the message is from (firewall verdict) — internal colleague /
|
|
64
|
+
* external HMAC-verified / anonymous / unknown, with email + org (§5.3 attribution).
|
|
65
|
+
* - Stream buffer: last streamSeq, byte count, `complete` flag, the content.
|
|
66
|
+
* - Tool-call ledger: started/executed/indeterminate per call, with effect class.
|
|
67
|
+
* - Final-write state: whether the final message is written, acked, and evicted.
|
|
68
|
+
*
|
|
69
|
+
* It answers the question the whole lifecycle spec is built to answer —
|
|
70
|
+
* "did the agent have everything and fail to send, or did the stream stop early?"
|
|
71
|
+
* — WITHOUT any watchdog. It is pure instrumentation: it records, it never
|
|
72
|
+
* mutates turn behavior, and every operation is fail-soft (a store error must
|
|
73
|
+
* never break a live turn — the standing principle, §0).
|
|
74
|
+
*
|
|
75
|
+
* §5.1 tool-call idempotency ledger (now wired): each entry is keyed by the
|
|
76
|
+
* provider's `tool_use` id (`toolCallId`), so a replay of the SAME invocation
|
|
77
|
+
* dedupes (same id → no second entry) while two genuinely distinct calls (two
|
|
78
|
+
* ids) both record. The declared effect class (from the tool itself, resolved
|
|
79
|
+
* fail-closed — see `effectClassForBaseTool`) is recorded at call time so the
|
|
80
|
+
* crash-reconcile path can apply policy by class. A `started && !executed` entry
|
|
81
|
+
* sealed by an interrupted turn becomes `indeterminate` — the fail-closed residual.
|
|
82
|
+
*
|
|
83
|
+
* §3.2 final-write ack (now wired): agents-api sends a `chat_ack` frame ONLY after
|
|
84
|
+
* the terminal `chat_done` has been confirmed durably written to the DB transcript
|
|
85
|
+
* — that ack is the authoritative close. On receipt `markAcked` flips `acked`/`evicted`
|
|
86
|
+
* and drops the heavy `content` (the node-local durable copy is redundant once the
|
|
87
|
+
* server owns it), keeping a tiny tombstone the inspect command can still read. A turn
|
|
88
|
+
* whose ack never lands keeps its full record and is pruned by the TTL sweep below —
|
|
89
|
+
* the §3.1 "evicted at the 15-min backstop, an accepted terminal state" path.
|
|
90
|
+
*
|
|
91
|
+
* §5.1 crash reconcile (now wired): the resume-path reconciler (`chat-reconcile.ts`,
|
|
92
|
+
* run on node boot) READS this sealed ledger and applies the §5.1 policy table by
|
|
93
|
+
* effect class — pure/read/idempotent-keyed re-run freely (`resolved-safe`), verifiable
|
|
94
|
+
* verifies-by-key then maybe re-runs (`needs-verify`), and the fail-closed default
|
|
95
|
+
* (`irreversible-unverifiable`, every undeclared tool) is NEVER auto-replayed and
|
|
96
|
+
* surfaces as an agent-facing reconcile task (`needs-agent-review`). This store records
|
|
97
|
+
* the coordinates; the reconciler is the actor and writes its verdict back here via
|
|
98
|
+
* `reconcileTurnRecord`, where `markReconciled`/`listTurnsNeedingReconcile` keep the
|
|
99
|
+
* pass idempotent (a turn is visited once) and the §5.3 inspect command can read the
|
|
100
|
+
* disposition per entry.
|
|
101
|
+
*
|
|
102
|
+
* Concurrency: the node is a single JS process. Each handle owns its own state and
|
|
103
|
+
* a single-flight debounce timer; persistence is tmp+rename so a crash mid-write
|
|
104
|
+
* can't leave a half-written record.
|
|
105
|
+
*
|
|
106
|
+
* Host coupling: the data dir + logger are the only two things the store needs from
|
|
107
|
+
* its host; both are injected via `./chat-store-context` (`configureChatStore`) so the
|
|
108
|
+
* SAME source vendors into both helix-os and helix-core. See that module's header.
|
|
109
|
+
*/
|
|
110
|
+
const fs = __importStar(require("fs"));
|
|
111
|
+
const path = __importStar(require("path"));
|
|
112
|
+
const crypto = __importStar(require("crypto"));
|
|
113
|
+
const chat_store_context_1 = require("./chat-store-context");
|
|
114
|
+
/** Schema version stamped on every record so the inspect command can reject drift. */
|
|
115
|
+
const SCHEMA = 1;
|
|
116
|
+
/** Coalesce stream-buffer disk flushes to this cadence (mirrors the persistence
|
|
117
|
+
* layer's STREAM_FLUSH_MS). Terminal + tool-ledger writes bypass it and flush now. */
|
|
118
|
+
const STREAM_FLUSH_MS = 750;
|
|
119
|
+
/** Prune CLOSED records older than this on open (disk stays bounded until the
|
|
120
|
+
* §3.2 ack-eviction path lands). Live/unclosed records are never swept. */
|
|
121
|
+
const RETENTION_MS = 24 * 60 * 60 * 1000;
|
|
122
|
+
/** Hard cap on retained records; oldest closed ones beyond it are pruned on open. */
|
|
123
|
+
const MAX_RECORDS = 500;
|
|
124
|
+
/** §5.1 fail-closed default: an undeclared/undeterminable tool is never auto-replayed. */
|
|
125
|
+
const FAIL_CLOSED_EFFECT_CLASS = 'irreversible-unverifiable';
|
|
126
|
+
/**
|
|
127
|
+
* Reduce the firewall's sender flags to one class. Precedence matches the firewall's
|
|
128
|
+
* own semantics: a recognized colleague (`known`) wins; else an HMAC-vouched external
|
|
129
|
+
* visitor (`verified`); else an anonymous public visitor; else unknown (the fail-closed
|
|
130
|
+
* default an undecidable/absent sender collapses to — the agent assumes no identity).
|
|
131
|
+
*/
|
|
132
|
+
function classifyIdentity(user) {
|
|
133
|
+
if (!user)
|
|
134
|
+
return 'unknown';
|
|
135
|
+
if (user.known)
|
|
136
|
+
return 'internal';
|
|
137
|
+
if (user.verified)
|
|
138
|
+
return 'external-verified';
|
|
139
|
+
if (user.anonymous)
|
|
140
|
+
return 'anonymous';
|
|
141
|
+
return 'unknown';
|
|
142
|
+
}
|
|
143
|
+
/** Build the recorded identity from the firewall-resolved sender flags + org. Returns
|
|
144
|
+
* undefined only when there is literally nothing to attribute (no user and no org), so
|
|
145
|
+
* the inspector can distinguish "never attributed" from an explicit `unknown` sender. */
|
|
146
|
+
function buildIdentity(user, org) {
|
|
147
|
+
if (!user && !org)
|
|
148
|
+
return undefined;
|
|
149
|
+
return {
|
|
150
|
+
class: classifyIdentity(user),
|
|
151
|
+
...(user?.id ? { userId: user.id } : {}),
|
|
152
|
+
...(user?.email ? { email: user.email } : {}),
|
|
153
|
+
...(user?.name ? { name: user.name } : {}),
|
|
154
|
+
...(org ? { org } : {}),
|
|
155
|
+
...(user?.known !== undefined ? { known: user.known } : {}),
|
|
156
|
+
...(user?.anonymous !== undefined ? { anonymous: user.anonymous } : {}),
|
|
157
|
+
...(user?.verified !== undefined ? { verified: user.verified } : {}),
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function storeDir() {
|
|
161
|
+
return path.join((0, chat_store_context_1.getChatStoreContext)().resolveDataDir(), 'chat-turns');
|
|
162
|
+
}
|
|
163
|
+
function recordPath(turnId) {
|
|
164
|
+
return path.join(storeDir(), `${turnId}.json`);
|
|
165
|
+
}
|
|
166
|
+
function mintTurnId() {
|
|
167
|
+
return `trn_${Date.now().toString(36)}_${crypto.randomBytes(4).toString('hex')}`;
|
|
168
|
+
}
|
|
169
|
+
function byteLen(s) {
|
|
170
|
+
return Buffer.byteLength(s, 'utf8');
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* A live handle wrapping one turn's record. `streamChatTurn` drives it through the
|
|
174
|
+
* turn; every method is fail-soft so instrumentation can never break the turn.
|
|
175
|
+
*/
|
|
176
|
+
class TurnRecordHandle {
|
|
177
|
+
rec;
|
|
178
|
+
timer = null;
|
|
179
|
+
dirty = false;
|
|
180
|
+
closed = false;
|
|
181
|
+
constructor(seed) {
|
|
182
|
+
const now = new Date().toISOString();
|
|
183
|
+
this.rec = {
|
|
184
|
+
schema: SCHEMA,
|
|
185
|
+
turnId: mintTurnId(),
|
|
186
|
+
sessionId: seed.sessionId,
|
|
187
|
+
agentId: seed.agentId,
|
|
188
|
+
createdBy: seed.createdBy ?? 'human',
|
|
189
|
+
identity: buildIdentity(seed.user, seed.org),
|
|
190
|
+
model: seed.model,
|
|
191
|
+
openedAt: now,
|
|
192
|
+
lastProgressAt: now,
|
|
193
|
+
stream: { lastStreamSeq: 0, byteCount: 0, complete: false },
|
|
194
|
+
tools: [],
|
|
195
|
+
final: { written: false, acked: false, evicted: false },
|
|
196
|
+
content: '',
|
|
197
|
+
};
|
|
198
|
+
// Create-on-open (§3 step 1): the row exists the moment the turn begins, so a
|
|
199
|
+
// turn that dies before its first token is still visible as a stall.
|
|
200
|
+
this.flushNow();
|
|
201
|
+
}
|
|
202
|
+
get turnId() {
|
|
203
|
+
return this.rec.turnId;
|
|
204
|
+
}
|
|
205
|
+
/** A committed stream frame (a `chat_delta` leaving the node). Renews progress,
|
|
206
|
+
* advances `streamSeq`, accumulates content. Disk flush is debounced. */
|
|
207
|
+
commitFrame(text) {
|
|
208
|
+
try {
|
|
209
|
+
if (this.closed || !text)
|
|
210
|
+
return;
|
|
211
|
+
this.rec.content += text;
|
|
212
|
+
this.rec.stream.lastStreamSeq += 1;
|
|
213
|
+
this.rec.stream.byteCount = byteLen(this.rec.content);
|
|
214
|
+
this.rec.lastProgressAt = new Date().toISOString();
|
|
215
|
+
this.scheduleFlush();
|
|
216
|
+
}
|
|
217
|
+
catch (err) {
|
|
218
|
+
this.warn('commitFrame', err);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/** Provider continuation handle learned mid-turn (resume anchor). */
|
|
222
|
+
markRef(providerRef) {
|
|
223
|
+
try {
|
|
224
|
+
this.rec.providerRef = providerRef;
|
|
225
|
+
this.scheduleFlush();
|
|
226
|
+
}
|
|
227
|
+
catch (err) {
|
|
228
|
+
this.warn('markRef', err);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/** Ledger: a tool call STARTED (written before the result — side-effect ordering,
|
|
232
|
+
* §5.1). Flushed immediately so the `started && !executed` gap survives a crash.
|
|
233
|
+
* Keyed by `toolCallId` (the provider `tool_use` id): a replay of the SAME
|
|
234
|
+
* invocation (same id) dedupes and does NOT open a second entry, while two
|
|
235
|
+
* distinct ids both record. `effectClass` is what the tool declared, resolved
|
|
236
|
+
* fail-closed by the caller. */
|
|
237
|
+
toolStarted(name, opts) {
|
|
238
|
+
try {
|
|
239
|
+
const toolCallId = opts?.toolCallId;
|
|
240
|
+
// §5.1 dedupe: same invocation id already on the ledger ⇒ a replay, not a new
|
|
241
|
+
// call. Renew progress but never duplicate the entry.
|
|
242
|
+
if (toolCallId && this.rec.tools.some((t) => t.toolCallId === toolCallId)) {
|
|
243
|
+
this.rec.lastProgressAt = new Date().toISOString();
|
|
244
|
+
this.flushNow();
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
const ordinal = this.rec.tools.length + 1;
|
|
248
|
+
this.rec.tools.push({
|
|
249
|
+
ordinal,
|
|
250
|
+
...(toolCallId ? { toolCallId } : {}),
|
|
251
|
+
name,
|
|
252
|
+
effectClass: opts?.effectClass ?? FAIL_CLOSED_EFFECT_CLASS,
|
|
253
|
+
startedAt: new Date().toISOString(),
|
|
254
|
+
state: 'started',
|
|
255
|
+
});
|
|
256
|
+
this.rec.lastProgressAt = new Date().toISOString();
|
|
257
|
+
this.flushNow();
|
|
258
|
+
}
|
|
259
|
+
catch (err) {
|
|
260
|
+
this.warn('toolStarted', err);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
/** Ledger: a tool call returned. Resolves the entry by `toolCallId` when the
|
|
264
|
+
* result carries one (§5.1 — the exact invocation its call opened); otherwise
|
|
265
|
+
* falls back to the oldest unresolved same-named call, then the oldest unresolved
|
|
266
|
+
* call (the full-assistant-message path that carries no block id). */
|
|
267
|
+
toolExecuted(name, ok, opts) {
|
|
268
|
+
try {
|
|
269
|
+
const toolCallId = opts?.toolCallId;
|
|
270
|
+
const entry = (toolCallId ? this.rec.tools.find((t) => t.toolCallId === toolCallId) : undefined) ??
|
|
271
|
+
this.rec.tools.find((t) => t.state === 'started' && t.name === name) ??
|
|
272
|
+
this.rec.tools.find((t) => t.state === 'started');
|
|
273
|
+
if (entry) {
|
|
274
|
+
entry.state = 'executed';
|
|
275
|
+
entry.executedAt = new Date().toISOString();
|
|
276
|
+
entry.ok = ok;
|
|
277
|
+
}
|
|
278
|
+
this.rec.lastProgressAt = new Date().toISOString();
|
|
279
|
+
this.flushNow();
|
|
280
|
+
}
|
|
281
|
+
catch (err) {
|
|
282
|
+
this.warn('toolExecuted', err);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
/** Terminal success: the final full-message write landed (§3.2). `complete` flips
|
|
286
|
+
* true; `acked`/`evicted` await the §3.2 browser ack path (not wired here). */
|
|
287
|
+
markDone(settle) {
|
|
288
|
+
try {
|
|
289
|
+
this.rec.stream.complete = true;
|
|
290
|
+
this.rec.final.written = true;
|
|
291
|
+
this.rec.usage = settle.usage;
|
|
292
|
+
this.rec.costUsd = settle.costUsd ?? null;
|
|
293
|
+
this.rec.durationMs = settle.durationMs;
|
|
294
|
+
if (settle.providerRef)
|
|
295
|
+
this.rec.providerRef = settle.providerRef;
|
|
296
|
+
this.close('done');
|
|
297
|
+
}
|
|
298
|
+
catch (err) {
|
|
299
|
+
this.warn('markDone', err);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
/** Terminal failure frame. */
|
|
303
|
+
markError(message) {
|
|
304
|
+
try {
|
|
305
|
+
this.rec.errorMessage = message;
|
|
306
|
+
this.close('error');
|
|
307
|
+
}
|
|
308
|
+
catch (err) {
|
|
309
|
+
this.warn('markError', err);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
/** Seal a turn that reached no terminal frame (abort/transport drop/crash of the
|
|
313
|
+
* stream loop). Any still-`started` tool call becomes `indeterminate` — the §5.1
|
|
314
|
+
* fail-closed residual. No-op if the turn already closed via done/error. */
|
|
315
|
+
seal() {
|
|
316
|
+
try {
|
|
317
|
+
if (this.closed)
|
|
318
|
+
return;
|
|
319
|
+
for (const t of this.rec.tools) {
|
|
320
|
+
if (t.state === 'started')
|
|
321
|
+
t.state = 'indeterminate';
|
|
322
|
+
}
|
|
323
|
+
this.close('interrupted');
|
|
324
|
+
}
|
|
325
|
+
catch (err) {
|
|
326
|
+
this.warn('seal', err);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
close(reason) {
|
|
330
|
+
this.rec.terminalReason = reason;
|
|
331
|
+
this.rec.closedAt = new Date().toISOString();
|
|
332
|
+
this.closed = true;
|
|
333
|
+
if (this.timer) {
|
|
334
|
+
clearTimeout(this.timer);
|
|
335
|
+
this.timer = null;
|
|
336
|
+
}
|
|
337
|
+
this.flushNow();
|
|
338
|
+
}
|
|
339
|
+
scheduleFlush() {
|
|
340
|
+
this.dirty = true;
|
|
341
|
+
if (this.timer)
|
|
342
|
+
return;
|
|
343
|
+
this.timer = setTimeout(() => {
|
|
344
|
+
this.timer = null;
|
|
345
|
+
if (this.dirty)
|
|
346
|
+
this.flushNow();
|
|
347
|
+
}, STREAM_FLUSH_MS);
|
|
348
|
+
}
|
|
349
|
+
flushNow() {
|
|
350
|
+
this.dirty = false;
|
|
351
|
+
try {
|
|
352
|
+
const p = recordPath(this.rec.turnId);
|
|
353
|
+
const tmp = `${p}.tmp`;
|
|
354
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
355
|
+
fs.writeFileSync(tmp, JSON.stringify(this.rec, null, 2), { mode: 0o600 });
|
|
356
|
+
fs.renameSync(tmp, p);
|
|
357
|
+
}
|
|
358
|
+
catch (err) {
|
|
359
|
+
this.warn('flush', err);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
warn(op, err) {
|
|
363
|
+
try {
|
|
364
|
+
(0, chat_store_context_1.getChatStoreContext)().logger.debug('chat-store: op failed (ignored — instrumentation is fail-soft)', {
|
|
365
|
+
op,
|
|
366
|
+
turnId: this.rec?.turnId,
|
|
367
|
+
error: String(err),
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
catch {
|
|
371
|
+
/* never let logging break a turn */
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
exports.TurnRecordHandle = TurnRecordHandle;
|
|
376
|
+
/**
|
|
377
|
+
* Open a record for a new turn. Sweeps expired records first (cheap, bounded) so
|
|
378
|
+
* disk stays capped until the §3.2 ack-eviction path lands. Fail-soft: on any
|
|
379
|
+
* error returns a no-op-ish handle that still drives the turn without persisting.
|
|
380
|
+
*/
|
|
381
|
+
function openTurnRecord(seed) {
|
|
382
|
+
try {
|
|
383
|
+
sweepExpired();
|
|
384
|
+
}
|
|
385
|
+
catch {
|
|
386
|
+
/* sweep is best-effort */
|
|
387
|
+
}
|
|
388
|
+
return new TurnRecordHandle(seed);
|
|
389
|
+
}
|
|
390
|
+
/** Read every persisted record (newest first). Read-only — for the §5.3 command. */
|
|
391
|
+
function listTurnRecords() {
|
|
392
|
+
const dir = storeDir();
|
|
393
|
+
let files;
|
|
394
|
+
try {
|
|
395
|
+
files = fs.readdirSync(dir).filter((f) => f.endsWith('.json'));
|
|
396
|
+
}
|
|
397
|
+
catch {
|
|
398
|
+
return [];
|
|
399
|
+
}
|
|
400
|
+
const out = [];
|
|
401
|
+
for (const f of files) {
|
|
402
|
+
const rec = safeRead(path.join(dir, f));
|
|
403
|
+
if (rec)
|
|
404
|
+
out.push(rec);
|
|
405
|
+
}
|
|
406
|
+
out.sort((a, b) => (a.openedAt < b.openedAt ? 1 : -1));
|
|
407
|
+
return out;
|
|
408
|
+
}
|
|
409
|
+
/** Read one record by turnId. */
|
|
410
|
+
function readTurnRecord(turnId) {
|
|
411
|
+
return safeRead(recordPath(turnId));
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* §3.2 final-write ack. Called when agents-api confirms — via a `chat_ack` frame —
|
|
415
|
+
* that this turn's final message is DURABLY in the DB transcript. That ack is the
|
|
416
|
+
* authoritative close: it is the one signal that proves the node's local copy is now
|
|
417
|
+
* redundant, so we evict the content (the durability purpose of the store is served)
|
|
418
|
+
* while keeping a tombstone so the §5.3 inspect command can still confirm "acked +
|
|
419
|
+
* evicted". Reads off disk (the live `TurnRecordHandle` is long gone by the time the
|
|
420
|
+
* ack returns) and rewrites tmp+rename. Fail-soft and IDEMPOTENT: a duplicate ack (or
|
|
421
|
+
* one for an unknown/already-evicted turn) is a no-op. Returns true iff it flipped a
|
|
422
|
+
* record. Never throws — a store error must never break the node.
|
|
423
|
+
*/
|
|
424
|
+
function markAcked(turnId) {
|
|
425
|
+
try {
|
|
426
|
+
if (!turnId)
|
|
427
|
+
return false;
|
|
428
|
+
const p = recordPath(turnId);
|
|
429
|
+
const rec = safeRead(p);
|
|
430
|
+
if (!rec)
|
|
431
|
+
return false; // unknown turn (never recorded, or already swept)
|
|
432
|
+
if (rec.final.acked)
|
|
433
|
+
return false; // idempotent: already acked
|
|
434
|
+
rec.final.acked = true;
|
|
435
|
+
rec.final.evicted = true;
|
|
436
|
+
rec.final.ackedAt = new Date().toISOString();
|
|
437
|
+
// Evict the heavy durable copy now that the server owns it; the byteCount stays
|
|
438
|
+
// as the pre-eviction size so the tombstone still reads as "had N bytes, acked".
|
|
439
|
+
rec.content = '';
|
|
440
|
+
const tmp = `${p}.tmp`;
|
|
441
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
442
|
+
fs.writeFileSync(tmp, JSON.stringify(rec, null, 2), { mode: 0o600 });
|
|
443
|
+
fs.renameSync(tmp, p);
|
|
444
|
+
try {
|
|
445
|
+
(0, chat_store_context_1.getChatStoreContext)().logger.debug('chat-store: turn acked + evicted (final write durable server-side)', {
|
|
446
|
+
turnId, sessionId: rec.sessionId,
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
catch { /* logging must never break the ack */ }
|
|
450
|
+
return true;
|
|
451
|
+
}
|
|
452
|
+
catch {
|
|
453
|
+
return false; // fail-soft — an ack write failure just leaves the record for TTL sweep
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
/** Every record for a session, newest first. */
|
|
457
|
+
function recordsForSession(sessionId) {
|
|
458
|
+
return listTurnRecords().filter((r) => r.sessionId === sessionId);
|
|
459
|
+
}
|
|
460
|
+
/** A ledger entry is a §5.1 reconcile GAP when it started but never resolved to a
|
|
461
|
+
* result — `started` (a hard crash before `seal` ran) or `indeterminate` (sealed).
|
|
462
|
+
* An `executed` entry has no gap. */
|
|
463
|
+
function isReconcileGap(entry) {
|
|
464
|
+
return entry.state === 'started' || entry.state === 'indeterminate';
|
|
465
|
+
}
|
|
466
|
+
/** Turns the resume-path reconciler still owes a pass: at least one ledger gap and
|
|
467
|
+
* not yet stamped `reconciledAt`. Read-only. The reconciler runs at boot, when every
|
|
468
|
+
* on-disk record predates this process, so a gap here is a prior life's interrupted
|
|
469
|
+
* turn — never a turn live in THIS process. Newest-first (inherits listTurnRecords). */
|
|
470
|
+
function listTurnsNeedingReconcile() {
|
|
471
|
+
return listTurnRecords().filter((r) => !r.reconciledAt && r.tools.some(isReconcileGap));
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* §5.1 reconcile write-back. The resume-path reconciler applies the policy table to a
|
|
475
|
+
* turn's ledger gaps (`chat-reconcile.ts`) and calls this to record the verdict durably:
|
|
476
|
+
* each outcome stamps its entry's `reconcile`, and the turn is stamped `reconciledAt` so
|
|
477
|
+
* the pass is IDEMPOTENT — a turn is reconciled exactly once (a second call, or one for
|
|
478
|
+
* an already-reconciled/unknown turn, is a no-op returning false). Reads off disk and
|
|
479
|
+
* rewrites tmp+rename (the live handle is long gone by boot). Fail-soft: a store error
|
|
480
|
+
* never throws — an unwritten verdict just leaves the turn for the next boot's pass.
|
|
481
|
+
* Returns true iff it stamped the record.
|
|
482
|
+
*/
|
|
483
|
+
function reconcileTurnRecord(turnId, outcomes) {
|
|
484
|
+
try {
|
|
485
|
+
if (!turnId)
|
|
486
|
+
return false;
|
|
487
|
+
const p = recordPath(turnId);
|
|
488
|
+
const rec = safeRead(p);
|
|
489
|
+
if (!rec)
|
|
490
|
+
return false; // unknown turn (never recorded, or already swept)
|
|
491
|
+
if (rec.reconciledAt)
|
|
492
|
+
return false; // idempotent: already reconciled
|
|
493
|
+
const at = new Date().toISOString();
|
|
494
|
+
for (const o of outcomes) {
|
|
495
|
+
const entry = (o.toolCallId ? rec.tools.find((t) => t.toolCallId === o.toolCallId) : undefined) ??
|
|
496
|
+
rec.tools.find((t) => t.ordinal === o.ordinal);
|
|
497
|
+
if (!entry)
|
|
498
|
+
continue;
|
|
499
|
+
entry.reconcile = { disposition: o.disposition, effectClass: o.effectClass, at };
|
|
500
|
+
}
|
|
501
|
+
rec.reconciledAt = at;
|
|
502
|
+
const tmp = `${p}.tmp`;
|
|
503
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
504
|
+
fs.writeFileSync(tmp, JSON.stringify(rec, null, 2), { mode: 0o600 });
|
|
505
|
+
fs.renameSync(tmp, p);
|
|
506
|
+
return true;
|
|
507
|
+
}
|
|
508
|
+
catch {
|
|
509
|
+
return false; // fail-soft — leave the turn for the next boot's reconcile pass
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* §5.1 residual hand-off. Take this session's unresolved reconcile residual — the
|
|
514
|
+
* `needs-verify` / `needs-agent-review` gaps a prior interrupted turn left and the
|
|
515
|
+
* boot reconciler has already classified — so the NEXT turn can surface them to the
|
|
516
|
+
* agent as a reconcile task (spec §5.1: "surfaces first as an agent-facing reconcile
|
|
517
|
+
* task," the agent then resolves it itself or asks the user in natural language).
|
|
518
|
+
*
|
|
519
|
+
* SINGLE-SHOT by design: each contributing turn is stamped `reconcileSurfacedAt` as it
|
|
520
|
+
* is taken, so the residual is handed to the agent exactly once and never re-nags every
|
|
521
|
+
* subsequent turn. The durable per-entry disposition is untouched — the §5.3 inspector
|
|
522
|
+
* still reads it regardless of whether it was surfaced. Fail-soft: any read/write error
|
|
523
|
+
* yields the empty set (a missed hand-off leaves the residual visible in the inspector
|
|
524
|
+
* and node log — never silently re-run, the safe direction).
|
|
525
|
+
*
|
|
526
|
+
* Only `resolved-safe` gaps are filtered out (a free/keyed re-run strands nothing);
|
|
527
|
+
* everything else is the agent's to resolve. Returns newest-turn-first.
|
|
528
|
+
*/
|
|
529
|
+
function takeReconcileResidualForSession(sessionId) {
|
|
530
|
+
const out = [];
|
|
531
|
+
if (!sessionId)
|
|
532
|
+
return out;
|
|
533
|
+
let records;
|
|
534
|
+
try {
|
|
535
|
+
records = recordsForSession(sessionId);
|
|
536
|
+
}
|
|
537
|
+
catch {
|
|
538
|
+
return out; // fail-soft — no hand-off, residual stays visible in the inspector
|
|
539
|
+
}
|
|
540
|
+
for (const rec of records) {
|
|
541
|
+
try {
|
|
542
|
+
// Only reconciled turns carry verdicts; skip anything already surfaced.
|
|
543
|
+
if (!rec.reconciledAt || rec.reconcileSurfacedAt)
|
|
544
|
+
continue;
|
|
545
|
+
const residual = rec.tools.filter((t) => t.reconcile && t.reconcile.disposition !== 'resolved-safe');
|
|
546
|
+
if (residual.length === 0)
|
|
547
|
+
continue;
|
|
548
|
+
// Stamp surfaced FIRST (durably) so a crash mid-hand-off can't re-surface it; a
|
|
549
|
+
// lost surfacing is the safe failure (residual stays inspectable, never re-run).
|
|
550
|
+
if (!stampSurfaced(rec.turnId))
|
|
551
|
+
continue; // racing take / write failure → leave it
|
|
552
|
+
for (const t of residual) {
|
|
553
|
+
out.push({
|
|
554
|
+
turnId: rec.turnId,
|
|
555
|
+
tool: t.name,
|
|
556
|
+
disposition: t.reconcile.disposition,
|
|
557
|
+
effectClass: t.reconcile.effectClass,
|
|
558
|
+
...(t.toolCallId ? { toolCallId: t.toolCallId } : {}),
|
|
559
|
+
...(rec.closedAt ? { interruptedAt: rec.closedAt } : {}),
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
catch {
|
|
564
|
+
/* per-turn fail-soft — skip this turn, keep the rest */
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
return out;
|
|
568
|
+
}
|
|
569
|
+
/** Durably stamp a turn `reconcileSurfacedAt` (tmp+rename). Idempotent: a turn already
|
|
570
|
+
* stamped (or unknown/swept) returns false and is left alone. Fail-soft — never throws. */
|
|
571
|
+
function stampSurfaced(turnId) {
|
|
572
|
+
try {
|
|
573
|
+
const p = recordPath(turnId);
|
|
574
|
+
const rec = safeRead(p);
|
|
575
|
+
if (!rec)
|
|
576
|
+
return false; // unknown / already swept
|
|
577
|
+
if (rec.reconcileSurfacedAt)
|
|
578
|
+
return false; // already surfaced (a racing take)
|
|
579
|
+
rec.reconcileSurfacedAt = new Date().toISOString();
|
|
580
|
+
const tmp = `${p}.tmp`;
|
|
581
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
582
|
+
fs.writeFileSync(tmp, JSON.stringify(rec, null, 2), { mode: 0o600 });
|
|
583
|
+
fs.renameSync(tmp, p);
|
|
584
|
+
return true;
|
|
585
|
+
}
|
|
586
|
+
catch {
|
|
587
|
+
return false;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
/** Prune CLOSED records older than RETENTION_MS, and any closed overflow past
|
|
591
|
+
* MAX_RECORDS (oldest first). Live/unclosed records are never pruned — a stall
|
|
592
|
+
* must stay inspectable. */
|
|
593
|
+
function sweepExpired(now = Date.now()) {
|
|
594
|
+
const all = listTurnRecords();
|
|
595
|
+
const toDelete = [];
|
|
596
|
+
const closedByAge = [];
|
|
597
|
+
for (const r of all) {
|
|
598
|
+
const isClosed = !!r.closedAt;
|
|
599
|
+
if (isClosed) {
|
|
600
|
+
closedByAge.push(r);
|
|
601
|
+
const age = now - new Date(r.closedAt).getTime();
|
|
602
|
+
if (age > RETENTION_MS)
|
|
603
|
+
toDelete.push(r.turnId);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
// Overflow: keep the newest MAX_RECORDS closed records, prune the rest.
|
|
607
|
+
if (closedByAge.length > MAX_RECORDS) {
|
|
608
|
+
closedByAge
|
|
609
|
+
.slice() // newest-first already (listTurnRecords sort)
|
|
610
|
+
.sort((a, b) => (a.closedAt < b.closedAt ? 1 : -1))
|
|
611
|
+
.slice(MAX_RECORDS)
|
|
612
|
+
.forEach((r) => toDelete.push(r.turnId));
|
|
613
|
+
}
|
|
614
|
+
let pruned = 0;
|
|
615
|
+
for (const turnId of new Set(toDelete)) {
|
|
616
|
+
try {
|
|
617
|
+
fs.unlinkSync(recordPath(turnId));
|
|
618
|
+
pruned++;
|
|
619
|
+
}
|
|
620
|
+
catch {
|
|
621
|
+
/* already gone */
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
return pruned;
|
|
625
|
+
}
|
|
626
|
+
function safeRead(p) {
|
|
627
|
+
try {
|
|
628
|
+
const raw = fs.readFileSync(p, 'utf8');
|
|
629
|
+
const parsed = JSON.parse(raw);
|
|
630
|
+
if (!parsed || parsed.schema !== SCHEMA || !parsed.turnId)
|
|
631
|
+
return null;
|
|
632
|
+
return parsed;
|
|
633
|
+
}
|
|
634
|
+
catch {
|
|
635
|
+
return null;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
//# sourceMappingURL=chat-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-store.js","sourceRoot":"","sources":["../../src/chat/chat-store.ts"],"names":[],"mappings":"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"}
|