@yielded/agent-storage-cloudflare 0.1.0-beta.167 → 0.1.0-beta.169
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/DoMemoryStore.mjs +1 -1
- package/dist/DoMessageDeliveryStore.d.mts +1 -1
- package/dist/DoMessageDeliveryStore.mjs +3 -2
- package/dist/DoMessageDeliveryStore.mjs.map +1 -1
- package/dist/DoScheduleStore.mjs +16 -37
- package/dist/DoScheduleStore.mjs.map +1 -1
- package/dist/DoStorageConfig.d.mts +2 -10
- package/dist/DoStorageConfig.mjs +2 -11
- package/dist/DoStorageConfig.mjs.map +1 -1
- package/dist/{DoStorageError-CGuAfSwF.d.mts → DoStorageError-CxjMnzUA.d.mts} +7 -18
- package/dist/DoStorageError.d.mts +2 -2
- package/dist/DoStorageError.mjs +14 -30
- package/dist/DoStorageError.mjs.map +1 -1
- package/dist/DoStorageFailpoint.d.mts +1 -1
- package/dist/DoStorageFailpointTesting.d.mts +1 -1
- package/dist/{DoStorageVersion-iNSyi3cJ.d.mts → DoStorageVersion-DTFoLglB.d.mts} +3 -4
- package/dist/DoStorageVersion.d.mts +1 -1
- package/dist/DoStorageVersion.mjs +2 -2
- package/dist/DoStorageVersion.mjs.map +1 -1
- package/dist/DoSubmissionLedger.d.mts +7 -5
- package/dist/DoSubmissionLedger.mjs +378 -528
- package/dist/DoSubmissionLedger.mjs.map +1 -1
- package/dist/DoSubscriptionStore.mjs +5 -24
- package/dist/DoSubscriptionStore.mjs.map +1 -1
- package/dist/{DoThreadStore-D_83OjCH.d.mts → DoThreadStore-Bd4fTns3.d.mts} +17 -18
- package/dist/DoThreadStore-CwBvTLoq.mjs +468 -0
- package/dist/DoThreadStore-CwBvTLoq.mjs.map +1 -0
- package/dist/DoThreadStore.d.mts +2 -2
- package/dist/DoThreadStore.mjs +4 -529
- package/dist/MemoryProtocol.mjs +3 -3
- package/dist/MemoryProtocol.mjs.map +1 -1
- package/dist/PortProtocol.d.mts +11727 -3410
- package/dist/PortProtocol.mjs +103 -15
- package/dist/PortProtocol.mjs.map +1 -1
- package/dist/PortRouting.d.mts +14 -9
- package/dist/PortRouting.mjs +155 -29
- package/dist/PortRouting.mjs.map +1 -1
- package/dist/do-journal-Cawnsetj.mjs +761 -0
- package/dist/do-journal-Cawnsetj.mjs.map +1 -0
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +1 -1
- package/dist/migrations-D_EP3KYf.mjs +148 -0
- package/dist/migrations-D_EP3KYf.mjs.map +1 -0
- package/dist/{owned-state-DHm2aRXx.mjs → owned-state-BHzUi0eb.mjs} +50 -19
- package/dist/owned-state-BHzUi0eb.mjs.map +1 -0
- package/package.json +1 -1
- package/src/DoMessageDeliveryStore.ts +2 -1
- package/src/DoScheduleStore.ts +19 -59
- package/src/DoStorageConfig.ts +2 -11
- package/src/DoStorageError.ts +3 -26
- package/src/DoStorageVersion.ts +1 -1
- package/src/DoSubmissionLedger.ts +1806 -2030
- package/src/DoSubscriptionStore.ts +5 -47
- package/src/DoThreadStore.ts +276 -622
- package/src/MemoryProtocol.ts +3 -3
- package/src/PortProtocol.ts +198 -12
- package/src/PortRouting.ts +527 -108
- package/src/internal/canonical-append.ts +15 -0
- package/src/internal/do-journal.ts +548 -1440
- package/src/internal/migrations.ts +184 -287
- package/src/internal/owned-state.ts +81 -30
- package/src/internal/prompt-checkpoint.ts +158 -0
- package/src/internal/storage-span.ts +2 -5
- package/dist/DoThreadStore.mjs.map +0 -1
- package/dist/do-journal-DUhjZkOf.mjs +0 -1352
- package/dist/do-journal-DUhjZkOf.mjs.map +0 -1
- package/dist/migrations-DtKz_Gxr.mjs +0 -306
- package/dist/migrations-DtKz_Gxr.mjs.map +0 -1
- package/dist/owned-state-DHm2aRXx.mjs.map +0 -1
- package/src/internal/message-delivery-schema.ts +0 -24
- package/src/internal/recovery-checkpoint-schema.ts +0 -17
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
import { SqliteClient } from "@effect/sql-sqlite-do";
|
|
2
|
-
import {
|
|
2
|
+
import { makeStorageOwner, type StorageOwner } from "@yielded/agent/run-storage";
|
|
3
|
+
import { Deferred, Effect, Exit, Predicate, Schema, Scope, Semaphore } from "effect";
|
|
3
4
|
import { SqlClient } from "effect/sql/SqlClient";
|
|
4
5
|
import type { SqlError } from "effect/sql/SqlError";
|
|
5
6
|
|
|
6
7
|
import { DoStorageCorruptionError, DoStorageError } from "../DoStorageError.ts";
|
|
7
8
|
|
|
8
|
-
const ActiveState = Context.Reference<OwnedState | undefined>(
|
|
9
|
-
"@effect-agent/storage-cloudflare/internal/ActiveState",
|
|
10
|
-
{ defaultValue: () => undefined },
|
|
11
|
-
);
|
|
12
|
-
|
|
13
9
|
/** One disposable view per physical Object database, including separately acquired adapters. */
|
|
14
10
|
export class OwnedState {
|
|
15
|
-
|
|
11
|
+
constructor(readonly owner: StorageOwner["Service"]) {}
|
|
16
12
|
readonly invalidators = new Set<() => void>();
|
|
17
13
|
|
|
18
14
|
readonly invalidate = Effect.sync(() => {
|
|
@@ -21,11 +17,7 @@ export class OwnedState {
|
|
|
21
17
|
|
|
22
18
|
/** Cached readers must wait for the complete transaction, including rollback/commit. */
|
|
23
19
|
readonly read = <A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>
|
|
24
|
-
|
|
25
|
-
active === this
|
|
26
|
-
? effect
|
|
27
|
-
: this.gate.withPermits(1)(Effect.provideService(effect, ActiveState, this)),
|
|
28
|
-
);
|
|
20
|
+
this.owner.withMutation(effect);
|
|
29
21
|
|
|
30
22
|
readonly transaction = <A, E, R>(
|
|
31
23
|
effect: Effect.Effect<A, E, R>,
|
|
@@ -39,14 +31,24 @@ export class OwnedState {
|
|
|
39
31
|
);
|
|
40
32
|
}
|
|
41
33
|
|
|
42
|
-
|
|
34
|
+
interface RetainedState {
|
|
35
|
+
readonly ready: Deferred.Deferred<OwnedState>;
|
|
36
|
+
readonly disposed: Deferred.Deferred<void>;
|
|
37
|
+
readonly scope: Scope.Closeable;
|
|
38
|
+
references: number;
|
|
39
|
+
closing: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const states = new WeakMap<object, RetainedState>();
|
|
43
43
|
|
|
44
44
|
/** Explicit invalidation for maintenance that writes private tables outside the adapters. */
|
|
45
45
|
export const invalidateOwnedState = (storage: DurableObjectStorage): Effect.Effect<void> =>
|
|
46
46
|
Effect.suspend(() => {
|
|
47
47
|
const state = states.get(storage);
|
|
48
48
|
|
|
49
|
-
return state === undefined
|
|
49
|
+
return state === undefined
|
|
50
|
+
? Effect.void
|
|
51
|
+
: Deferred.await(state.ready).pipe(Effect.flatMap((state) => state.read(state.invalidate)));
|
|
50
52
|
});
|
|
51
53
|
|
|
52
54
|
const DoClient = Schema.declare<SqliteClient.SqliteClient>(
|
|
@@ -61,22 +63,64 @@ export const ownedState = (sql: SqlClient) =>
|
|
|
61
63
|
message: "Owned state requires a Durable Object SQLite client.",
|
|
62
64
|
}),
|
|
63
65
|
),
|
|
64
|
-
Effect.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (state === undefined) {
|
|
70
|
-
state = new OwnedState();
|
|
71
|
-
states.set(key, state);
|
|
72
|
-
}
|
|
66
|
+
Effect.flatMap((client) =>
|
|
67
|
+
Effect.uninterruptible(
|
|
68
|
+
Effect.gen(function* () {
|
|
69
|
+
// Instrumentation may return fresh wrappers; the physical Object identity owns the root.
|
|
70
|
+
const key = client.config.storage ?? client.config.db ?? client;
|
|
73
71
|
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
for (;;) {
|
|
73
|
+
let retained = states.get(key);
|
|
74
|
+
|
|
75
|
+
if (retained?.closing) {
|
|
76
|
+
yield* Deferred.await(retained.disposed);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (retained === undefined) {
|
|
80
|
+
retained = {
|
|
81
|
+
ready: Deferred.makeUnsafe(),
|
|
82
|
+
disposed: Deferred.makeUnsafe(),
|
|
83
|
+
scope: Scope.makeUnsafe(),
|
|
84
|
+
references: 1,
|
|
85
|
+
closing: false,
|
|
86
|
+
};
|
|
87
|
+
states.set(key, retained);
|
|
88
|
+
|
|
89
|
+
const owner = yield* makeStorageOwner(Semaphore.makeUnsafe(1).withPermits(1)).pipe(
|
|
90
|
+
Scope.provide(retained.scope),
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
yield* Deferred.succeed(retained.ready, new OwnedState(owner));
|
|
94
|
+
} else retained.references++;
|
|
95
|
+
const current = retained;
|
|
96
|
+
|
|
97
|
+
yield* Effect.addFinalizer(() =>
|
|
98
|
+
Effect.uninterruptible(
|
|
99
|
+
Effect.gen(function* () {
|
|
100
|
+
current.references--;
|
|
101
|
+
if (current.references !== 0) return;
|
|
102
|
+
current.closing = true;
|
|
103
|
+
yield* Scope.close(current.scope, Exit.void).pipe(
|
|
104
|
+
Effect.ensuring(
|
|
105
|
+
Effect.gen(function* () {
|
|
106
|
+
if (states.get(key) === current) states.delete(key);
|
|
107
|
+
yield* Deferred.succeed(current.disposed, undefined);
|
|
108
|
+
}),
|
|
109
|
+
),
|
|
110
|
+
);
|
|
111
|
+
}),
|
|
112
|
+
),
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
return yield* Deferred.await(current.ready);
|
|
116
|
+
}
|
|
117
|
+
}),
|
|
118
|
+
),
|
|
119
|
+
),
|
|
76
120
|
);
|
|
77
121
|
|
|
78
122
|
/**
|
|
79
|
-
* Demand-loaded row views. Writes apply SQLite's RETURNING rows to
|
|
123
|
+
* Demand-loaded row views. Writes apply SQLite's RETURNING rows to affected retained views in
|
|
80
124
|
* the same transaction; rollback discards them. Bounded views avoid loading a host's entire
|
|
81
125
|
* retained submission history just to fence one live submission.
|
|
82
126
|
*/
|
|
@@ -86,6 +130,7 @@ export const ownedRows = <A, I>(
|
|
|
86
130
|
key: (row: A) => string,
|
|
87
131
|
identityColumn?: keyof A & string,
|
|
88
132
|
uniqueFields: ReadonlyArray<ReadonlyArray<keyof A & string>> = [],
|
|
133
|
+
projection: (sql: SqlClient) => ReturnType<SqlClient["literal"]> = (sql) => sql.literal("*"),
|
|
89
134
|
) => {
|
|
90
135
|
type View = {
|
|
91
136
|
readonly id: string;
|
|
@@ -95,6 +140,7 @@ export const ownedRows = <A, I>(
|
|
|
95
140
|
readonly bytes: number;
|
|
96
141
|
};
|
|
97
142
|
const caches = new WeakMap<OwnedState, Map<string, View>>();
|
|
143
|
+
const decodeRows = Schema.decodeUnknownEffect(Schema.Array(schema));
|
|
98
144
|
|
|
99
145
|
return (state: OwnedState, sql: SqlClient) => {
|
|
100
146
|
let cache = caches.get(state);
|
|
@@ -109,7 +155,7 @@ export const ownedRows = <A, I>(
|
|
|
109
155
|
const current = cache;
|
|
110
156
|
|
|
111
157
|
const decode = (rows: unknown) =>
|
|
112
|
-
|
|
158
|
+
decodeRows(rows).pipe(
|
|
113
159
|
Effect.mapError(() =>
|
|
114
160
|
DoStorageCorruptionError.make({
|
|
115
161
|
table,
|
|
@@ -166,7 +212,7 @@ export const ownedRows = <A, I>(
|
|
|
166
212
|
matching(
|
|
167
213
|
JSON.stringify([field, value]),
|
|
168
214
|
(row) => row[field] === value,
|
|
169
|
-
sql`SELECT
|
|
215
|
+
sql`SELECT ${projection(sql)} FROM ${sql(table)} WHERE ${sql(field)} = ${value}`,
|
|
170
216
|
);
|
|
171
217
|
|
|
172
218
|
// Only a source mutation proving the complete result may seed a view. This must run
|
|
@@ -178,7 +224,7 @@ export const ownedRows = <A, I>(
|
|
|
178
224
|
matching(
|
|
179
225
|
JSON.stringify(fields),
|
|
180
226
|
(row) => fields.every(([field, value]) => row[field] === value),
|
|
181
|
-
sql`SELECT
|
|
227
|
+
sql`SELECT ${projection(sql)} FROM ${sql(table)} WHERE ${sql.and(fields.map(([field, value]) => sql`${sql(field)} = ${value}`))}`,
|
|
182
228
|
);
|
|
183
229
|
|
|
184
230
|
const apply =
|
|
@@ -186,12 +232,17 @@ export const ownedRows = <A, I>(
|
|
|
186
232
|
<E, R>(effect: Effect.Effect<ReadonlyArray<unknown>, E, R>) =>
|
|
187
233
|
Effect.gen(function* () {
|
|
188
234
|
const rows = yield* decode(yield* effect);
|
|
235
|
+
|
|
236
|
+
if (rows.length === 0) return rows;
|
|
189
237
|
const changed = new Set(rows.map(key));
|
|
190
238
|
|
|
191
239
|
for (const { id, matches, maxRows, rows: prior } of Array.from(current.values())) {
|
|
240
|
+
const matchingRows = remove ? [] : rows.filter(matches);
|
|
241
|
+
|
|
242
|
+
if (matchingRows.length === 0 && !prior.some((row) => changed.has(key(row)))) continue;
|
|
192
243
|
const next = prior.filter((row) => !changed.has(key(row)));
|
|
193
244
|
|
|
194
|
-
|
|
245
|
+
next.push(...matchingRows);
|
|
195
246
|
retain(id, matches, next, maxRows);
|
|
196
247
|
}
|
|
197
248
|
// A RETURNING row completely defines its unique-key view, even on a new Thread.
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { utf8ByteLength } from "@yielded/agent/digest";
|
|
2
|
+
import {
|
|
3
|
+
MAX_PROMPT_CHECKPOINT_BYTES,
|
|
4
|
+
PromptCheckpoint,
|
|
5
|
+
PromptCheckpointHead,
|
|
6
|
+
PromptCheckpointRead,
|
|
7
|
+
ThreadStoreError,
|
|
8
|
+
type PromptCheckpoints,
|
|
9
|
+
} from "@yielded/agent/thread-store";
|
|
10
|
+
import { Effect, Option, Schema } from "effect";
|
|
11
|
+
import { SqlClient } from "effect/sql/SqlClient";
|
|
12
|
+
|
|
13
|
+
import type { DoJournal } from "./do-journal.ts";
|
|
14
|
+
|
|
15
|
+
const Header = Schema.Struct({
|
|
16
|
+
...PromptCheckpointHead.fields,
|
|
17
|
+
chunks: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 64 })),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const decodeHeader = Schema.decodeEffect(Schema.fromJsonString(Header));
|
|
21
|
+
const encodeHeader = Schema.encodeEffect(Schema.fromJsonString(Header));
|
|
22
|
+
|
|
23
|
+
const decodeRows = Schema.decodeUnknownEffect(
|
|
24
|
+
Schema.Array(
|
|
25
|
+
Schema.Struct({
|
|
26
|
+
key: Schema.String,
|
|
27
|
+
value: Schema.String.check(Schema.isMaxLength(2_000_000)),
|
|
28
|
+
}),
|
|
29
|
+
).check(Schema.isMaxLength(65)),
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
const decodeWrite = Schema.decodeEffect(PromptCheckpoint);
|
|
33
|
+
const decodeRead = Schema.decodeEffect(PromptCheckpointRead);
|
|
34
|
+
|
|
35
|
+
export const promptCheckpointPrefix = (threadId: string) =>
|
|
36
|
+
`prompt-checkpoint/${JSON.stringify(threadId)}/`;
|
|
37
|
+
|
|
38
|
+
const keyFor = (prefix: string, chunk: number) => prefix + String(chunk).padStart(5, "0");
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Versioned derivative keys use the adapter's existing metadata store. Canonical layout and
|
|
42
|
+
* export are unchanged. Chunking keeps SQL values below the DO limit; loading is one bounded
|
|
43
|
+
* query followed by one parse of the native prompt. Only the latest checkpoint is retained.
|
|
44
|
+
*/
|
|
45
|
+
export const makePromptCheckpoints = (
|
|
46
|
+
sql: SqlClient,
|
|
47
|
+
journal: DoJournal,
|
|
48
|
+
maxValueBytes: number,
|
|
49
|
+
): PromptCheckpoints => ({
|
|
50
|
+
load: (input) =>
|
|
51
|
+
journal.state
|
|
52
|
+
.read(
|
|
53
|
+
Effect.gen(function* () {
|
|
54
|
+
const request = yield* decodeRead(input);
|
|
55
|
+
const prefix = promptCheckpointPrefix(request.threadId);
|
|
56
|
+
|
|
57
|
+
// Every row repeats the Thread ID. Bound those known key bytes separately from
|
|
58
|
+
// the prompt and header so supported long IDs do not consume the prompt allowance.
|
|
59
|
+
const maxHydratedBytes =
|
|
60
|
+
MAX_PROMPT_CHECKPOINT_BYTES + 16_384 + 65 * utf8ByteLength(keyFor(prefix, 0));
|
|
61
|
+
|
|
62
|
+
const rows = yield* decodeRows(
|
|
63
|
+
yield* sql`
|
|
64
|
+
SELECT key, value FROM effect_agent_meta
|
|
65
|
+
WHERE key >= ${prefix} AND key < ${prefix + "~"}
|
|
66
|
+
AND (SELECT sum(length(CAST(key AS BLOB)) + length(CAST(value AS BLOB)))
|
|
67
|
+
FROM effect_agent_meta
|
|
68
|
+
WHERE key >= ${prefix} AND key < ${prefix + "~"})
|
|
69
|
+
<= ${maxHydratedBytes}
|
|
70
|
+
ORDER BY key LIMIT 66`,
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
const first = rows[0];
|
|
74
|
+
|
|
75
|
+
if (first === undefined || first.key !== keyFor(prefix, 0)) return Option.none();
|
|
76
|
+
const header = yield* decodeHeader(first.value);
|
|
77
|
+
|
|
78
|
+
if (
|
|
79
|
+
header.threadId !== request.threadId ||
|
|
80
|
+
header.historyThrough >= header.throughSequence ||
|
|
81
|
+
header.chunks !== rows.length - 1 ||
|
|
82
|
+
rows.some((row, index) => row.key !== keyFor(prefix, index))
|
|
83
|
+
)
|
|
84
|
+
return Option.none();
|
|
85
|
+
const [head] = yield* journal.getThread(request.threadId);
|
|
86
|
+
|
|
87
|
+
if (
|
|
88
|
+
head === undefined ||
|
|
89
|
+
head.tail_sequence !== request.throughSequence ||
|
|
90
|
+
head.tail_sequence < header.throughSequence
|
|
91
|
+
)
|
|
92
|
+
return Option.none();
|
|
93
|
+
let bytes = 0;
|
|
94
|
+
|
|
95
|
+
for (const row of rows) {
|
|
96
|
+
bytes += utf8ByteLength(row.value);
|
|
97
|
+
if (bytes > MAX_PROMPT_CHECKPOINT_BYTES + 16_384) return Option.none();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return Option.some({
|
|
101
|
+
...header,
|
|
102
|
+
promptJson: rows
|
|
103
|
+
.slice(1)
|
|
104
|
+
.map((row) => row.value)
|
|
105
|
+
.join(""),
|
|
106
|
+
});
|
|
107
|
+
}),
|
|
108
|
+
)
|
|
109
|
+
.pipe(Effect.orElseSucceed(() => Option.none())),
|
|
110
|
+
save: (input) =>
|
|
111
|
+
Effect.gen(function* () {
|
|
112
|
+
const checkpoint = yield* decodeWrite(input);
|
|
113
|
+
|
|
114
|
+
if (
|
|
115
|
+
utf8ByteLength(checkpoint.promptJson) > MAX_PROMPT_CHECKPOINT_BYTES ||
|
|
116
|
+
checkpoint.historyThrough >= checkpoint.throughSequence
|
|
117
|
+
)
|
|
118
|
+
return;
|
|
119
|
+
const prefix = promptCheckpointPrefix(checkpoint.threadId);
|
|
120
|
+
const chunks: Array<string> = [];
|
|
121
|
+
// Three UTF-8 bytes per UTF-16 code unit is a conservative bound. Keep surrogate pairs
|
|
122
|
+
// together so SQLite never normalizes an isolated half while persisting a chunk.
|
|
123
|
+
const chars = Math.floor(Math.min(maxValueBytes - 4_096, 1_000_000) / 3);
|
|
124
|
+
|
|
125
|
+
if (chars < 1) return;
|
|
126
|
+
for (let offset = 0; offset < checkpoint.promptJson.length;) {
|
|
127
|
+
let end = Math.min(offset + chars, checkpoint.promptJson.length);
|
|
128
|
+
const last = checkpoint.promptJson.charCodeAt(end - 1);
|
|
129
|
+
|
|
130
|
+
if (last >= 0xd800 && last <= 0xdbff) end--;
|
|
131
|
+
if (end <= offset || chunks.length >= 64) return;
|
|
132
|
+
chunks.push(checkpoint.promptJson.slice(offset, end));
|
|
133
|
+
offset = end;
|
|
134
|
+
}
|
|
135
|
+
const header = yield* encodeHeader({ ...checkpoint, chunks: chunks.length });
|
|
136
|
+
|
|
137
|
+
yield* journal.state
|
|
138
|
+
.transaction(
|
|
139
|
+
Effect.gen(function* () {
|
|
140
|
+
const [head] = yield* journal.getThread(checkpoint.threadId);
|
|
141
|
+
|
|
142
|
+
if (head === undefined || head.tail_sequence !== checkpoint.throughSequence) return;
|
|
143
|
+
yield* sql`DELETE FROM effect_agent_meta WHERE key >= ${prefix} AND key < ${prefix + "~"}`;
|
|
144
|
+
for (const [index, value] of [header, ...chunks].entries())
|
|
145
|
+
yield* sql`INSERT INTO effect_agent_meta (key, value) VALUES (${keyFor(prefix, index)}, ${value})`;
|
|
146
|
+
}),
|
|
147
|
+
)
|
|
148
|
+
.pipe(Effect.provideService(SqlClient, sql));
|
|
149
|
+
}).pipe(
|
|
150
|
+
Effect.mapError((cause) =>
|
|
151
|
+
ThreadStoreError.make({
|
|
152
|
+
operation: "save prompt checkpoint",
|
|
153
|
+
message: "Unable to retain a disposable prompt checkpoint",
|
|
154
|
+
cause,
|
|
155
|
+
}),
|
|
156
|
+
),
|
|
157
|
+
),
|
|
158
|
+
});
|
|
@@ -3,10 +3,7 @@ import { Effect, Predicate, Result } from "effect";
|
|
|
3
3
|
type Tagged = { readonly _tag: string; readonly reason?: unknown };
|
|
4
4
|
|
|
5
5
|
export const isAppendContention = (error: Tagged): boolean =>
|
|
6
|
-
error._tag === "
|
|
7
|
-
error._tag === "FenceRejected" ||
|
|
8
|
-
((error._tag === "DoAppendConflict" || error._tag === "AppendConflict") &&
|
|
9
|
-
error.reason === "tail");
|
|
6
|
+
(error._tag === "DoAppendConflict" || error._tag === "AppendConflict") && error.reason === "tail";
|
|
10
7
|
|
|
11
8
|
/** Expected refusals remain typed at the port, but are outcomes of the storage operation. */
|
|
12
9
|
export const storageResult = <A, E extends Tagged, R>(
|
|
@@ -30,7 +27,7 @@ export const annotateStorageError = (error: Tagged) =>
|
|
|
30
27
|
});
|
|
31
28
|
|
|
32
29
|
export const withStorageSpan =
|
|
33
|
-
(name: string, expected: (error: Tagged) => boolean) =>
|
|
30
|
+
(name: string, expected: (error: Tagged) => boolean = () => false) =>
|
|
34
31
|
<A, E extends Tagged, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E, R> =>
|
|
35
32
|
storageResult(effect, expected).pipe(
|
|
36
33
|
Effect.tap((result) =>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"DoThreadStore.mjs","names":[],"sources":["../src/DoThreadStore.ts"],"sourcesContent":["import { BrowserCrypto } from \"@effect/platform-browser\";\nimport { SqliteClient } from \"@effect/sql-sqlite-do\";\nimport {\n makeSelectedReads,\n SelectedReadOwner,\n} from \"@yielded/agent-storage-sql/sql-thread-native-reads\";\nimport { digestCanonicalBatch, EMPTY_TAIL_DIGEST } from \"@yielded/agent/digest\";\nimport {\n CanonicalBatch,\n CanonicalRecord,\n CanonicalRecordEnvelope,\n CanonicalSequence,\n Digest,\n ObservationOffset,\n} from \"@yielded/agent/records\";\nimport { SqlStorageOwner } from \"@yielded/agent/sql-memory-store\";\nimport { DEFAULT_OWNERSHIP_LEASE_DURATION } from \"@yielded/agent/submission-ledger\";\nimport {\n AppendConflict,\n AppendResult,\n CheckpointRejected,\n ThreadCheckpoint,\n ThreadExport,\n ThreadExportRequest,\n ThreadMaterialization,\n ThreadNotMaterialized,\n ThreadObservation,\n ThreadReadRequest,\n ThreadStore,\n type ThreadCheckpoints,\n ThreadStoreError,\n ThreadStoreDiagnostic,\n ThreadTail,\n ThreadTailRequest,\n FenceRejected,\n FencedAppendRequest,\n LoadCheckpointRequest,\n SaveCheckpointRequest,\n SaveRecoveryCheckpointRequest,\n MAX_THREAD_EXPORT_RECORDS,\n type ThreadRecoveryCheckpoints,\n} from \"@yielded/agent/thread-store\";\nimport {\n Clock,\n Context,\n Crypto,\n Duration,\n Effect,\n Layer,\n Option,\n Ref,\n Schema,\n Stream,\n} from \"effect\";\nimport * as SqlClientService from \"effect/sql/SqlClient\";\n\nimport {\n DEFAULT_MAX_STORED_VALUE_BYTES,\n DoStorageConfig,\n DoStorageConfigValue,\n} from \"./DoStorageConfig.ts\";\nimport {\n type DoStorageCompatibilityError,\n DoAppendConflict,\n DoCheckpointConflict,\n DoFenceRejected,\n type DoStorageFailpointLocation,\n DoStorageCorruptionError,\n DoStorageError,\n} from \"./DoStorageError.ts\";\nimport { DoStorageFailpoint, type DoStorageFailpointHandler } from \"./DoStorageFailpoint.ts\";\nimport {\n initializeDoJournal,\n RawAppendRequest,\n RawCheckpoint,\n RawReadRequest,\n type DoJournal,\n} from \"./internal/do-journal.ts\";\nimport { invalidateOwnedState, ownedState } from \"./internal/owned-state.ts\";\nimport { isAppendContention, withStorageSpan } from \"./internal/storage-span.ts\";\n\n/**\n * Convenience-layer construction options. `storage` is the Durable Object's own\n * `ctx.storage` handle, injected as a value (DEPLOY-010: platform bindings enter only\n * through Layers; this package never imports `cloudflare:workers`).\n */\nexport interface DoStorageOptions {\n readonly storage: DurableObjectStorage;\n readonly observationPollInterval?: number | undefined;\n /**\n * Submission ownership lease duration in milliseconds (D5). Defaults to\n * `DEFAULT_OWNERSHIP_LEASE_DURATION` from `@yielded/agent/submission-ledger`.\n */\n readonly ownershipLeaseDuration?: number | undefined;\n /**\n * Maximum bytes for any single stored value; must stay under the platform's 2 MB\n * per-value limit. Defaults to `DEFAULT_MAX_STORED_VALUE_BYTES`.\n */\n readonly maxStoredValueBytes?: number | undefined;\n /**\n * Re-verify every stored payload and digest chain while opening the store. Defaults to\n * off: per-operation Schema decoding and the digest chain already fail clearly on corrupt\n * rows without scanning the whole database on every open.\n */\n readonly verifyOnOpen?: boolean | undefined;\n readonly failpoint?: DoStorageFailpointHandler | undefined;\n}\n\nexport type DoStorageInitializationError =\n | DoStorageCompatibilityError\n | DoStorageCorruptionError\n | DoStorageError;\n\nconst OffsetText = Schema.String.check(Schema.isMaxLength(4 * 1024));\nconst DO_OFFSET_PREFIX = \"effect-agent-do@1:\";\nconst ZERO_CANONICAL_SEQUENCE = Schema.decodeSync(CanonicalSequence)(0);\nconst isDigest = Schema.is(Digest);\nconst isDoFenceRejected = Schema.is(DoFenceRejected);\nconst isDoAppendConflict = Schema.is(DoAppendConflict);\nconst isDoCheckpointConflict = Schema.is(DoCheckpointConflict);\n// Reuse the same AST/parser across reads. Reconstructing a JSON codec per row\n// defeats Schema's parser cache and repeatedly walks the canonical union.\nconst CanonicalRecordJson = Schema.fromJsonString(CanonicalRecord);\nconst CanonicalBatchJson = Schema.fromJsonString(CanonicalBatch);\nconst ThreadCheckpointJson = Schema.fromJsonString(ThreadCheckpoint);\nconst decodeCanonicalRecord = Schema.decodeEffect(CanonicalRecordJson);\n\nconst storeError = (\n operation: string,\n error: { readonly message: string; readonly diagnostic?: ThreadStoreDiagnostic },\n) =>\n ThreadStoreError.make({\n cause: error,\n operation,\n message: error.message,\n ...(error.diagnostic === undefined ? {} : { diagnostic: error.diagnostic }),\n });\n\nconst schemaStoreError = (operation: string, error: Schema.SchemaError) =>\n ThreadStoreError.make({\n operation,\n message: \"A Thread storage value does not satisfy its schema\",\n diagnostic: ThreadStoreDiagnostic.make({\n causeTag: error._tag,\n operation,\n issueTag: error.issue._tag,\n }),\n });\n\nconst makeOffset = Effect.fn(function* (\n threadId: ThreadMaterialization[\"threadId\"],\n sequence: number,\n): Effect.fn.Return<ObservationOffset, ThreadStoreError> {\n return yield* Schema.decodeEffect(CanonicalSequence)(sequence).pipe(\n Effect.flatMap((validatedSequence) =>\n Schema.decodeEffect(ObservationOffset)(\n `${DO_OFFSET_PREFIX}${encodeURIComponent(threadId)}:${validatedSequence}`,\n ),\n ),\n Effect.mapError((error) => schemaStoreError(\"encode observation offset\", error)),\n );\n});\n\nconst parseOffset = Effect.fn(function* (\n threadId: ThreadMaterialization[\"threadId\"],\n offset: ObservationOffset | undefined,\n): Effect.fn.Return<CanonicalSequence, ThreadStoreError> {\n if (offset === undefined) return ZERO_CANONICAL_SEQUENCE;\n\n const text = yield* Schema.decodeEffect(OffsetText)(offset).pipe(\n Effect.mapError((error) => schemaStoreError(\"decode observation offset\", error)),\n );\n\n const threadPrefix = `${DO_OFFSET_PREFIX}${encodeURIComponent(threadId)}:`;\n\n if (!text.startsWith(threadPrefix)) {\n return yield* ThreadStoreError.make({\n operation: \"decode observation offset\",\n message: \"The observation offset belongs to a different adapter, storage version, or Thread.\",\n });\n }\n const sequenceText = text.slice(threadPrefix.length);\n\n if (!/^(0|[1-9][0-9]*)$/.test(sequenceText)) {\n return yield* ThreadStoreError.make({\n operation: \"decode observation offset\",\n message: \"The observation offset is malformed.\",\n });\n }\n\n return yield* Schema.decodeEffect(CanonicalSequence)(Number(sequenceText)).pipe(\n Effect.mapError((error) => schemaStoreError(\"decode observation offset\", error)),\n );\n});\n\nconst mapFence = (threadId: ThreadMaterialization[\"threadId\"], error: DoFenceRejected) =>\n FenceRejected.make({\n threadId,\n actualEpoch: error.actualEpoch,\n attemptedEpoch: error.producerEpoch,\n });\n\nconst encodeCanonicalRecord = Effect.fn(function* (\n record: CanonicalRecord,\n): Effect.fn.Return<string, ThreadStoreError> {\n return yield* Schema.encodeEffect(CanonicalRecordJson)(record).pipe(\n Effect.mapError((error) => schemaStoreError(\"encode canonical record\", error)),\n );\n});\n\nconst encodeCanonicalBatch = Effect.fn(function* (\n batch: CanonicalBatch,\n): Effect.fn.Return<string, ThreadStoreError> {\n return yield* Schema.encodeEffect(CanonicalBatchJson)(batch).pipe(\n Effect.mapError((error) => schemaStoreError(\"encode canonical batch\", error)),\n );\n});\n\nconst encodeCheckpoint = Effect.fn(function* (\n checkpoint: ThreadCheckpoint,\n): Effect.fn.Return<string, ThreadStoreError> {\n return yield* Schema.encodeEffect(ThreadCheckpointJson)(checkpoint).pipe(\n Effect.mapError((error) => schemaStoreError(\"encode checkpoint\", error)),\n );\n});\n\nconst envelopes = new WeakMap<object, CanonicalRecordEnvelope>();\n\nconst decodeEnvelope = Effect.fnUntraced(function* (row: {\n readonly batch_id: string;\n readonly thread_id: string;\n readonly record_json: string;\n readonly sequence: CanonicalSequence;\n}) {\n const cached = envelopes.get(row);\n\n if (cached !== undefined) return cached;\n\n const record = yield* decodeCanonicalRecord(row.record_json).pipe(\n Effect.mapError((error) =>\n ThreadStoreError.make({\n operation: \"decode canonical record\",\n message: \"The canonical record does not satisfy its schema\",\n diagnostic: ThreadStoreDiagnostic.make({\n causeTag: error._tag,\n operation: \"decode canonical record\",\n decoder: \"CanonicalRecord\",\n sequence: row.sequence,\n issueTag: error.issue._tag,\n }),\n }),\n ),\n Effect.tapError((error) =>\n Effect.annotateCurrentSpan({\n \"storage.failure.operation\": error.diagnostic?.operation,\n \"storage.failure.cause\": error.diagnostic?.causeTag,\n \"storage.failure.decoder\": error.diagnostic?.decoder,\n \"storage.failure.sequence\": row.sequence,\n \"storage.failure.issue\": error.diagnostic?.issueTag,\n }),\n ),\n );\n\n const threadId = yield* Schema.decodeEffect(CanonicalRecordEnvelope.fields.threadId)(\n row.thread_id,\n ).pipe(Effect.mapError((error) => schemaStoreError(\"decode thread identity\", error)));\n\n const offset = yield* makeOffset(threadId, row.sequence);\n\n const batchId = yield* Schema.decodeEffect(CanonicalRecordEnvelope.fields.batchId)(\n row.batch_id,\n ).pipe(Effect.mapError((error) => schemaStoreError(\"decode batch identity\", error)));\n\n const envelope = CanonicalRecordEnvelope.make({\n threadId,\n batchId,\n sequence: row.sequence,\n offset,\n record,\n });\n\n envelopes.set(row, envelope);\n\n return envelope;\n});\n\nconst decodeCheckpoint = Effect.fn(function* (\n checkpointJson: string,\n): Effect.fn.Return<ThreadCheckpoint, ThreadStoreError> {\n return yield* Schema.decodeEffect(Schema.fromJsonString(ThreadCheckpoint))(checkpointJson).pipe(\n Effect.mapError((error) => schemaStoreError(\"decode checkpoint\", error)),\n );\n});\n\nconst requireThread = Effect.fn(\"DoThreadStore.requireThread\")(function* (\n journal: DoJournal,\n threadId: ThreadMaterialization[\"threadId\"],\n) {\n const rows = yield* journal\n .getThread(threadId)\n .pipe(Effect.mapError((error) => storeError(\"read thread\", error)));\n\n if (rows.length === 0) {\n return yield* ThreadNotMaterialized.make({ threadId });\n }\n\n return rows[0];\n});\n\nconst tailDigestAt = Effect.fn(\"DoThreadStore.tailDigestAt\")(function* (\n journal: DoJournal,\n threadId: ThreadMaterialization[\"threadId\"],\n sequence: CanonicalSequence,\n) {\n if (sequence === 0) return EMPTY_TAIL_DIGEST;\n\n const digests = yield* journal\n .getTailDigestAt(threadId, sequence)\n .pipe(Effect.mapError((error) => storeError(\"read checkpoint digest\", error)));\n\n if (digests.length !== 1) {\n return yield* CheckpointRejected.make({\n threadId,\n reason: \"digest-mismatch\",\n });\n }\n\n return yield* Schema.decodeEffect(Digest)(digests[0]).pipe(\n Effect.mapError((error) => schemaStoreError(\"decode checkpoint digest\", error)),\n );\n});\n\nconst groupByKey = <A>(\n rows: ReadonlyArray<A>,\n key: (row: A) => string,\n): ReadonlyMap<string, ReadonlyArray<A>> => {\n const grouped = new Map<string, Array<A>>();\n\n for (const row of rows) {\n const existing = grouped.get(key(row));\n\n if (existing === undefined) {\n grouped.set(key(row), [row]);\n } else {\n existing.push(row);\n }\n }\n\n return grouped;\n};\n\n/**\n * Opt-in integrity audit (`verifyOnOpen`) of canonical payloads, their digest chains and generic\n * projection checkpoints. Disposable recovery checkpoints are validated when loaded. Routine opens\n * skip this scan: per-operation Schema decoding fails clearly on corrupt canonical rows.\n */\nconst decodeStartupPayloads = Effect.fn(\"DoThreadStore.decodeStartupPayloads\")(function* (\n journal: DoJournal,\n crypto: Crypto.Crypto,\n) {\n const stored = yield* journal.scanStoredPayloads();\n\n const batches = yield* Effect.forEach(stored.batches, (batch) =>\n Schema.decodeEffect(Schema.fromJsonString(CanonicalBatch))(batch.batch_json).pipe(\n Effect.map((decoded) => ({ decoded, row: batch })),\n Effect.mapError((error) =>\n DoStorageCorruptionError.make({\n table: \"effect_agent_canonical_batches\",\n rowKey: `${batch.thread_id}/${batch.batch_id}`,\n message: error.message,\n }),\n ),\n ),\n );\n\n const records = yield* Effect.forEach(stored.records, (record) =>\n Schema.decodeEffect(Schema.fromJsonString(CanonicalRecord))(record.record_json).pipe(\n Effect.map((decoded) => ({ decoded, row: record })),\n Effect.mapError((error) =>\n DoStorageCorruptionError.make({\n table: \"effect_agent_canonical_records\",\n rowKey: `${record.thread_id}/${record.sequence}`,\n message: error.message,\n }),\n ),\n ),\n );\n\n const checkpoints = yield* Effect.forEach(stored.checkpoints, (checkpoint) =>\n Schema.decodeEffect(Schema.fromJsonString(ThreadCheckpoint))(checkpoint.checkpoint_json).pipe(\n Effect.map((decoded) => ({ decoded, row: checkpoint })),\n Effect.mapError((error) =>\n DoStorageCorruptionError.make({\n table: \"effect_agent_checkpoints\",\n rowKey: `${checkpoint.thread_id}/${checkpoint.through_sequence}`,\n message: error.message,\n }),\n ),\n ),\n );\n\n const batchesByThread = groupByKey(batches, ({ row }) => row.thread_id);\n const recordsByThread = groupByKey(records, ({ row }) => row.thread_id);\n const checkpointsByThread = groupByKey(checkpoints, ({ row }) => row.thread_id);\n const materializedIds = new Set(stored.threads.map((thread) => thread.thread_id));\n\n for (const thread of stored.threads) {\n const threadBatches = batchesByThread.get(thread.thread_id) ?? [];\n const threadRecords = recordsByThread.get(thread.thread_id) ?? [];\n const threadCheckpoints = checkpointsByThread.get(thread.thread_id) ?? [];\n const recordsByBatch = groupByKey(threadRecords, ({ row }) => row.batch_id);\n let previousDigest = EMPTY_TAIL_DIGEST;\n let expectedSequence = 1;\n const tailDigests = new Map<number, string>([[0, EMPTY_TAIL_DIGEST]]);\n\n for (const { decoded: canonicalBatch, row: batchRow } of threadBatches) {\n const key = `${batchRow.thread_id}/${batchRow.batch_id}`;\n\n if (\n canonicalBatch.batchId !== batchRow.batch_id ||\n batchRow.first_sequence !== expectedSequence ||\n batchRow.last_sequence !== batchRow.first_sequence + canonicalBatch.records.length - 1\n ) {\n return yield* DoStorageCorruptionError.make({\n table: \"effect_agent_canonical_batches\",\n rowKey: key,\n message: \"Canonical batch identity, sequence, or record count is inconsistent.\",\n });\n }\n\n const digest = yield* digestCanonicalBatch(previousDigest, canonicalBatch).pipe(\n Effect.provideService(Crypto.Crypto, crypto),\n Effect.mapError((error) =>\n DoStorageCorruptionError.make({\n table: \"effect_agent_canonical_batches\",\n rowKey: key,\n message: error.message,\n }),\n ),\n );\n\n if (batchRow.batch_digest !== digest || batchRow.tail_digest !== digest) {\n return yield* DoStorageCorruptionError.make({\n table: \"effect_agent_canonical_batches\",\n rowKey: key,\n message: \"Canonical batch digest does not match its decoded content and prior tail.\",\n });\n }\n\n const batchRecords = recordsByBatch.get(batchRow.batch_id) ?? [];\n\n if (batchRecords.length !== canonicalBatch.records.length) {\n return yield* DoStorageCorruptionError.make({\n table: \"effect_agent_canonical_records\",\n rowKey: key,\n message: \"Canonical batch and record-table counts differ.\",\n });\n }\n for (let index = 0; index < canonicalBatch.records.length; index++) {\n const expectedRecord = canonicalBatch.records[index];\n const storedRecord = batchRecords[index];\n\n const expectedJson = yield* Schema.encodeEffect(Schema.fromJsonString(CanonicalRecord))(\n expectedRecord,\n ).pipe(\n Effect.mapError((error) =>\n DoStorageCorruptionError.make({\n table: \"effect_agent_canonical_batches\",\n rowKey: key,\n message: error.message,\n }),\n ),\n );\n\n const storedJson = yield* Schema.encodeEffect(Schema.fromJsonString(CanonicalRecord))(\n storedRecord.decoded,\n ).pipe(\n Effect.mapError((error) =>\n DoStorageCorruptionError.make({\n table: \"effect_agent_canonical_records\",\n rowKey: `${key}/${storedRecord.row.sequence}`,\n message: error.message,\n }),\n ),\n );\n\n if (\n storedRecord.row.sequence !== batchRow.first_sequence + index ||\n storedRecord.row.record_id !== expectedRecord.recordId ||\n expectedJson !== storedJson\n ) {\n return yield* DoStorageCorruptionError.make({\n table: \"effect_agent_canonical_records\",\n rowKey: `${key}/${storedRecord.row.sequence}`,\n message: \"Canonical record identity, sequence, or payload differs from its batch.\",\n });\n }\n }\n\n previousDigest = digest;\n expectedSequence = batchRow.last_sequence + 1;\n tailDigests.set(batchRow.last_sequence, digest);\n }\n\n if (\n threadRecords.length !== thread.tail_sequence ||\n thread.tail_sequence !== expectedSequence - 1 ||\n thread.tail_digest !== previousDigest\n ) {\n return yield* DoStorageCorruptionError.make({\n table: \"effect_agent_threads\",\n rowKey: thread.thread_id,\n message: \"Thread tail does not match its canonical batch chain.\",\n });\n }\n\n for (const checkpoint of threadCheckpoints) {\n if (\n checkpoint.decoded.threadId !== thread.thread_id ||\n checkpoint.decoded.throughSequence !== checkpoint.row.through_sequence ||\n checkpoint.decoded.tailDigest !== checkpoint.row.tail_digest ||\n tailDigests.get(checkpoint.row.through_sequence) !== checkpoint.row.tail_digest\n ) {\n return yield* DoStorageCorruptionError.make({\n table: \"effect_agent_checkpoints\",\n rowKey: `${thread.thread_id}/${checkpoint.row.through_sequence}`,\n message: \"Checkpoint identity or digest is not bound to a canonical batch tail.\",\n });\n }\n }\n }\n\n if (\n batches.some(({ row }) => !materializedIds.has(row.thread_id)) ||\n records.some(({ row }) => !materializedIds.has(row.thread_id)) ||\n checkpoints.some(({ row }) => !materializedIds.has(row.thread_id))\n ) {\n return yield* DoStorageCorruptionError.make({\n table: \"effect_agent_threads\",\n rowKey: \"startup_scan\",\n message: \"Canonical rows exist without a materialized Thread.\",\n });\n }\n});\n\nconst makeServices = Effect.fn(\"DoThreadStore.makeServices\")(function* () {\n const config = yield* DoStorageConfig;\n const failpoint = yield* DoStorageFailpoint;\n const sql = yield* SqlClientService.SqlClient;\n const crypto = yield* Crypto.Crypto;\n const journal = yield* initializeDoJournal(sql, failpoint.hit, config.maxStoredValueBytes);\n\n if (config.verifyOnOpen) {\n yield* decodeStartupPayloads(journal, crypto);\n }\n\n const provideCrypto = <A, E>(effect: Effect.Effect<A, E, Crypto.Crypto>) =>\n Effect.provideService(effect, Crypto.Crypto, crypto);\n\n const hitFailpoint = Effect.fn(\n (location: DoStorageFailpointLocation): Effect.Effect<void, ThreadStoreError> =>\n failpoint\n .hit(location)\n .pipe(Effect.mapError((error) => storeError(`storage failpoint ${location}`, error))),\n );\n\n const materialize: ThreadStore[\"Service\"][\"materialize\"] = Effect.fnUntraced(\n function* (request: ThreadMaterialization) {\n const validated = yield* Schema.decodeEffect(Schema.toType(ThreadMaterialization))(\n request,\n ).pipe(Effect.mapError((error) => schemaStoreError(\"validate materialization\", error)));\n\n const now = yield* Clock.currentTimeMillis;\n\n yield* hitFailpoint(\"materialize:before\");\n yield* journal\n .materialize(\n validated.threadId,\n new Date(now).toISOString(),\n EMPTY_TAIL_DIGEST,\n validated.producerEpoch,\n )\n .pipe(\n Effect.mapError((error) =>\n error._tag === \"DoFenceRejected\"\n ? mapFence(validated.threadId, error)\n : storeError(\"materialize thread\", error),\n ),\n );\n yield* hitFailpoint(\"materialize:after\");\n },\n withStorageSpan(\"DoThreadStore.materialize\", (error) => error._tag === \"FenceRejected\"),\n );\n\n const append: ThreadStore[\"Service\"][\"append\"] = Effect.fnUntraced(\n function* (request: FencedAppendRequest) {\n const validated = yield* Schema.decodeEffect(Schema.toType(FencedAppendRequest))(\n request,\n ).pipe(Effect.mapError((error) => schemaStoreError(\"validate canonical append\", error)));\n\n const observed = yield* requireThread(journal, validated.threadId);\n\n const tailDigest = yield* provideCrypto(\n digestCanonicalBatch(validated.expectedTailDigest, validated.batch),\n ).pipe(Effect.mapError((error) => storeError(\"digest canonical append\", error)));\n\n const batchJson = yield* encodeCanonicalBatch(validated.batch);\n\n const rawRecords = yield* Effect.forEach(validated.batch.records, (record) =>\n encodeCanonicalRecord(record).pipe(\n Effect.map((recordJson) => ({\n recordId: record.recordId,\n recordJson,\n })),\n ),\n );\n\n const rawRequest = yield* Schema.decodeEffect(RawAppendRequest)({\n threadId: validated.threadId,\n batchId: validated.batch.batchId,\n batchDigest: tailDigest,\n batchJson,\n expectedTailSequence: validated.expectedTailSequence,\n expectedTailDigest: validated.expectedTailDigest,\n producerEpoch: validated.producerEpoch,\n records: rawRecords,\n tailDigest,\n }).pipe(Effect.mapError((error) => schemaStoreError(\"encode canonical append\", error)));\n\n yield* hitFailpoint(\"append:before\");\n\n const result = yield* journal.append(rawRequest, observed).pipe(\n Effect.mapError((error) => {\n if (isDoFenceRejected(error)) {\n return mapFence(validated.threadId, error);\n }\n if (isDoAppendConflict(error)) {\n return error.actualTailSequence !== undefined && isDigest(error.actualTailDigest)\n ? AppendConflict.make({\n threadId: validated.threadId,\n batchId: validated.batch.batchId,\n reason: error.reason,\n actualTailSequence: error.actualTailSequence,\n actualTailDigest: error.actualTailDigest,\n })\n : AppendConflict.make({\n threadId: validated.threadId,\n batchId: validated.batch.batchId,\n reason: error.reason,\n });\n }\n\n return storeError(\"append canonical batch\", error);\n }),\n Effect.flatMap((result) =>\n Schema.decodeEffect(AppendResult)(result).pipe(\n Effect.mapError((error) => schemaStoreError(\"decode append result\", error)),\n ),\n ),\n );\n\n yield* hitFailpoint(\"append:after\");\n\n return result;\n },\n withStorageSpan(\"DoThreadStore.append\", isAppendContention),\n );\n\n const loadRecords = Effect.fnUntraced(function* (request: RawReadRequest) {\n const result = yield* journal\n .read(request)\n .pipe(Effect.mapError((error) => storeError(\"read canonical records\", error)));\n\n return {\n count: result.count,\n records: result.records.pipe(\n Stream.mapError((error) => storeError(\"read canonical records\", error)),\n Stream.mapEffect(decodeEnvelope),\n ),\n };\n });\n\n const readEffect = Effect.fn(\"DoThreadStore.read\")(function* (request: ThreadReadRequest) {\n const validated = yield* Schema.decodeEffect(Schema.toType(ThreadReadRequest))(request).pipe(\n Effect.mapError((error) => schemaStoreError(\"validate thread read\", error)),\n );\n\n if (\"selection\" in validated) return Stream.fromIterable(yield* selectedReads.read(validated));\n yield* requireThread(journal, validated.threadId);\n\n const result = yield* loadRecords(\n RawReadRequest.make({\n threadId: validated.threadId,\n fromSequenceExclusive: validated.afterSequence ?? ZERO_CANONICAL_SEQUENCE,\n limit: validated.limit,\n }),\n );\n\n return result.records;\n });\n\n const read: ThreadStore[\"Service\"][\"read\"] = (request) => Stream.unwrap(readEffect(request));\n\n const observeEffect = Effect.fnUntraced(function* (request: ThreadObservation) {\n const validated = yield* Schema.decodeEffect(Schema.toType(ThreadObservation))(request).pipe(\n Effect.mapError((error) => schemaStoreError(\"validate thread observation\", error)),\n );\n\n yield* requireThread(journal, validated.threadId);\n const initialSequence = yield* parseOffset(validated.threadId, validated.afterOffset);\n const cursor = yield* Ref.make(initialSequence);\n let polls = 0;\n let emptyPolls = 0;\n let deliveredRecords = 0;\n\n const poll = Effect.fnUntraced(function* () {\n polls++;\n const fromSequenceExclusive = yield* Ref.get(cursor);\n\n const result = yield* loadRecords(\n RawReadRequest.make({\n threadId: validated.threadId,\n fromSequenceExclusive,\n limit: 1_024,\n }),\n );\n\n if (result.count === 0) {\n emptyPolls++;\n yield* Effect.sleep(config.observationPollInterval);\n\n return Stream.empty;\n }\n\n return result.records.pipe(\n Stream.tap((record) => {\n deliveredRecords++;\n\n return Ref.set(cursor, record.sequence);\n }),\n );\n });\n\n return Stream.fromEffectRepeat(poll()).pipe(\n Stream.flatten,\n Stream.ensuring(\n Effect.suspend(() =>\n Effect.annotateCurrentSpan({\n \"effect_agent.observation.polls\": polls,\n \"effect_agent.observation.empty_polls\": emptyPolls,\n \"effect_agent.observation.records\": deliveredRecords,\n }),\n ),\n ),\n );\n });\n\n const observe: ThreadStore[\"Service\"][\"observe\"] = (request) =>\n Stream.unwrap(observeEffect(request)).pipe(Stream.withSpan(\"DoThreadStore.observe\"));\n\n const exportThread: ThreadStore[\"Service\"][\"export\"] = Effect.fn(\"DoThreadStore.export\")(\n function* (request: ThreadExportRequest) {\n const validated = yield* Schema.decodeEffect(Schema.toType(ThreadExportRequest))(\n request,\n ).pipe(Effect.mapError((error) => schemaStoreError(\"validate thread export\", error)));\n\n yield* requireThread(journal, validated.threadId);\n\n const exported = yield* journal\n .exportThread(validated.threadId)\n .pipe(Effect.mapError((error) => storeError(\"export thread\", error)));\n\n const records = yield* Effect.forEach(exported.records, decodeEnvelope);\n\n if (records.length > MAX_THREAD_EXPORT_RECORDS) {\n return yield* ThreadStoreError.make({\n operation: \"decode thread export\",\n message: \"The thread exceeds the current export record limit.\",\n });\n }\n\n const tailDigest = yield* Schema.decodeEffect(Digest)(exported.thread.tail_digest).pipe(\n Effect.mapError((error) => schemaStoreError(\"decode export tail digest\", error)),\n );\n\n return ThreadExport.make({\n format: \"effect-agent/thread@1\",\n threadId: validated.threadId,\n tailSequence: exported.thread.tail_sequence,\n tailDigest,\n records,\n });\n },\n );\n\n const inspectTail: ThreadStore[\"Service\"][\"inspectTail\"] = Effect.fn(\"DoThreadStore.inspectTail\")(\n function* (request: ThreadTailRequest) {\n const validated = yield* Schema.decodeEffect(Schema.toType(ThreadTailRequest))(request).pipe(\n Effect.mapError((error) => schemaStoreError(\"validate tail inspection\", error)),\n );\n\n const thread = yield* requireThread(journal, validated.threadId);\n\n const tailDigest = yield* Schema.decodeEffect(Digest)(thread.tail_digest).pipe(\n Effect.mapError((error) => schemaStoreError(\"decode tail digest\", error)),\n );\n\n return ThreadTail.make({\n threadId: validated.threadId,\n tailSequence: thread.tail_sequence,\n tailDigest,\n producerEpoch: thread.producer_epoch,\n });\n },\n );\n\n const saveCheckpoint: ThreadCheckpoints[\"save\"] = Effect.fn(\"DoThreadStore.saveCheckpoint\")(\n function* (request: SaveCheckpointRequest) {\n const validated = yield* Schema.decodeEffect(Schema.toType(SaveCheckpointRequest))(\n request,\n ).pipe(Effect.mapError((error) => schemaStoreError(\"validate checkpoint\", error)));\n\n const thread = yield* requireThread(journal, validated.checkpoint.threadId);\n\n if (validated.checkpoint.throughSequence > thread.tail_sequence) {\n return yield* CheckpointRejected.make({\n threadId: validated.checkpoint.threadId,\n reason: \"ahead-of-tail\",\n });\n }\n\n const canonicalDigest = yield* tailDigestAt(\n journal,\n validated.checkpoint.threadId,\n validated.checkpoint.throughSequence,\n );\n\n if (canonicalDigest !== validated.checkpoint.tailDigest) {\n return yield* CheckpointRejected.make({\n threadId: validated.checkpoint.threadId,\n reason: \"digest-mismatch\",\n });\n }\n const checkpointJson = yield* encodeCheckpoint(validated.checkpoint);\n\n const raw = RawCheckpoint.make({\n threadId: validated.checkpoint.threadId,\n throughSequence: validated.checkpoint.throughSequence,\n tailDigest: validated.checkpoint.tailDigest,\n checkpointJson,\n });\n\n yield* hitFailpoint(\"save-checkpoint:before\");\n yield* journal.saveCheckpoint(raw).pipe(\n Effect.mapError((error) =>\n isDoCheckpointConflict(error)\n ? CheckpointRejected.make({\n threadId: validated.checkpoint.threadId,\n reason: \"digest-mismatch\",\n })\n : storeError(\"save checkpoint\", error),\n ),\n );\n yield* hitFailpoint(\"save-checkpoint:after\");\n },\n );\n\n const loadCheckpoint: ThreadCheckpoints[\"load\"] = Effect.fn(\"DoThreadStore.loadCheckpoint\")(\n function* (request: LoadCheckpointRequest) {\n const validated = yield* Schema.decodeEffect(Schema.toType(LoadCheckpointRequest))(\n request,\n ).pipe(Effect.mapError((error) => schemaStoreError(\"validate checkpoint lookup\", error)));\n\n const thread = yield* requireThread(journal, validated.threadId);\n\n const rows = yield* journal\n .loadCheckpoint(validated.threadId, validated.atOrBeforeSequence ?? thread.tail_sequence)\n .pipe(Effect.mapError((error) => storeError(\"load checkpoint\", error)));\n\n if (rows.length === 0) return Option.none();\n if (rows.length !== 1) {\n return yield* ThreadStoreError.make({\n operation: \"load checkpoint\",\n message: `Expected at most one checkpoint row but found ${rows.length}.`,\n });\n }\n const row = rows[0];\n const checkpoint = yield* decodeCheckpoint(row.checkpoint_json);\n\n if (\n row.thread_id !== validated.threadId ||\n checkpoint.threadId !== row.thread_id ||\n checkpoint.throughSequence !== row.through_sequence ||\n checkpoint.tailDigest !== row.tail_digest\n ) {\n return yield* ThreadStoreError.make({\n operation: \"load checkpoint\",\n message: \"Stored checkpoint metadata does not match its canonical row.\",\n });\n }\n\n const canonicalDigest = yield* tailDigestAt(\n journal,\n checkpoint.threadId,\n checkpoint.throughSequence,\n );\n\n if (canonicalDigest !== checkpoint.tailDigest) {\n return yield* CheckpointRejected.make({\n threadId: checkpoint.threadId,\n reason: \"digest-mismatch\",\n });\n }\n\n return Option.some(checkpoint);\n },\n );\n\n const saveRecoveryCheckpoint: ThreadRecoveryCheckpoints[\"save\"] = Effect.fn(\n \"DoThreadStore.saveRecoveryCheckpoint\",\n )(function* (request) {\n const validated = yield* Schema.decodeEffect(Schema.toType(SaveRecoveryCheckpointRequest))(\n request,\n ).pipe(Effect.mapError((error) => schemaStoreError(\"validate recovery checkpoint\", error)));\n\n const checkpointJson = yield* encodeCheckpoint(validated.checkpoint);\n\n yield* journal\n .saveRecoveryCheckpoint(validated, checkpointJson)\n .pipe(\n Effect.mapError((error) =>\n error._tag === \"CheckpointRejected\" ||\n error._tag === \"FenceRejected\" ||\n error._tag === \"ThreadNotMaterialized\"\n ? error\n : storeError(\"save recovery checkpoint\", error),\n ),\n );\n });\n\n const loadRecoveryCheckpoint: ThreadRecoveryCheckpoints[\"load\"] = Effect.fn(\n \"DoThreadStore.loadRecoveryCheckpoint\",\n )(function* (request) {\n const validated = yield* Schema.decodeEffect(Schema.toType(LoadCheckpointRequest))(\n request,\n ).pipe(\n Effect.mapError((error) => schemaStoreError(\"validate recovery checkpoint lookup\", error)),\n );\n\n const thread = yield* requireThread(journal, validated.threadId);\n\n const corrupt = () =>\n CheckpointRejected.make({ threadId: validated.threadId, reason: \"corrupt\" });\n\n const rows = yield* journal\n .loadRecoveryCheckpoint(validated.threadId)\n .pipe(\n Effect.mapError((error) =>\n error._tag === \"DoStorageCorruptionError\"\n ? corrupt()\n : storeError(\"load recovery checkpoint\", error),\n ),\n );\n\n if (rows.length === 0) return Option.none();\n if (rows.length !== 1) return yield* corrupt();\n const row = rows[0];\n\n const checkpoint = yield* Schema.decodeEffect(Schema.fromJsonString(ThreadCheckpoint))(\n row.checkpoint_json,\n ).pipe(Effect.mapError(corrupt));\n\n if (\n row.thread_id !== validated.threadId ||\n checkpoint.threadId !== row.thread_id ||\n checkpoint.throughSequence !== row.through_sequence ||\n checkpoint.tailDigest !== row.tail_digest\n )\n return yield* corrupt();\n if (checkpoint.throughSequence > thread.tail_sequence)\n return yield* CheckpointRejected.make({\n threadId: validated.threadId,\n reason: \"ahead-of-tail\",\n });\n if (checkpoint.throughSequence > (validated.atOrBeforeSequence ?? thread.tail_sequence))\n return Option.none();\n\n const canonicalDigest = yield* tailDigestAt(\n journal,\n checkpoint.threadId,\n checkpoint.throughSequence,\n );\n\n if (canonicalDigest !== checkpoint.tailDigest)\n return yield* CheckpointRejected.make({\n threadId: validated.threadId,\n reason: \"digest-mismatch\",\n });\n\n return Option.some(checkpoint);\n });\n\n const selectedReads = yield* makeSelectedReads(decodeEnvelope).pipe(\n Effect.provideService(SelectedReadOwner, {\n snapshot: journal.state.read,\n tail: (threadId) =>\n journal.getThread(threadId).pipe(\n Effect.flatMap((rows) =>\n Schema.decodeEffect(\n Schema.UndefinedOr(\n Schema.Struct({\n tail_sequence: CanonicalSequence,\n tail_digest: Digest,\n producer_epoch: ThreadMaterialization.fields.producerEpoch,\n }),\n ),\n )(rows[0]),\n ),\n Effect.mapError((error) => storeError(\"native thread tail\", error)),\n ),\n }),\n );\n\n const threadStore = ThreadStore.of({\n ...(journal.lifecycle === undefined\n ? {}\n : { lifecyclePublications: journal.lifecycle.storage }),\n readIdentity: selectedReads.readIdentity,\n countPeerMessages: selectedReads.countPeerMessages,\n append,\n export: exportThread,\n inspectTail,\n materialize,\n observe,\n read,\n checkpoints: { save: saveCheckpoint, load: loadCheckpoint },\n recoveryCheckpoints: { save: saveRecoveryCheckpoint, load: loadRecoveryCheckpoint },\n });\n\n return Context.make(ThreadStore, threadStore);\n});\n\n/**\n * Durable Object Thread Store implementation with configuration, failpoint, SQL, and\n * Crypto authority kept visible in its input channel.\n */\nexport const threadStoreLayer: Layer.Layer<\n ThreadStore,\n DoStorageInitializationError,\n DoStorageConfig | DoStorageFailpoint | SqlClientService.SqlClient | Crypto.Crypto\n> = Layer.effectContext(makeServices());\n\n/**\n * Validated Durable Object storage configuration Layer with the documented defaults applied.\n * Shared by the ThreadStore and SubmissionLedger convenience layers so their defaults\n * cannot drift.\n */\nexport const storageConfigLayer = (\n options: DoStorageOptions,\n): Layer.Layer<DoStorageConfig, DoStorageError> =>\n Layer.effect(DoStorageConfig)(\n Schema.decodeEffect(DoStorageConfigValue)({\n observationPollInterval: options.observationPollInterval ?? 25,\n ownershipLeaseDuration:\n options.ownershipLeaseDuration ?? Duration.toMillis(DEFAULT_OWNERSHIP_LEASE_DURATION),\n maxStoredValueBytes: options.maxStoredValueBytes ?? DEFAULT_MAX_STORED_VALUE_BYTES,\n verifyOnOpen: options.verifyOnOpen ?? false,\n }).pipe(\n Effect.mapError((error) =>\n DoStorageError.make({\n cause: error,\n operation: \"configure Durable Object storage\",\n message: error.message,\n }),\n ),\n ),\n );\n\n/** The failpoint Layer selected by convenience options: explicit handler or the no-op default. */\nexport const storageFailpointLayer = (\n options: DoStorageOptions,\n): Layer.Layer<DoStorageFailpoint> =>\n options.failpoint === undefined\n ? DoStorageFailpoint.layer\n : Layer.succeed(DoStorageFailpoint)({ hit: options.failpoint });\n\n/**\n * A composition-root convenience Layer for canonical Threads inside one Durable Object,\n * built over `ctx.storage`. Durable accepted work is served by the separate SubmissionLedger\n * port; point both at the SAME `ctx.storage` so claims fence the same producer epochs\n * (ADR-0011 D7's \"same file\" rule, transposed to one object's private database).\n */\nexport const layer = (\n options: DoStorageOptions,\n): Layer.Layer<ThreadStore, DoStorageInitializationError> =>\n Layer.unwrap(\n Effect.map(DoStorageConfig, (config) =>\n threadStoreLayer.pipe(\n Layer.provide(\n Layer.mergeAll(\n Layer.succeed(DoStorageConfig)(config),\n storageFailpointLayer(options),\n SqliteClient.layer({ storage: options.storage }),\n BrowserCrypto.layer,\n ),\n ),\n ),\n ),\n ).pipe(Layer.provide(storageConfigLayer(options)));\n\n/**\n * Discard the Object's derived thread and ledger state after direct SQL maintenance.\n * Quiesce port operations during the raw write and invalidation, and enroll the write with\n * the host mutation gate. Ordinary ThreadStore/SubmissionLedger writes maintain this view.\n */\nexport const invalidate = invalidateOwnedState;\n\n/** Share the Object's transaction gate with owner-local SQL Memory compositions. */\nexport const sqlOwnerLayer = Layer.effect(SqlStorageOwner)(\n Effect.flatMap(SqlClientService.SqlClient, ownedState),\n);\n"],"mappings":"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"}
|