@effect-agent/storage-cloudflare 0.1.0-beta.38 → 0.1.0-beta.40

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/src/errors.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { CanonicalSequence, ProducerEpoch } from "@effect-agent/session";
1
+ import { CanonicalSequence, ProducerEpoch } from "@effect-agent/thread";
2
2
  import { Schema } from "effect";
3
3
 
4
4
  /** The Durable Object's SQLite storage uses a private-development format this adapter cannot read. */
@@ -75,7 +75,7 @@ export class DoAppendConflict extends Schema.TaggedError<DoAppendConflict>()("Do
75
75
  }) {}
76
76
 
77
77
  /**
78
- * A producer epoch does not match the Conversation's current writer registration. Appends
78
+ * A producer epoch does not match the Thread's current writer registration. Appends
79
79
  * require the exact registered epoch, so both older and newer unregistered epochs are fenced;
80
80
  * a newer epoch takes over by materializing first.
81
81
  */
@@ -109,7 +109,7 @@ export const DoStorageFailpointLocation = Schema.Literals([
109
109
  "append:after-record-insert",
110
110
  "append:after-tail-update",
111
111
  "append:after",
112
- "export:after-conversation-read",
112
+ "export:after-thread-read",
113
113
  "save-checkpoint:before",
114
114
  "save-checkpoint:after",
115
115
  "ledger:admit:before",
package/src/index.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
- * `@effect-agent/storage-cloudflare` — Durable Object SQLite adapters for the session ports
3
- * (`ConversationStore`, `SubmissionLedger`).
2
+ * `@effect-agent/storage-cloudflare` — Durable Object SQLite adapters for the thread ports
3
+ * (`ThreadStore`, `SubmissionLedger`).
4
4
  *
5
- * WP1 lands the LOCAL facets: the full port implementations against one Conversation Durable
5
+ * WP1 lands the LOCAL facets: the full port implementations against one Thread Durable
6
6
  * Object's private SQLite database, structurally mirroring the Node/SQLite adapters (same
7
7
  * tables, same failpoint-location names, same conformance suites) with the DC-specific
8
8
  * differences documented in each module — Durable Object storage-backed transactions instead
@@ -13,20 +13,21 @@
13
13
  *
14
14
  * WP2 adds the cross-Object distribution seam: `port-protocol.ts` (the Schema
15
15
  * request/response/failure envelopes for the CLOSED route-capable port subset) and
16
- * `routing.ts` (the `ConversationPortTransport` service, the routed decorator Layers over
17
- * the local facets — this-conversation → local, route-capable foreign → transport, anything
16
+ * `routing.ts` (the `ThreadPortTransport` service, the routed decorator Layers over
17
+ * the local facets — this-thread → local, route-capable foreign → transport, anything
18
18
  * else foreign → fail fast typed — and the owner-side `handleEncodedPortRequest` endpoint
19
- * body for the Conversation Object's `portCall`).
19
+ * body for the Thread Object's `portCall`).
20
20
  *
21
21
  * This package never imports the `cloudflare:workers` runtime module — Durable Object handles
22
22
  * (`ctx.storage`) are injected as Layer construction values, and `@cloudflare/workers-types`
23
23
  * stays a types-only devDependency.
24
24
  */
25
25
  export * from "./errors.ts";
26
- export * from "./migrations.ts";
27
- export * from "./do-conversation-store.ts";
26
+ export { CurrentDoStorageVersion } from "./migrations.ts";
27
+ export * from "./do-thread-store.ts";
28
28
  export * from "./do-ledger.ts";
29
29
  export * from "./do-schedule-store.ts";
30
+ export * from "./do-subscription-store.ts";
30
31
  export * from "./do-storage-config.ts";
31
32
  export * from "./do-storage-failpoint.ts";
32
33
  export * from "./port-protocol.ts";
package/src/migrations.ts CHANGED
@@ -2,35 +2,28 @@ import { SqliteMigrator } from "@effect/sql-sqlite-do";
2
2
  import { Effect } from "effect";
3
3
  import * as SqlClient from "effect/unstable/sql/SqlClient";
4
4
 
5
- /**
6
- * The exact-or-fresh storage version recorded in `effect_agent_meta`. Cloudflare is a fresh
7
- * platform, so there is exactly ONE migration carrying the complete current schema — no
8
- * v1→v4 history to replay (deployment spec §9: no rolling data-version promise during
9
- * private development).
10
- */
11
- export const CurrentDoStorageVersion = 1;
5
+ /** The current storage version recorded in `effect_agent_meta`. */
6
+ export const CurrentDoStorageVersion = 2;
12
7
 
13
8
  /**
14
- * The Conversation Durable Object schema. Table names and columns mirror the Node/SQLite v4
15
- * schema byte-for-byte (`packages/storage-sqlite/src/migrations.ts`, migrations 1–4 collapsed
16
- * into their final shape) so the shared conformance suites and crash-matrix rows address
17
- * identical durable state. Two DC-specific additions:
9
+ * The Thread Durable Object schema shares its thread and ledger tables with Node/SQLite.
10
+ * Schedules and subscriptions use separate Durable Objects. Two DC-specific additions:
18
11
  *
19
12
  * 1. `effect_agent_meta` replaces `PRAGMA user_version` as the exact-or-fresh version gate —
20
13
  * a meta table is portable regardless of which PRAGMAs Durable Object SQL storage allows.
21
14
  * 2. `effect_agent_child_settlements` is the durable cross-store notification marker the
22
15
  * SubmissionLedger port contract mandates for cross-store adapters (`suspend`'s covering
23
- * check and `recordChildSettled`'s wake both consult it): parent and child Conversations
16
+ * check and `recordChildSettled`'s wake both consult it): parent and child Threads
24
17
  * live in different Durable Objects, so a child settlement reported before the parent's
25
18
  * suspend commits must be observable from the PARENT's own storage.
26
19
  */
27
20
  export const doMigrations = SqliteMigrator.fromRecord({
28
- "1_current_cloudflare_conversation_object": Effect.gen(function* () {
21
+ "1_current_cloudflare_thread_object": Effect.gen(function* () {
29
22
  const sql = yield* SqlClient.SqlClient;
30
23
 
31
24
  yield* sql`
32
- CREATE TABLE effect_agent_conversations (
33
- conversation_id TEXT PRIMARY KEY NOT NULL,
25
+ CREATE TABLE effect_agent_threads (
26
+ thread_id TEXT PRIMARY KEY NOT NULL,
34
27
  created_at TEXT NOT NULL,
35
28
  tail_sequence INTEGER NOT NULL,
36
29
  tail_digest TEXT NOT NULL,
@@ -40,59 +33,59 @@ export const doMigrations = SqliteMigrator.fromRecord({
40
33
 
41
34
  yield* sql`
42
35
  CREATE TABLE effect_agent_canonical_batches (
43
- conversation_id TEXT NOT NULL,
36
+ thread_id TEXT NOT NULL,
44
37
  batch_id TEXT NOT NULL,
45
38
  first_sequence INTEGER NOT NULL,
46
39
  last_sequence INTEGER NOT NULL,
47
40
  batch_digest TEXT NOT NULL,
48
41
  tail_digest TEXT NOT NULL,
49
42
  batch_json TEXT NOT NULL,
50
- PRIMARY KEY (conversation_id, batch_id),
51
- FOREIGN KEY (conversation_id)
52
- REFERENCES effect_agent_conversations(conversation_id)
43
+ PRIMARY KEY (thread_id, batch_id),
44
+ FOREIGN KEY (thread_id)
45
+ REFERENCES effect_agent_threads(thread_id)
53
46
  ON DELETE RESTRICT
54
47
  )
55
48
  `.withoutTransform;
56
49
 
57
50
  yield* sql`
58
51
  CREATE TABLE effect_agent_canonical_records (
59
- conversation_id TEXT NOT NULL,
52
+ thread_id TEXT NOT NULL,
60
53
  sequence INTEGER NOT NULL,
61
54
  record_id TEXT NOT NULL,
62
55
  batch_id TEXT NOT NULL,
63
56
  record_json TEXT NOT NULL,
64
- PRIMARY KEY (conversation_id, sequence),
65
- UNIQUE (conversation_id, record_id),
66
- FOREIGN KEY (conversation_id, batch_id)
67
- REFERENCES effect_agent_canonical_batches(conversation_id, batch_id)
57
+ PRIMARY KEY (thread_id, sequence),
58
+ UNIQUE (thread_id, record_id),
59
+ FOREIGN KEY (thread_id, batch_id)
60
+ REFERENCES effect_agent_canonical_batches(thread_id, batch_id)
68
61
  ON DELETE RESTRICT
69
62
  )
70
63
  `.withoutTransform;
71
64
 
72
65
  yield* sql`
73
66
  CREATE INDEX effect_agent_canonical_records_batch
74
- ON effect_agent_canonical_records (conversation_id, batch_id, sequence)
67
+ ON effect_agent_canonical_records (thread_id, batch_id, sequence)
75
68
  `.withoutTransform;
76
69
 
77
70
  yield* sql`
78
71
  CREATE TABLE effect_agent_checkpoints (
79
- conversation_id TEXT NOT NULL,
72
+ thread_id TEXT NOT NULL,
80
73
  through_sequence INTEGER NOT NULL,
81
74
  tail_digest TEXT NOT NULL,
82
75
  checkpoint_json TEXT NOT NULL,
83
- PRIMARY KEY (conversation_id, through_sequence),
84
- FOREIGN KEY (conversation_id)
85
- REFERENCES effect_agent_conversations(conversation_id)
76
+ PRIMARY KEY (thread_id, through_sequence),
77
+ FOREIGN KEY (thread_id)
78
+ REFERENCES effect_agent_threads(thread_id)
86
79
  ON DELETE RESTRICT
87
80
  )
88
81
  `.withoutTransform;
89
82
 
90
- // Admission rows exist before Conversation materialization (durability §4), so
91
- // conversation_id intentionally carries no foreign key into effect_agent_conversations.
83
+ // Admission rows exist before Thread materialization (durability §4), so
84
+ // thread_id intentionally carries no foreign key into effect_agent_threads.
92
85
  yield* sql`
93
86
  CREATE TABLE effect_agent_submissions (
94
87
  submission_id TEXT PRIMARY KEY NOT NULL,
95
- conversation_id TEXT NOT NULL,
88
+ thread_id TEXT NOT NULL,
96
89
  queue_sequence INTEGER NOT NULL,
97
90
  principal TEXT NOT NULL,
98
91
  idempotency_key TEXT NOT NULL,
@@ -115,8 +108,8 @@ export const doMigrations = SqliteMigrator.fromRecord({
115
108
  unknown_tool_call_ids_json TEXT,
116
109
  parent_submission_id TEXT,
117
110
  parent_tool_call_id TEXT,
118
- UNIQUE (conversation_id, principal, idempotency_key),
119
- UNIQUE (conversation_id, queue_sequence)
111
+ UNIQUE (thread_id, principal, idempotency_key),
112
+ UNIQUE (thread_id, queue_sequence)
120
113
  )
121
114
  `.withoutTransform;
122
115
 
@@ -148,7 +141,7 @@ export const doMigrations = SqliteMigrator.fromRecord({
148
141
  CREATE TABLE effect_agent_attempts (
149
142
  attempt_id TEXT PRIMARY KEY NOT NULL,
150
143
  submission_id TEXT NOT NULL,
151
- conversation_id TEXT NOT NULL,
144
+ thread_id TEXT NOT NULL,
152
145
  owner_producer_id TEXT NOT NULL,
153
146
  producer_epoch INTEGER NOT NULL,
154
147
  claimed_at TEXT NOT NULL,
@@ -10,14 +10,14 @@ import {
10
10
  CanonicalRecordEnvelope,
11
11
  ChildSettledNotification,
12
12
  ChildSettledOutcome,
13
- ConversationExport,
14
- ConversationExportRequest,
15
- ConversationMaterialization,
16
- ConversationNotMaterialized,
17
- ConversationRead,
18
- ConversationStoreError,
19
- ConversationTail,
20
- ConversationTailRequest,
13
+ ThreadExport,
14
+ ThreadExportRequest,
15
+ ThreadMaterialization,
16
+ ThreadNotMaterialized,
17
+ ThreadRead,
18
+ ThreadStoreError,
19
+ ThreadTail,
20
+ ThreadTailRequest,
21
21
  FenceRejected,
22
22
  FencedAppendRequest,
23
23
  JoinedToHost,
@@ -27,20 +27,20 @@ import {
27
27
  SubmissionLookup,
28
28
  SubmissionLookupByKey,
29
29
  SubmissionSnapshot,
30
- } from "@effect-agent/session";
30
+ } from "@effect-agent/thread";
31
31
  import { Schema } from "effect";
32
32
 
33
33
  /**
34
34
  * The cross-Durable-Object port protocol (plan §1.3, D-P6-3): Schema request/response/error
35
- * envelopes for the CLOSED route-capable subset of the session ports. One Conversation's
36
- * Durable Object executes another Conversation's request against its OWN local facets; the
35
+ * envelopes for the CLOSED route-capable subset of the thread ports. One Thread's
36
+ * Durable Object executes another Thread's request against its OWN local facets; the
37
37
  * envelopes here are the only values that cross the Object boundary, and they are
38
38
  * transport-agnostic — native Durable Object JS RPC is the shipped carrier, fetch-with-JSON
39
39
  * the documented fallback, and both move the same Schema-encoded JSON.
40
40
  *
41
41
  * The closed subset is exactly the set of operations the durable coordinator performs against
42
- * a FOREIGN Conversation (parent/child establishment, status checks, abort propagation,
43
- * child-settlement notification, and the child-conversation store operations used by
42
+ * a FOREIGN Thread (parent/child establishment, status checks, abort propagation,
43
+ * child-settlement notification, and the child-thread store operations used by
44
44
  * establishment, `verifySettledChild`, and result projection):
45
45
  *
46
46
  * - ledger: `admit`, `markReady`, `lookup`, `resolveAdmission`, `requestAbort`,
@@ -53,7 +53,7 @@ import { Schema } from "effect";
53
53
  *
54
54
  * Failures cross the boundary as the `PortFailure` union and re-decode on the caller side to
55
55
  * the SAME tagged error types the local facet would have produced, so routed calls keep
56
- * error-tag fidelity. `cause` chains inside `LedgerError`/`ConversationStoreError` travel as
56
+ * error-tag fidelity. `cause` chains inside `LedgerError`/`ThreadStoreError` travel as
57
57
  * Schema defects and do not claim instance fidelity across Objects (plan §2.8).
58
58
  */
59
59
 
@@ -71,7 +71,7 @@ export const boundPortDiagnostic = (value: string): string =>
71
71
  /**
72
72
  * The envelope itself could not be honored: the receiving Object could not decode the
73
73
  * request, or a response could not be encoded/decoded. It never carries port semantics —
74
- * callers fold it into the operation's base error (`LedgerError`/`ConversationStoreError`),
74
+ * callers fold it into the operation's base error (`LedgerError`/`ThreadStoreError`),
75
75
  * except `resolveAdmission`, which folds it into `AdmissionIndeterminate` because a
76
76
  * non-answer is never proof of absence (SUB-031).
77
77
  */
@@ -128,39 +128,39 @@ export class LedgerRecordChildSettledCall extends Schema.TaggedClass<LedgerRecor
128
128
  request: ChildSettledNotification,
129
129
  }) {}
130
130
 
131
- /** Routed `ConversationStore.materialize` against the owning Object. */
131
+ /** Routed `ThreadStore.materialize` against the owning Object. */
132
132
  export class StoreMaterializeCall extends Schema.TaggedClass<StoreMaterializeCall>(
133
133
  "@effect-agent/storage-cloudflare/StoreMaterializeCall",
134
134
  )("StoreMaterialize", {
135
- request: ConversationMaterialization,
135
+ request: ThreadMaterialization,
136
136
  }) {}
137
137
 
138
- /** Routed `ConversationStore.append` against the owning Object. */
138
+ /** Routed `ThreadStore.append` against the owning Object. */
139
139
  export class StoreAppendCall extends Schema.TaggedClass<StoreAppendCall>(
140
140
  "@effect-agent/storage-cloudflare/StoreAppendCall",
141
141
  )("StoreAppend", {
142
142
  request: FencedAppendRequest,
143
143
  }) {}
144
144
 
145
- /** Routed one-page `ConversationStore.read`; the page bound is the request's own `limit`. */
145
+ /** Routed one-page `ThreadStore.read`; the page bound is the request's own `limit`. */
146
146
  export class StoreReadPageCall extends Schema.TaggedClass<StoreReadPageCall>(
147
147
  "@effect-agent/storage-cloudflare/StoreReadPageCall",
148
148
  )("StoreReadPage", {
149
- request: ConversationRead,
149
+ request: ThreadRead,
150
150
  }) {}
151
151
 
152
- /** Routed `ConversationStore.inspectTail` against the owning Object. */
152
+ /** Routed `ThreadStore.inspectTail` against the owning Object. */
153
153
  export class StoreInspectTailCall extends Schema.TaggedClass<StoreInspectTailCall>(
154
154
  "@effect-agent/storage-cloudflare/StoreInspectTailCall",
155
155
  )("StoreInspectTail", {
156
- request: ConversationTailRequest,
156
+ request: ThreadTailRequest,
157
157
  }) {}
158
158
 
159
- /** Routed `ConversationStore.export` against the owning Object. */
159
+ /** Routed `ThreadStore.export` against the owning Object. */
160
160
  export class StoreExportCall extends Schema.TaggedClass<StoreExportCall>(
161
161
  "@effect-agent/storage-cloudflare/StoreExportCall",
162
162
  )("StoreExport", {
163
- request: ConversationExportRequest,
163
+ request: ThreadExportRequest,
164
164
  }) {}
165
165
 
166
166
  /** Every request that may cross a Durable Object boundary — the CLOSED route-capable subset. */
@@ -241,13 +241,13 @@ export class StoreReadPageResult extends Schema.TaggedClass<StoreReadPageResult>
241
241
  export class StoreInspectTailResult extends Schema.TaggedClass<StoreInspectTailResult>(
242
242
  "@effect-agent/storage-cloudflare/StoreInspectTailResult",
243
243
  )("StoreInspectTailResult", {
244
- tail: ConversationTail,
244
+ tail: ThreadTail,
245
245
  }) {}
246
246
 
247
247
  export class StoreExportResult extends Schema.TaggedClass<StoreExportResult>(
248
248
  "@effect-agent/storage-cloudflare/StoreExportResult",
249
249
  )("StoreExportResult", {
250
- export: ConversationExport,
250
+ export: ThreadExport,
251
251
  }) {}
252
252
 
253
253
  /** Every successful routed result. Callers narrow by the tag their request implies. */
@@ -273,15 +273,15 @@ export type PortResult = typeof PortResult.Type;
273
273
  /**
274
274
  * Every typed failure a route-capable operation can produce on its owning Object, plus the
275
275
  * protocol's own `PortProtocolError`. Members re-decode to the SAME tagged classes the
276
- * session ports declare, so a routed caller observes identical error tags and fields.
276
+ * thread ports declare, so a routed caller observes identical error tags and fields.
277
277
  */
278
278
  export const PortFailure = Schema.Union([
279
279
  AdmissionConflict,
280
280
  SettlementConflict,
281
281
  JoinedToHost,
282
282
  LedgerError,
283
- ConversationStoreError,
284
- ConversationNotMaterialized,
283
+ ThreadStoreError,
284
+ ThreadNotMaterialized,
285
285
  AppendConflict,
286
286
  FenceRejected,
287
287
  PortProtocolError,