@spark-strategic/helix-core 0.2.4 → 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,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// ============================================================================
|
|
3
|
+
// GENERATED — DO NOT EDIT.
|
|
4
|
+
// Vendored from @spark-strategic/helix-chat (auxiliary/helix-chat/src/chat-store-context.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.configureChatStore = configureChatStore;
|
|
43
|
+
exports.getChatStoreContext = getChatStoreContext;
|
|
44
|
+
/**
|
|
45
|
+
* The dependency-injection seam for the durable chat store (`chat-store.ts`) and its
|
|
46
|
+
* §5.1 reconciler (`chat-reconcile.ts`).
|
|
47
|
+
*
|
|
48
|
+
* The store itself is pure Node (fs/path/crypto) and must stay that way so the SAME
|
|
49
|
+
* source can be vendored byte-for-byte into both consumers that ship standalone with
|
|
50
|
+
* plain `tsc`:
|
|
51
|
+
*
|
|
52
|
+
* - helix-os — the heavy node runtime. dataDir = `getConfig().dataDir`,
|
|
53
|
+
* logger = its winston `getLogger()`.
|
|
54
|
+
* - helix-core — the minimal personal-agent connector. dataDir = `~/.helix`,
|
|
55
|
+
* logger = the connector's console logger.
|
|
56
|
+
*
|
|
57
|
+
* Those are the ONLY two things the store ever needed from its host (the `getConfig().dataDir`
|
|
58
|
+
* read in `storeDir()` and the `getLogger()` call in the fail-soft `warn`/`markAcked`/reconcile
|
|
59
|
+
* paths). Rather than import a host module, the host calls {@link configureChatStore} once at
|
|
60
|
+
* boot to inject them. Both are resolved LAZILY (`resolveDataDir()` is called per operation,
|
|
61
|
+
* the logger methods delegate at call time), so configuration order never matters and a host
|
|
62
|
+
* whose config/logger is set up after this module is imported still works — the exact lazy
|
|
63
|
+
* behavior the original `getConfig()`/`getLogger()` calls had.
|
|
64
|
+
*
|
|
65
|
+
* Fail-soft to the last: if a host forgets to configure, the store does NOT throw (it is pure
|
|
66
|
+
* instrumentation and must never break a turn). It falls back to `~/.helix` and a console
|
|
67
|
+
* logger — a safe default that keeps a lone import runnable.
|
|
68
|
+
*/
|
|
69
|
+
const os = __importStar(require("os"));
|
|
70
|
+
const path = __importStar(require("path"));
|
|
71
|
+
/** The safe fallback used until (or if) a host configures: `~/.helix` + console. Keeps
|
|
72
|
+
* the store runnable on a bare import without ever throwing. */
|
|
73
|
+
const DEFAULT_CONTEXT = {
|
|
74
|
+
resolveDataDir: () => path.join(os.homedir(), '.helix'),
|
|
75
|
+
logger: {
|
|
76
|
+
debug: () => { },
|
|
77
|
+
info: () => { },
|
|
78
|
+
warn: (m, x) => console.warn(`[helix-chat] ${m}`, x ?? ''),
|
|
79
|
+
error: (m, x) => console.error(`[helix-chat] ${m}`, x ?? ''),
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
let _ctx = null;
|
|
83
|
+
/**
|
|
84
|
+
* Inject the host's data dir resolver + logger. Call once at boot. Idempotent — a later
|
|
85
|
+
* call simply replaces the context (useful for tests). Never throws.
|
|
86
|
+
*/
|
|
87
|
+
function configureChatStore(ctx) {
|
|
88
|
+
_ctx = ctx;
|
|
89
|
+
}
|
|
90
|
+
/** The active context, or the safe default if the host never configured. Never throws. */
|
|
91
|
+
function getChatStoreContext() {
|
|
92
|
+
return _ctx ?? DEFAULT_CONTEXT;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=chat-store-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-store-context.js","sourceRoot":"","sources":["../../src/chat/chat-store-context.ts"],"names":[],"mappings":";AAAA,+EAA+E;AAC/E,2BAA2B;AAC3B,gGAAgG;AAChG,iFAAiF;AACjF,8FAA8F;AAC9F,+EAA+E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoE/E,gDAEC;AAGD,kDAEC;AAzED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,uCAAyB;AACzB,2CAA6B;AAqB7B;iEACiE;AACjE,MAAM,eAAe,GAAqB;IACxC,cAAc,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC;IACvD,MAAM,EAAE;QACN,KAAK,EAAE,GAAG,EAAE,GAAE,CAAC;QACf,IAAI,EAAE,GAAG,EAAE,GAAE,CAAC;QACd,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC;QAC1D,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC;KAC7D;CACF,CAAC;AAEF,IAAI,IAAI,GAA4B,IAAI,CAAC;AAEzC;;;GAGG;AACH,SAAgB,kBAAkB,CAAC,GAAqB;IACtD,IAAI,GAAG,GAAG,CAAC;AACb,CAAC;AAED,0FAA0F;AAC1F,SAAgB,mBAAmB;IACjC,OAAO,IAAI,IAAI,eAAe,CAAC;AACjC,CAAC"}
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/** Schema version stamped on every record so the inspect command can reject drift. */
|
|
2
|
+
declare const SCHEMA: 1;
|
|
3
|
+
export type ToolState = 'started' | 'executed' | 'indeterminate';
|
|
4
|
+
export type TerminalReason = 'done' | 'error' | 'interrupted';
|
|
5
|
+
/**
|
|
6
|
+
* §5.1 crash-reconcile disposition — the policy outcome the resume-path reconciler
|
|
7
|
+
* assigns to a ledger gap (`started && !executed`) by the tool's declared effect class:
|
|
8
|
+
* - `resolved-safe` pure/read/idempotent-keyed — a re-run is free or collapses
|
|
9
|
+
* by key, so nothing is stranded; no human/agent attention.
|
|
10
|
+
* - `needs-verify` verifiable — the agent should query reality by the key on
|
|
11
|
+
* its next turn and re-run only if the effect didn't land.
|
|
12
|
+
* - `needs-agent-review` irreversible-unverifiable (the fail-closed default) — never
|
|
13
|
+
* auto-replayed; surfaces as an agent-facing reconcile task.
|
|
14
|
+
*/
|
|
15
|
+
export type ReconcileDisposition = 'resolved-safe' | 'needs-verify' | 'needs-agent-review';
|
|
16
|
+
export interface ToolLedgerEntry {
|
|
17
|
+
/** Stable per-turn display ordinal (for the §5.3 inspect command). */
|
|
18
|
+
ordinal: number;
|
|
19
|
+
/** §5.1 per-invocation key: the provider's `tool_use` id. The ledger dedupes on
|
|
20
|
+
* it (replay = same id = no second entry). Absent only on the full-assistant-
|
|
21
|
+
* message fallback path, which carries no streamed block id — those fall back to
|
|
22
|
+
* the name/oldest-started heuristic for result resolution. */
|
|
23
|
+
toolCallId?: string;
|
|
24
|
+
/** Display name of the tool. */
|
|
25
|
+
name: string;
|
|
26
|
+
/** §5.1 effect class, resolved from the tool at call time (fail-closed default
|
|
27
|
+
* `irreversible-unverifiable` for anything undeclared/undeterminable). */
|
|
28
|
+
effectClass: string;
|
|
29
|
+
startedAt: string;
|
|
30
|
+
executedAt?: string;
|
|
31
|
+
ok?: boolean;
|
|
32
|
+
state: ToolState;
|
|
33
|
+
/** §5.1 crash-reconcile verdict, written by the resume-path reconciler when it
|
|
34
|
+
* visits this entry's gap. Absent until a reconcile pass runs; an `executed`
|
|
35
|
+
* entry never gets one (no gap to reconcile). */
|
|
36
|
+
reconcile?: {
|
|
37
|
+
disposition: ReconcileDisposition;
|
|
38
|
+
/** The effect class the reconciler applied policy to (the recorded class today;
|
|
39
|
+
* a refined class once record-time resolution is broadened). */
|
|
40
|
+
effectClass: string;
|
|
41
|
+
at: string;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Sender classification for the §5.3 inspector — the firewall verdict (agents-api,
|
|
46
|
+
* resolved server-side) reduced to the one label that answers "who is this message
|
|
47
|
+
* from, and how do I trust them?":
|
|
48
|
+
* - `internal` a recognized Helix colleague (mapped to a real User, `known`).
|
|
49
|
+
* - `external-verified` an EXTERNAL visitor the embedding site cryptographically
|
|
50
|
+
* vouched for (widget HMAC) — not a colleague, but identified
|
|
51
|
+
* and trusted to act on their own behalf.
|
|
52
|
+
* - `anonymous` an unidentified public-widget visitor.
|
|
53
|
+
* - `unknown` no identity resolved / an unrecognized sender the agent must
|
|
54
|
+
* not assume an identity for (and the absent-user fallback).
|
|
55
|
+
*/
|
|
56
|
+
export type IdentityClass = 'internal' | 'external-verified' | 'anonymous' | 'unknown';
|
|
57
|
+
/** The firewall-resolved sender flags this store records (mirrors `AgentChatTurn.user`). */
|
|
58
|
+
interface IdentityFlags {
|
|
59
|
+
id?: string;
|
|
60
|
+
email?: string;
|
|
61
|
+
name?: string;
|
|
62
|
+
known?: boolean;
|
|
63
|
+
anonymous?: boolean;
|
|
64
|
+
verified?: boolean;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Reduce the firewall's sender flags to one class. Precedence matches the firewall's
|
|
68
|
+
* own semantics: a recognized colleague (`known`) wins; else an HMAC-vouched external
|
|
69
|
+
* visitor (`verified`); else an anonymous public visitor; else unknown (the fail-closed
|
|
70
|
+
* default an undecidable/absent sender collapses to — the agent assumes no identity).
|
|
71
|
+
*/
|
|
72
|
+
export declare function classifyIdentity(user?: IdentityFlags): IdentityClass;
|
|
73
|
+
/**
|
|
74
|
+
* Sender attribution recorded on the turn (§5.3). Answers who the message is from, their
|
|
75
|
+
* email, whether they're internal/external, and — for an external sender — whether the
|
|
76
|
+
* embedding site cryptographically verified them (HMAC). Derived once at turn open from
|
|
77
|
+
* the firewall-resolved `AgentChatTurn.user`/`org`; the raw flags are kept alongside the
|
|
78
|
+
* reduced `class` so the inspector can show both the verdict and what drove it.
|
|
79
|
+
*/
|
|
80
|
+
export interface TurnIdentity {
|
|
81
|
+
/** The reduced sender classification (`classifyIdentity`). */
|
|
82
|
+
class: IdentityClass;
|
|
83
|
+
userId?: string;
|
|
84
|
+
email?: string;
|
|
85
|
+
name?: string;
|
|
86
|
+
/** The org the agent serves this turn (customer org display name), for context. */
|
|
87
|
+
org?: string;
|
|
88
|
+
/** Raw firewall flags (what drove `class`). */
|
|
89
|
+
known?: boolean;
|
|
90
|
+
anonymous?: boolean;
|
|
91
|
+
verified?: boolean;
|
|
92
|
+
}
|
|
93
|
+
export interface ChatTurnRecord {
|
|
94
|
+
schema: typeof SCHEMA;
|
|
95
|
+
turnId: string;
|
|
96
|
+
sessionId: string;
|
|
97
|
+
agentId?: string;
|
|
98
|
+
/** §1.1 origination attribute (no bearing on lifecycle; recorded for context). */
|
|
99
|
+
createdBy: 'human' | 'agent';
|
|
100
|
+
/** §5.3 sender attribution — who this message is from and how they're trusted,
|
|
101
|
+
* from the firewall verdict. Absent only on turns opened without a resolved user
|
|
102
|
+
* (older records / non-attributed paths); the inspector reads it as `unknown`. */
|
|
103
|
+
identity?: TurnIdentity;
|
|
104
|
+
model?: string;
|
|
105
|
+
openedAt: string;
|
|
106
|
+
/** Renews on every committed stream frame — the §3.1 backstop's "last progress". */
|
|
107
|
+
lastProgressAt: string;
|
|
108
|
+
closedAt?: string;
|
|
109
|
+
terminalReason?: TerminalReason;
|
|
110
|
+
/** §5.1 reconcile-pass marker: set once the resume-path reconciler has visited this
|
|
111
|
+
* turn and applied policy to its ledger gaps. Keeps the pass idempotent — a turn is
|
|
112
|
+
* reconciled exactly once (`listTurnsNeedingReconcile` excludes anything stamped). */
|
|
113
|
+
reconciledAt?: string;
|
|
114
|
+
/** §5.1 residual-surfacing marker: set once this turn's unresolved residual
|
|
115
|
+
* (`needs-verify`/`needs-agent-review` gaps) has been handed to the agent as a
|
|
116
|
+
* reconcile task on a later turn (`takeReconcileResidualForSession`). Keeps the
|
|
117
|
+
* hand-off single-shot — the residual surfaces to the agent exactly once, then the
|
|
118
|
+
* agent owns it (verify / ask the user / let it drop); it never re-nags turn after
|
|
119
|
+
* turn. The durable disposition on each entry stays readable in the inspector
|
|
120
|
+
* regardless. Absent until a turn with residual is surfaced. */
|
|
121
|
+
reconcileSurfacedAt?: string;
|
|
122
|
+
/** Provider continuation handle, if the turn emitted one (resume anchor). */
|
|
123
|
+
providerRef?: string;
|
|
124
|
+
/** Stream buffer coordinates (§5.3). */
|
|
125
|
+
stream: {
|
|
126
|
+
lastStreamSeq: number;
|
|
127
|
+
byteCount: number;
|
|
128
|
+
complete: boolean;
|
|
129
|
+
};
|
|
130
|
+
/** Tool-call ledger (§5.3). */
|
|
131
|
+
tools: ToolLedgerEntry[];
|
|
132
|
+
/** Final-write state (§5.3). `acked` flips when agents-api confirms the final
|
|
133
|
+
* message is durably in the DB transcript (§3.2 ack); `evicted` flips with it
|
|
134
|
+
* (the node-local durable copy is then redundant and its content is dropped). */
|
|
135
|
+
final: {
|
|
136
|
+
written: boolean;
|
|
137
|
+
acked: boolean;
|
|
138
|
+
evicted: boolean;
|
|
139
|
+
/** When the server ack landed (the final write was confirmed durable). */
|
|
140
|
+
ackedAt?: string;
|
|
141
|
+
};
|
|
142
|
+
/** Settled attribution from the terminal `done` frame. */
|
|
143
|
+
usage?: unknown;
|
|
144
|
+
costUsd?: number | null;
|
|
145
|
+
durationMs?: number;
|
|
146
|
+
errorMessage?: string;
|
|
147
|
+
/** The accumulated agent content — the literal answer to "did it have everything?" */
|
|
148
|
+
content: string;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* A live handle wrapping one turn's record. `streamChatTurn` drives it through the
|
|
152
|
+
* turn; every method is fail-soft so instrumentation can never break the turn.
|
|
153
|
+
*/
|
|
154
|
+
export declare class TurnRecordHandle {
|
|
155
|
+
private rec;
|
|
156
|
+
private timer;
|
|
157
|
+
private dirty;
|
|
158
|
+
private closed;
|
|
159
|
+
constructor(seed: {
|
|
160
|
+
sessionId: string;
|
|
161
|
+
agentId?: string;
|
|
162
|
+
createdBy?: 'human' | 'agent';
|
|
163
|
+
model?: string;
|
|
164
|
+
user?: IdentityFlags;
|
|
165
|
+
org?: string;
|
|
166
|
+
});
|
|
167
|
+
get turnId(): string;
|
|
168
|
+
/** A committed stream frame (a `chat_delta` leaving the node). Renews progress,
|
|
169
|
+
* advances `streamSeq`, accumulates content. Disk flush is debounced. */
|
|
170
|
+
commitFrame(text: string): void;
|
|
171
|
+
/** Provider continuation handle learned mid-turn (resume anchor). */
|
|
172
|
+
markRef(providerRef: string): void;
|
|
173
|
+
/** Ledger: a tool call STARTED (written before the result — side-effect ordering,
|
|
174
|
+
* §5.1). Flushed immediately so the `started && !executed` gap survives a crash.
|
|
175
|
+
* Keyed by `toolCallId` (the provider `tool_use` id): a replay of the SAME
|
|
176
|
+
* invocation (same id) dedupes and does NOT open a second entry, while two
|
|
177
|
+
* distinct ids both record. `effectClass` is what the tool declared, resolved
|
|
178
|
+
* fail-closed by the caller. */
|
|
179
|
+
toolStarted(name: string, opts?: {
|
|
180
|
+
toolCallId?: string;
|
|
181
|
+
effectClass?: string;
|
|
182
|
+
}): void;
|
|
183
|
+
/** Ledger: a tool call returned. Resolves the entry by `toolCallId` when the
|
|
184
|
+
* result carries one (§5.1 — the exact invocation its call opened); otherwise
|
|
185
|
+
* falls back to the oldest unresolved same-named call, then the oldest unresolved
|
|
186
|
+
* call (the full-assistant-message path that carries no block id). */
|
|
187
|
+
toolExecuted(name: string, ok: boolean, opts?: {
|
|
188
|
+
toolCallId?: string;
|
|
189
|
+
}): void;
|
|
190
|
+
/** Terminal success: the final full-message write landed (§3.2). `complete` flips
|
|
191
|
+
* true; `acked`/`evicted` await the §3.2 browser ack path (not wired here). */
|
|
192
|
+
markDone(settle: {
|
|
193
|
+
usage?: unknown;
|
|
194
|
+
costUsd?: number | null;
|
|
195
|
+
durationMs?: number;
|
|
196
|
+
providerRef?: string;
|
|
197
|
+
}): void;
|
|
198
|
+
/** Terminal failure frame. */
|
|
199
|
+
markError(message: string): void;
|
|
200
|
+
/** Seal a turn that reached no terminal frame (abort/transport drop/crash of the
|
|
201
|
+
* stream loop). Any still-`started` tool call becomes `indeterminate` — the §5.1
|
|
202
|
+
* fail-closed residual. No-op if the turn already closed via done/error. */
|
|
203
|
+
seal(): void;
|
|
204
|
+
private close;
|
|
205
|
+
private scheduleFlush;
|
|
206
|
+
private flushNow;
|
|
207
|
+
private warn;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Open a record for a new turn. Sweeps expired records first (cheap, bounded) so
|
|
211
|
+
* disk stays capped until the §3.2 ack-eviction path lands. Fail-soft: on any
|
|
212
|
+
* error returns a no-op-ish handle that still drives the turn without persisting.
|
|
213
|
+
*/
|
|
214
|
+
export declare function openTurnRecord(seed: {
|
|
215
|
+
sessionId: string;
|
|
216
|
+
agentId?: string;
|
|
217
|
+
createdBy?: 'human' | 'agent';
|
|
218
|
+
model?: string;
|
|
219
|
+
/** Firewall-resolved sender identity (§5.3 attribution), classified at open. */
|
|
220
|
+
user?: IdentityFlags;
|
|
221
|
+
/** Org the agent serves this turn (customer org display name). */
|
|
222
|
+
org?: string;
|
|
223
|
+
}): TurnRecordHandle;
|
|
224
|
+
/** Read every persisted record (newest first). Read-only — for the §5.3 command. */
|
|
225
|
+
export declare function listTurnRecords(): ChatTurnRecord[];
|
|
226
|
+
/** Read one record by turnId. */
|
|
227
|
+
export declare function readTurnRecord(turnId: string): ChatTurnRecord | null;
|
|
228
|
+
/**
|
|
229
|
+
* §3.2 final-write ack. Called when agents-api confirms — via a `chat_ack` frame —
|
|
230
|
+
* that this turn's final message is DURABLY in the DB transcript. That ack is the
|
|
231
|
+
* authoritative close: it is the one signal that proves the node's local copy is now
|
|
232
|
+
* redundant, so we evict the content (the durability purpose of the store is served)
|
|
233
|
+
* while keeping a tombstone so the §5.3 inspect command can still confirm "acked +
|
|
234
|
+
* evicted". Reads off disk (the live `TurnRecordHandle` is long gone by the time the
|
|
235
|
+
* ack returns) and rewrites tmp+rename. Fail-soft and IDEMPOTENT: a duplicate ack (or
|
|
236
|
+
* one for an unknown/already-evicted turn) is a no-op. Returns true iff it flipped a
|
|
237
|
+
* record. Never throws — a store error must never break the node.
|
|
238
|
+
*/
|
|
239
|
+
export declare function markAcked(turnId: string): boolean;
|
|
240
|
+
/** Every record for a session, newest first. */
|
|
241
|
+
export declare function recordsForSession(sessionId: string): ChatTurnRecord[];
|
|
242
|
+
/** A ledger entry is a §5.1 reconcile GAP when it started but never resolved to a
|
|
243
|
+
* result — `started` (a hard crash before `seal` ran) or `indeterminate` (sealed).
|
|
244
|
+
* An `executed` entry has no gap. */
|
|
245
|
+
export declare function isReconcileGap(entry: ToolLedgerEntry): boolean;
|
|
246
|
+
/** Turns the resume-path reconciler still owes a pass: at least one ledger gap and
|
|
247
|
+
* not yet stamped `reconciledAt`. Read-only. The reconciler runs at boot, when every
|
|
248
|
+
* on-disk record predates this process, so a gap here is a prior life's interrupted
|
|
249
|
+
* turn — never a turn live in THIS process. Newest-first (inherits listTurnRecords). */
|
|
250
|
+
export declare function listTurnsNeedingReconcile(): ChatTurnRecord[];
|
|
251
|
+
/** One per-entry reconcile verdict the reconciler hands back to be written durably. */
|
|
252
|
+
export interface ToolReconcileOutcome {
|
|
253
|
+
/** Identifies the entry: by `toolCallId` when present, else by stable `ordinal`. */
|
|
254
|
+
ordinal: number;
|
|
255
|
+
toolCallId?: string;
|
|
256
|
+
disposition: ReconcileDisposition;
|
|
257
|
+
effectClass: string;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* §5.1 reconcile write-back. The resume-path reconciler applies the policy table to a
|
|
261
|
+
* turn's ledger gaps (`chat-reconcile.ts`) and calls this to record the verdict durably:
|
|
262
|
+
* each outcome stamps its entry's `reconcile`, and the turn is stamped `reconciledAt` so
|
|
263
|
+
* the pass is IDEMPOTENT — a turn is reconciled exactly once (a second call, or one for
|
|
264
|
+
* an already-reconciled/unknown turn, is a no-op returning false). Reads off disk and
|
|
265
|
+
* rewrites tmp+rename (the live handle is long gone by boot). Fail-soft: a store error
|
|
266
|
+
* never throws — an unwritten verdict just leaves the turn for the next boot's pass.
|
|
267
|
+
* Returns true iff it stamped the record.
|
|
268
|
+
*/
|
|
269
|
+
export declare function reconcileTurnRecord(turnId: string, outcomes: ToolReconcileOutcome[]): boolean;
|
|
270
|
+
/** One unresolved residual gap handed to the agent as a reconcile task (§5.1 residual
|
|
271
|
+
* handling). Carries the human-readable coordinates the agent needs to resolve it
|
|
272
|
+
* itself (verify by key) or to ask the user in its own natural language — never a raw
|
|
273
|
+
* `rerun tool_abc123?`. `disposition` is always a non-`resolved-safe` verdict (a safe
|
|
274
|
+
* re-run strands nothing, so it is never surfaced). */
|
|
275
|
+
export interface ReconcileResidualItem {
|
|
276
|
+
/** The interrupted turn this gap belongs to (the §5.1 `(turnId, toolCallId)` key). */
|
|
277
|
+
turnId: string;
|
|
278
|
+
/** Display name of the tool whose outcome is unknown. */
|
|
279
|
+
tool: string;
|
|
280
|
+
/** `needs-verify` (verifiable — check reality by key, re-run only if absent) or
|
|
281
|
+
* `needs-agent-review` (irreversible/undeclared — never auto-replay; ask the user). */
|
|
282
|
+
disposition: ReconcileDisposition;
|
|
283
|
+
effectClass: string;
|
|
284
|
+
/** The per-invocation key — binds any eventual re-run to the SAME original call so it
|
|
285
|
+
* re-enters the normal consent gate rather than a privileged rerun fast-path. */
|
|
286
|
+
toolCallId?: string;
|
|
287
|
+
/** When the owning turn was sealed (so the agent can phrase "earlier" / "a moment ago"). */
|
|
288
|
+
interruptedAt?: string;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* §5.1 residual hand-off. Take this session's unresolved reconcile residual — the
|
|
292
|
+
* `needs-verify` / `needs-agent-review` gaps a prior interrupted turn left and the
|
|
293
|
+
* boot reconciler has already classified — so the NEXT turn can surface them to the
|
|
294
|
+
* agent as a reconcile task (spec §5.1: "surfaces first as an agent-facing reconcile
|
|
295
|
+
* task," the agent then resolves it itself or asks the user in natural language).
|
|
296
|
+
*
|
|
297
|
+
* SINGLE-SHOT by design: each contributing turn is stamped `reconcileSurfacedAt` as it
|
|
298
|
+
* is taken, so the residual is handed to the agent exactly once and never re-nags every
|
|
299
|
+
* subsequent turn. The durable per-entry disposition is untouched — the §5.3 inspector
|
|
300
|
+
* still reads it regardless of whether it was surfaced. Fail-soft: any read/write error
|
|
301
|
+
* yields the empty set (a missed hand-off leaves the residual visible in the inspector
|
|
302
|
+
* and node log — never silently re-run, the safe direction).
|
|
303
|
+
*
|
|
304
|
+
* Only `resolved-safe` gaps are filtered out (a free/keyed re-run strands nothing);
|
|
305
|
+
* everything else is the agent's to resolve. Returns newest-turn-first.
|
|
306
|
+
*/
|
|
307
|
+
export declare function takeReconcileResidualForSession(sessionId: string): ReconcileResidualItem[];
|
|
308
|
+
/** Prune CLOSED records older than RETENTION_MS, and any closed overflow past
|
|
309
|
+
* MAX_RECORDS (oldest first). Live/unclosed records are never pruned — a stall
|
|
310
|
+
* must stay inspectable. */
|
|
311
|
+
export declare function sweepExpired(now?: number): number;
|
|
312
|
+
export {};
|
|
313
|
+
//# sourceMappingURL=chat-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-store.d.ts","sourceRoot":"","sources":["../../src/chat/chat-store.ts"],"names":[],"mappings":"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"}
|