@adjudicate/adapter-core 0.1.0 → 0.1.1

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/loop.js ADDED
@@ -0,0 +1,422 @@
1
+ /**
2
+ * `createAdjudicatedAgent` — the provider-neutral message-loop orchestrator.
3
+ *
4
+ * Wires the planner, renderer, provider bridge, kernel, and Decision
5
+ * translator into a single send/resume/confirm surface.
6
+ *
7
+ * Invariants the loop preserves:
8
+ * - `pack.planner.plan(state, context)` is called every iteration. State
9
+ * may change mid-turn (a refund executes, freeing a previously-locked
10
+ * tool); the visible-tool surface MUST update accordingly.
11
+ * - The Pack passed in MUST already be `safePlan` + `withBasisAudit`
12
+ * wrapped (Pack-author convention). The loop does NOT double-wrap.
13
+ * - Every intent envelope crosses `adjudicateAndAudit()` from
14
+ * `@adjudicate/core/kernel`. The loop never bypasses the kernel,
15
+ * never raises taint, and never short-circuits the guard ordering.
16
+ * - First non-continue Decision wins: subsequent tool_use blocks in the
17
+ * same assistant turn are surfaced as `not_processed_due_to_pause`.
18
+ * - History `H` is opaque. The bridge is the only thing that knows the
19
+ * conversation-history shape; the loop threads it.
20
+ */
21
+ import { noopAuditSink, sha256Canonical, } from "@adjudicate/core";
22
+ import { adjudicateAndAudit } from "@adjudicate/core/kernel";
23
+ import { resumeDeferredIntent } from "@adjudicate/runtime";
24
+ import { buildEnvelopeFromToolUse, classifyIncomingToolUse, } from "./bridge.js";
25
+ import { makeOutOfPlanToolResult, translateDecision, } from "./decisions.js";
26
+ import { AdapterError, AdapterErrorCode } from "./errors.js";
27
+ import { noopTraceSink } from "./trace.js";
28
+ const DEFAULT_MAX_ITERATIONS = 8;
29
+ export function createAdjudicatedAgent(options) {
30
+ const maxIterations = options.maxIterations ?? DEFAULT_MAX_ITERATIONS;
31
+ const rk = options.rk ?? ((raw) => raw);
32
+ const deriveNonce = options.deriveNonce ?? ((args) => args.toolUseId);
33
+ const bridge = options.bridge;
34
+ const traceSink = options.traceSink ?? noopTraceSink;
35
+ function pauseActionToReason(kind) {
36
+ switch (kind) {
37
+ case "pause_for_defer":
38
+ return "deferred";
39
+ case "pause_for_user_confirmation":
40
+ return "awaiting_confirmation";
41
+ case "complete_for_escalation":
42
+ return "escalated";
43
+ default:
44
+ return undefined;
45
+ }
46
+ }
47
+ async function runLoop(sessionId, initialHistory, state, context, seedEvents,
48
+ /**
49
+ * Optional pre-seeded Decision injected before the first provider
50
+ * call — used by `confirm()` and `resume()` to splice an authoritative
51
+ * Decision (from the user's confirmation or the resumed envelope) back
52
+ * into the conversation without consulting the LLM again first.
53
+ */
54
+ seedDecision) {
55
+ const events = [...seedEvents];
56
+ let history = initialHistory;
57
+ let lastDecision = null;
58
+ if (seedDecision !== null) {
59
+ const single = await processSingleDecision({
60
+ decision: seedDecision.decision,
61
+ envelope: seedDecision.envelope,
62
+ toolUseId: seedDecision.toolUseId,
63
+ sessionId,
64
+ state,
65
+ historySnapshot: history,
66
+ });
67
+ lastDecision = seedDecision.decision;
68
+ events.push(...single.events);
69
+ if (single.toolResult !== null) {
70
+ history = bridge.appendToolResults(history, [single.toolResult]);
71
+ }
72
+ if (single.loopAction.kind !== "continue") {
73
+ return {
74
+ events,
75
+ history,
76
+ outcome: pauseToOutcome(single.loopAction, lastDecision),
77
+ };
78
+ }
79
+ }
80
+ for (let iter = 0; iter < maxIterations; iter++) {
81
+ traceSink.onTrace({
82
+ phase: "iteration_start",
83
+ sessionId,
84
+ iteration: iter + 1,
85
+ });
86
+ const plan = options.pack.planner.plan(state, context);
87
+ const rendered = options.renderer.render(state, context, plan);
88
+ const sent = await bridge.send(history, {
89
+ systemPrompt: rendered.systemPrompt,
90
+ maxTokens: rendered.maxTokens,
91
+ toolSchemas: rendered.toolSchemas,
92
+ });
93
+ history = sent.history;
94
+ for (const text of sent.turn.textBlocks) {
95
+ events.push({ kind: "assistant_text", text });
96
+ }
97
+ if (sent.turn.toolUses.length === 0) {
98
+ traceSink.onTrace({
99
+ phase: "completed",
100
+ sessionId,
101
+ iteration: iter + 1,
102
+ });
103
+ return {
104
+ events,
105
+ history,
106
+ outcome: {
107
+ kind: "completed",
108
+ assistantText: sent.turn.textBlocks.join(""),
109
+ },
110
+ };
111
+ }
112
+ const toolResults = [];
113
+ let pauseAction = null;
114
+ for (const tu of sent.turn.toolUses) {
115
+ events.push({
116
+ kind: "tool_use",
117
+ toolUseId: tu.id,
118
+ toolName: tu.name,
119
+ input: tu.input,
120
+ });
121
+ if (pauseAction !== null) {
122
+ // First non-continue Decision wins: surface remaining tool_uses
123
+ // as not-processed so the LLM (on resume) understands they were
124
+ // skipped this turn.
125
+ toolResults.push({
126
+ toolUseId: tu.id,
127
+ content: "Not processed: prior tool_use paused this turn.",
128
+ isError: true,
129
+ });
130
+ continue;
131
+ }
132
+ const cls = classifyIncomingToolUse({ name: tu.name, input: tu.input }, plan);
133
+ if (cls.kind === "out_of_plan") {
134
+ const result = makeOutOfPlanToolResult(tu.id, tu.name);
135
+ toolResults.push(result);
136
+ events.push({ kind: "tool_result", toolUseId: tu.id, payload: result });
137
+ continue;
138
+ }
139
+ if (cls.kind === "read") {
140
+ let readResult;
141
+ try {
142
+ readResult = await options.executor.invokeRead(cls.name, cls.input, state);
143
+ }
144
+ catch (err) {
145
+ const message = err instanceof Error ? err.message : "executor read failed";
146
+ const errResult = {
147
+ toolUseId: tu.id,
148
+ content: `Tool failed: ${message}`,
149
+ isError: true,
150
+ };
151
+ toolResults.push(errResult);
152
+ events.push({
153
+ kind: "tool_result",
154
+ toolUseId: tu.id,
155
+ payload: errResult,
156
+ });
157
+ continue;
158
+ }
159
+ const result = {
160
+ toolUseId: tu.id,
161
+ content: JSON.stringify({ ok: true, result: readResult }),
162
+ };
163
+ toolResults.push(result);
164
+ events.push({
165
+ kind: "handler_result",
166
+ toolUseId: tu.id,
167
+ result: readResult,
168
+ });
169
+ events.push({ kind: "tool_result", toolUseId: tu.id, payload: result });
170
+ continue;
171
+ }
172
+ // cls.kind === "intent"
173
+ const envelope = buildEnvelopeFromToolUse({
174
+ intentKind: cls.intentKind,
175
+ payload: cls.payload,
176
+ sessionId,
177
+ taint: "UNTRUSTED",
178
+ nonce: deriveNonce({
179
+ sessionId,
180
+ toolUseId: tu.id,
181
+ payload: cls.payload,
182
+ }),
183
+ });
184
+ events.push({ kind: "intent_proposed", envelope });
185
+ const { decision } = await adjudicateAndAudit(envelope, state, options.pack.policy, {
186
+ sink: options.auditSink ?? noopAuditSink(),
187
+ ledger: options.ledger,
188
+ context: options.runtimeContext,
189
+ plan: () => ({
190
+ visibleReadTools: plan.visibleReadTools,
191
+ allowedIntents: plan.allowedIntents,
192
+ }),
193
+ });
194
+ lastDecision = decision;
195
+ events.push({ kind: "decision", decision, envelope });
196
+ traceSink.onTrace({
197
+ phase: "decision_emitted",
198
+ sessionId,
199
+ iteration: iter + 1,
200
+ decisionKind: decision.kind,
201
+ });
202
+ const single = await processSingleDecision({
203
+ decision,
204
+ envelope: envelope,
205
+ toolUseId: tu.id,
206
+ sessionId,
207
+ state,
208
+ historySnapshot: history,
209
+ });
210
+ events.push(...single.events);
211
+ if (single.toolResult)
212
+ toolResults.push(single.toolResult);
213
+ if (single.loopAction.kind !== "continue") {
214
+ pauseAction = single.loopAction;
215
+ }
216
+ }
217
+ if (toolResults.length > 0) {
218
+ history = bridge.appendToolResults(history, toolResults);
219
+ }
220
+ if (pauseAction !== null) {
221
+ const reason = pauseActionToReason(pauseAction.kind);
222
+ traceSink.onTrace({
223
+ phase: "paused",
224
+ sessionId,
225
+ iteration: iter + 1,
226
+ ...(reason !== undefined ? { pauseReason: reason } : {}),
227
+ ...(lastDecision !== null
228
+ ? { decisionKind: lastDecision.kind }
229
+ : {}),
230
+ });
231
+ return {
232
+ events,
233
+ history,
234
+ outcome: pauseToOutcome(pauseAction, lastDecision),
235
+ };
236
+ }
237
+ }
238
+ traceSink.onTrace({
239
+ phase: "max_iterations_exceeded",
240
+ sessionId,
241
+ iteration: maxIterations,
242
+ ...(lastDecision !== null ? { decisionKind: lastDecision.kind } : {}),
243
+ });
244
+ return {
245
+ events,
246
+ history,
247
+ outcome: { kind: "max_iterations_exceeded", lastDecision },
248
+ };
249
+ async function processSingleDecision(args) {
250
+ const t = await translateDecision({
251
+ decision: args.decision,
252
+ envelope: args.envelope,
253
+ toolUseId: args.toolUseId,
254
+ sessionId: args.sessionId,
255
+ state: args.state,
256
+ executor: options.executor,
257
+ deferStore: options.deferStore,
258
+ confirmationStore: options.confirmationStore,
259
+ historySnapshot: args.historySnapshot,
260
+ rk,
261
+ log: options.log,
262
+ generateToken: () => globalThis.crypto?.randomUUID?.() ??
263
+ `ct-${Math.random().toString(36).slice(2)}-${Date.now()}`,
264
+ });
265
+ return {
266
+ events: [...t.extraEvents],
267
+ toolResult: t.toolResult,
268
+ loopAction: t.loopAction,
269
+ };
270
+ }
271
+ }
272
+ return {
273
+ async send(input) {
274
+ const baseHistory = input.history ?? bridge.emptyHistory();
275
+ const initialHistory = bridge.appendUserMessage(baseHistory, input.userMessage);
276
+ const seedEvents = [
277
+ { kind: "user_message", text: input.userMessage },
278
+ ];
279
+ return runLoop(input.sessionId, initialHistory, input.state, input.context, seedEvents, null);
280
+ },
281
+ async resume(args) {
282
+ const result = await resumeDeferredIntent({
283
+ sessionId: args.sessionId,
284
+ signal: args.signal,
285
+ redis: options.deferStore,
286
+ rk,
287
+ log: options.log,
288
+ verifyHash: options.verifyParkedHash ?? "warn",
289
+ });
290
+ if (!result.resumed || !result.parked) {
291
+ throw new AdapterError(AdapterErrorCode.RESUME_NO_PARKED, `No parked envelope for session "${args.sessionId}" and signal "${args.signal}" (reason: ${result.reason ?? "unknown"})`, { sessionId: args.sessionId, signal: args.signal, reason: result.reason });
292
+ }
293
+ const envelope = {
294
+ version: 2,
295
+ kind: result.parked.envelope.kind,
296
+ payload: result.parked.envelope.payload,
297
+ createdAt: new Date().toISOString(),
298
+ nonce: result.parked.envelope.intentHash,
299
+ actor: {
300
+ principal: "system",
301
+ sessionId: result.parked.envelope.actor.sessionId,
302
+ },
303
+ taint: "TRUSTED",
304
+ intentHash: result.parked.envelope.intentHash,
305
+ };
306
+ const resumePlan = options.pack.planner.plan(args.state, args.context);
307
+ const { decision } = await adjudicateAndAudit(envelope, args.state, options.pack.policy, {
308
+ sink: options.auditSink ?? noopAuditSink(),
309
+ ledger: options.ledger,
310
+ context: options.runtimeContext,
311
+ plan: () => ({
312
+ visibleReadTools: resumePlan.visibleReadTools,
313
+ allowedIntents: resumePlan.allowedIntents,
314
+ }),
315
+ });
316
+ const seedEvents = [
317
+ { kind: "intent_proposed", envelope },
318
+ { kind: "decision", decision, envelope },
319
+ ];
320
+ const fauxToolUseId = `resume-${result.parked.envelope.intentHash.slice(0, 8)}`;
321
+ const seedDecision = {
322
+ decision,
323
+ envelope,
324
+ toolUseId: fauxToolUseId,
325
+ };
326
+ return runLoop(args.sessionId, args.history ?? bridge.emptyHistory(), args.state, args.context, seedEvents, seedDecision);
327
+ },
328
+ async confirm(args) {
329
+ const pending = await options.confirmationStore.take(args.confirmationToken);
330
+ if (pending === null) {
331
+ throw new AdapterError(AdapterErrorCode.CONFIRMATION_TOKEN_INVALID, `Confirmation token "${args.confirmationToken}" is unknown or expired.`, { confirmationToken: args.confirmationToken });
332
+ }
333
+ const verifyMode = options.verifyParkedHash ?? "warn";
334
+ if (verifyMode !== "off") {
335
+ const derived = sha256Canonical({
336
+ version: pending.envelope.version,
337
+ kind: pending.envelope.kind,
338
+ payload: pending.envelope.payload,
339
+ nonce: pending.envelope.nonce,
340
+ actor: pending.envelope.actor,
341
+ taint: pending.envelope.taint,
342
+ });
343
+ if (derived !== pending.envelope.intentHash) {
344
+ options.log?.warn?.({
345
+ sessionId: pending.sessionId,
346
+ stored: pending.envelope.intentHash,
347
+ derived,
348
+ confirmationToken: args.confirmationToken,
349
+ }, "[adjudicated-agent] confirmation blob tampered — refusing to resume");
350
+ throw new AdapterError(AdapterErrorCode.CONFIRMATION_TOKEN_INVALID, `Confirmation token "${args.confirmationToken}" failed hash verification (envelope was modified after persistence).`, {
351
+ confirmationToken: args.confirmationToken,
352
+ reason: "confirmation_blob_tampered",
353
+ });
354
+ }
355
+ }
356
+ if (!args.accepted) {
357
+ const declineEvent = {
358
+ kind: "assistant_text",
359
+ text: "User declined the confirmation. Action skipped.",
360
+ };
361
+ return {
362
+ events: [declineEvent],
363
+ history: pending.assistantHistorySnapshot,
364
+ outcome: {
365
+ kind: "completed",
366
+ assistantText: "User declined the confirmation. Action skipped.",
367
+ },
368
+ };
369
+ }
370
+ const envelope = pending.envelope;
371
+ const confirmPlan = options.pack.planner.plan(args.state, args.context);
372
+ const { decision } = await adjudicateAndAudit(envelope, args.state, options.pack.policy, {
373
+ sink: options.auditSink ?? noopAuditSink(),
374
+ ledger: options.ledger,
375
+ context: options.runtimeContext,
376
+ plan: () => ({
377
+ visibleReadTools: confirmPlan.visibleReadTools,
378
+ allowedIntents: confirmPlan.allowedIntents,
379
+ }),
380
+ confirmationReceipt: {
381
+ intentHash: envelope.intentHash,
382
+ at: new Date().toISOString(),
383
+ },
384
+ });
385
+ const seedEvents = [
386
+ { kind: "intent_proposed", envelope },
387
+ { kind: "decision", decision, envelope },
388
+ ];
389
+ const seedDecision = {
390
+ decision,
391
+ envelope,
392
+ toolUseId: pending.toolUseId,
393
+ };
394
+ return runLoop(pending.sessionId, pending.assistantHistorySnapshot, args.state, args.context, seedEvents, seedDecision);
395
+ },
396
+ };
397
+ }
398
+ function pauseToOutcome(action, lastDecision) {
399
+ switch (action.kind) {
400
+ case "continue":
401
+ return { kind: "max_iterations_exceeded", lastDecision };
402
+ case "pause_for_user_confirmation":
403
+ return {
404
+ kind: "awaiting_confirmation",
405
+ prompt: action.prompt,
406
+ confirmationToken: action.token,
407
+ };
408
+ case "pause_for_defer":
409
+ return {
410
+ kind: "deferred",
411
+ signal: action.signal,
412
+ intentHash: action.intentHash,
413
+ };
414
+ case "complete_for_escalation":
415
+ return {
416
+ kind: "escalated",
417
+ to: action.to,
418
+ reason: action.reason,
419
+ };
420
+ }
421
+ }
422
+ //# sourceMappingURL=loop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop.js","sourceRoot":"","sources":["../src/loop.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Redis-backed `ConfirmationStore` — restart-durable pending confirmations.
3
+ *
4
+ * The in-memory `createInMemoryConfirmationStore` (see `./persistence.ts`)
5
+ * is suitable for tests and the quickstart, but a process restart loses
6
+ * every pending confirmation. Adopters running the adapter loop in a
7
+ * production process need restart durability so user-held tokens
8
+ * (REQUEST_CONFIRMATION flows that block for hours) survive deploys.
9
+ *
10
+ * This module ships a Redis-backed implementation that uses the same
11
+ * minimal `RedisLedgerClient` surface (`get`/`set`) as the rest of the
12
+ * audit + ledger stack. The store is generic over `H` (the conversation-
13
+ * history shape) — the caller supplies a serializer for their provider's
14
+ * history type.
15
+ *
16
+ * # Wire format
17
+ *
18
+ * Each pending confirmation is JSON-encoded under the key
19
+ * `${prefix}:confirm:${token}`. The TTL on the key matches the
20
+ * adopter-supplied `ttlSeconds` from `put()`.
21
+ *
22
+ * # Get-and-delete (take semantics)
23
+ *
24
+ * `take()` is single-use: a successful take deletes the key. Two
25
+ * concurrent `take(token)` calls race — Redis `GET` + `DEL` is not atomic
26
+ * without scripting, so at most one caller receives the pending
27
+ * confirmation. Production adopters needing strict at-most-once semantics
28
+ * across replicas should wire a Lua script; the JS implementation here
29
+ * accepts a tiny race window where two `take` calls might both return
30
+ * the same pending (the LATER one's adjudication then fails on
31
+ * `REPLAY_SUPPRESSED` via the kernel's ledger — fail-closed by design).
32
+ *
33
+ * # Replay safety
34
+ *
35
+ * Confirmation tokens are NOT inputs to the kernel's adjudication —
36
+ * they're externally-held opaque references. The kernel's
37
+ * `confirmationReceipt` (which IS adjudicated against) is reconstructed
38
+ * from the persisted envelope, not from the token. So storing them in
39
+ * Redis does not change replay determinism.
40
+ */
41
+ import type { ConfirmationStore } from "./persistence.js";
42
+ /**
43
+ * Minimal Redis surface required by the Redis confirmation store. Same
44
+ * shape as `@adjudicate/audit`'s `RedisLedgerClient` so adopters can
45
+ * reuse the same connection.
46
+ */
47
+ export interface ConfirmationRedisClient {
48
+ set(key: string, value: string, options?: {
49
+ NX?: boolean;
50
+ EX?: number;
51
+ }): Promise<string | null>;
52
+ get(key: string): Promise<string | null>;
53
+ del(key: string): Promise<unknown>;
54
+ }
55
+ export interface CreateRedisConfirmationStoreOptions<H> {
56
+ readonly client: ConfirmationRedisClient;
57
+ /**
58
+ * Adopter-supplied key namespacer. Adjudicate convention: wrap the
59
+ * raw suffix into a tenant/env-namespaced key (e.g.,
60
+ * `${APP_ENV}:adjudicate:${suffix}`). Defaults to identity.
61
+ */
62
+ readonly keyFor?: (suffix: string) => string;
63
+ /**
64
+ * Serializer for the assistant history snapshot. Required because `H`
65
+ * is the provider's opaque history shape — Anthropic's MessageParam[]
66
+ * and OpenAI's ChatCompletionMessageParam[] are both JSON-serializable
67
+ * by default. Adopters who use richer types (Date, BigInt) should plug
68
+ * in a custom serializer.
69
+ *
70
+ * Default: `JSON.stringify` / `JSON.parse`.
71
+ */
72
+ readonly serializeHistory?: (h: H) => string;
73
+ readonly deserializeHistory?: (s: string) => H;
74
+ }
75
+ /**
76
+ * Redis-backed `ConfirmationStore<H>`. Wraps the minimal `set/get/del`
77
+ * surface. `put` writes with EX (TTL); `take` does GET then DEL.
78
+ *
79
+ * Adopters share the underlying Redis client across the ledger, the
80
+ * kill switch, and the confirmation store — one connection per role
81
+ * (read/write vs subscribe) is the typical production wiring.
82
+ */
83
+ export declare function createRedisConfirmationStore<H = unknown>(opts: CreateRedisConfirmationStoreOptions<H>): ConfirmationStore<H>;
84
+ //# sourceMappingURL=persistence-redis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persistence-redis.d.ts","sourceRoot":"","sources":["../src/persistence-redis.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAGH,OAAO,KAAK,EACV,iBAAiB,EAElB,MAAM,kBAAkB,CAAC;AAE1B;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,GAAG,CACD,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,OAAO,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,GACtC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC1B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,mCAAmC,CAAC,CAAC;IACpD,QAAQ,CAAC,MAAM,EAAE,uBAAuB,CAAC;IACzC;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;IAC7C;;;;;;;;OAQG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC;IAC7C,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,CAAC,CAAC;CAChD;AAUD;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAAC,CAAC,GAAG,OAAO,EACtD,IAAI,EAAE,mCAAmC,CAAC,CAAC,CAAC,GAC3C,iBAAiB,CAAC,CAAC,CAAC,CAwDtB"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Redis-backed `ConfirmationStore` — restart-durable pending confirmations.
3
+ *
4
+ * The in-memory `createInMemoryConfirmationStore` (see `./persistence.ts`)
5
+ * is suitable for tests and the quickstart, but a process restart loses
6
+ * every pending confirmation. Adopters running the adapter loop in a
7
+ * production process need restart durability so user-held tokens
8
+ * (REQUEST_CONFIRMATION flows that block for hours) survive deploys.
9
+ *
10
+ * This module ships a Redis-backed implementation that uses the same
11
+ * minimal `RedisLedgerClient` surface (`get`/`set`) as the rest of the
12
+ * audit + ledger stack. The store is generic over `H` (the conversation-
13
+ * history shape) — the caller supplies a serializer for their provider's
14
+ * history type.
15
+ *
16
+ * # Wire format
17
+ *
18
+ * Each pending confirmation is JSON-encoded under the key
19
+ * `${prefix}:confirm:${token}`. The TTL on the key matches the
20
+ * adopter-supplied `ttlSeconds` from `put()`.
21
+ *
22
+ * # Get-and-delete (take semantics)
23
+ *
24
+ * `take()` is single-use: a successful take deletes the key. Two
25
+ * concurrent `take(token)` calls race — Redis `GET` + `DEL` is not atomic
26
+ * without scripting, so at most one caller receives the pending
27
+ * confirmation. Production adopters needing strict at-most-once semantics
28
+ * across replicas should wire a Lua script; the JS implementation here
29
+ * accepts a tiny race window where two `take` calls might both return
30
+ * the same pending (the LATER one's adjudication then fails on
31
+ * `REPLAY_SUPPRESSED` via the kernel's ledger — fail-closed by design).
32
+ *
33
+ * # Replay safety
34
+ *
35
+ * Confirmation tokens are NOT inputs to the kernel's adjudication —
36
+ * they're externally-held opaque references. The kernel's
37
+ * `confirmationReceipt` (which IS adjudicated against) is reconstructed
38
+ * from the persisted envelope, not from the token. So storing them in
39
+ * Redis does not change replay determinism.
40
+ */
41
+ /**
42
+ * Redis-backed `ConfirmationStore<H>`. Wraps the minimal `set/get/del`
43
+ * surface. `put` writes with EX (TTL); `take` does GET then DEL.
44
+ *
45
+ * Adopters share the underlying Redis client across the ledger, the
46
+ * kill switch, and the confirmation store — one connection per role
47
+ * (read/write vs subscribe) is the typical production wiring.
48
+ */
49
+ export function createRedisConfirmationStore(opts) {
50
+ const keyFor = opts.keyFor ?? ((s) => s);
51
+ const serialize = opts.serializeHistory ?? ((h) => JSON.stringify(h));
52
+ const deserialize = opts.deserializeHistory ?? ((s) => JSON.parse(s));
53
+ return {
54
+ async put(token, pending, ttlSeconds) {
55
+ const wire = {
56
+ envelope: pending.envelope,
57
+ sessionId: pending.sessionId,
58
+ historyJson: serialize(pending.assistantHistorySnapshot),
59
+ toolUseId: pending.toolUseId,
60
+ prompt: pending.prompt,
61
+ };
62
+ await opts.client.set(keyFor(`confirm:${token}`), JSON.stringify(wire), { EX: ttlSeconds });
63
+ },
64
+ async take(token) {
65
+ const key = keyFor(`confirm:${token}`);
66
+ const raw = await opts.client.get(key);
67
+ if (raw === null)
68
+ return null;
69
+ // Get-and-delete: a single use. Concurrent takes may race; the
70
+ // kernel's ledger backstops with REPLAY_SUPPRESSED on the second
71
+ // adjudication.
72
+ await opts.client.del(key);
73
+ let wire;
74
+ try {
75
+ wire = JSON.parse(raw);
76
+ }
77
+ catch {
78
+ return null;
79
+ }
80
+ let history;
81
+ try {
82
+ history = deserialize(wire.historyJson);
83
+ }
84
+ catch {
85
+ return null;
86
+ }
87
+ return {
88
+ envelope: wire.envelope,
89
+ sessionId: wire.sessionId,
90
+ assistantHistorySnapshot: history,
91
+ toolUseId: wire.toolUseId,
92
+ prompt: wire.prompt,
93
+ };
94
+ },
95
+ };
96
+ }
97
+ //# sourceMappingURL=persistence-redis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persistence-redis.js","sourceRoot":"","sources":["../src/persistence-redis.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAoDH;;;;;;;GAOG;AACH,MAAM,UAAU,4BAA4B,CAC1C,IAA4C;IAE5C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC;IACjD,MAAM,SAAS,GACb,IAAI,CAAC,gBAAgB,IAAI,CAAC,CAAC,CAAI,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;IACzD,MAAM,WAAW,GACf,IAAI,CAAC,kBAAkB,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAM,CAAC,CAAC;IAEjE,OAAO;QACL,KAAK,CAAC,GAAG,CACP,KAAa,EACb,OAA+B,EAC/B,UAAkB;YAElB,MAAM,IAAI,GAAe;gBACvB,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,WAAW,EAAE,SAAS,CAAC,OAAO,CAAC,wBAAwB,CAAC;gBACxD,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,MAAM,EAAE,OAAO,CAAC,MAAM;aACvB,CAAC;YACF,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CACnB,MAAM,CAAC,WAAW,KAAK,EAAE,CAAC,EAC1B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EACpB,EAAE,EAAE,EAAE,UAAU,EAAE,CACnB,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,KAAa;YACtB,MAAM,GAAG,GAAG,MAAM,CAAC,WAAW,KAAK,EAAE,CAAC,CAAC;YACvC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACvC,IAAI,GAAG,KAAK,IAAI;gBAAE,OAAO,IAAI,CAAC;YAC9B,+DAA+D;YAC/D,iEAAiE;YACjE,gBAAgB;YAChB,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC3B,IAAI,IAAgB,CAAC;YACrB,IAAI,CAAC;gBACH,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAe,CAAC;YACvC,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,IAAI,CAAC;YACd,CAAC;YACD,IAAI,OAAU,CAAC;YACf,IAAI,CAAC;gBACH,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC1C,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,IAAI,CAAC;YACd,CAAC;YACD,OAAO;gBACL,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,wBAAwB,EAAE,OAAO;gBACjC,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,MAAM,EAAE,IAAI,CAAC,MAAM;aACpB,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC"}