@effect-agent/platform-cloudflare 0.1.0-beta.9 → 0.1.0-beta.91

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.
Files changed (100) hide show
  1. package/dist/Alarm.d.mts +188 -0
  2. package/dist/Alarm.mjs +451 -0
  3. package/dist/Alarm.mjs.map +1 -0
  4. package/dist/BrowserRestCapture.d.mts +35 -0
  5. package/dist/BrowserRestCapture.mjs +238 -0
  6. package/dist/BrowserRestCapture.mjs.map +1 -0
  7. package/dist/BrowserRestCrawl.d.mts +17 -0
  8. package/dist/BrowserRestCrawl.mjs +244 -0
  9. package/dist/BrowserRestCrawl.mjs.map +1 -0
  10. package/dist/CloudflareAiGateway.d.mts +64 -0
  11. package/dist/CloudflareAiGateway.mjs +70 -0
  12. package/dist/CloudflareAiGateway.mjs.map +1 -0
  13. package/dist/CloudflareBindings.d.mts +115 -0
  14. package/dist/CloudflareBindings.mjs +113 -0
  15. package/dist/CloudflareBindings.mjs.map +1 -0
  16. package/dist/CloudflareBrowser-DV6kya1H.mjs +495 -0
  17. package/dist/CloudflareBrowser-DV6kya1H.mjs.map +1 -0
  18. package/dist/CloudflareBrowser-Doe1M7R5.d.mts +80 -0
  19. package/dist/CloudflareBrowser.d.mts +2 -0
  20. package/dist/CloudflareBrowser.mjs +2 -0
  21. package/dist/CloudflareCodeMode.d.mts +44 -0
  22. package/dist/CloudflareCodeMode.mjs +616 -0
  23. package/dist/CloudflareCodeMode.mjs.map +1 -0
  24. package/dist/CloudflareConfig-f3CqTel1.d.mts +101 -0
  25. package/dist/CloudflareConfig.d.mts +2 -0
  26. package/dist/CloudflareConfig.mjs +122 -0
  27. package/dist/CloudflareConfig.mjs.map +1 -0
  28. package/dist/CloudflareMemory.d.mts +142 -0
  29. package/dist/CloudflareMemory.mjs +202 -0
  30. package/dist/CloudflareMemory.mjs.map +1 -0
  31. package/dist/CloudflareScheduling.d.mts +52 -0
  32. package/dist/CloudflareScheduling.mjs +396 -0
  33. package/dist/CloudflareScheduling.mjs.map +1 -0
  34. package/dist/CloudflareSubscriptions.d.mts +87 -0
  35. package/dist/CloudflareSubscriptions.mjs +530 -0
  36. package/dist/CloudflareSubscriptions.mjs.map +1 -0
  37. package/dist/CloudflareThreadClient.d.mts +1496 -0
  38. package/dist/CloudflareThreadClient.mjs +382 -0
  39. package/dist/CloudflareThreadClient.mjs.map +1 -0
  40. package/dist/InteractiveBrowser-DUE_m12-.d.mts +161 -0
  41. package/dist/InteractiveBrowser-DupDtfw2.mjs +1169 -0
  42. package/dist/InteractiveBrowser-DupDtfw2.mjs.map +1 -0
  43. package/dist/InteractiveBrowser.d.mts +2 -0
  44. package/dist/InteractiveBrowser.mjs +2 -0
  45. package/dist/ProtectedBrowser.d.mts +123 -0
  46. package/dist/ProtectedBrowser.mjs +1135 -0
  47. package/dist/ProtectedBrowser.mjs.map +1 -0
  48. package/dist/ThreadObject-CIbmXZCY.d.mts +812 -0
  49. package/dist/ThreadObject-DvRG0dDz.mjs +835 -0
  50. package/dist/ThreadObject-DvRG0dDz.mjs.map +1 -0
  51. package/dist/ThreadObject.d.mts +2 -0
  52. package/dist/ThreadObject.mjs +3 -0
  53. package/dist/WakeScheduler.d.mts +23 -0
  54. package/dist/WakeScheduler.mjs +57 -0
  55. package/dist/WakeScheduler.mjs.map +1 -0
  56. package/dist/boundary-BguazVkh.mjs +42 -0
  57. package/dist/boundary-BguazVkh.mjs.map +1 -0
  58. package/dist/index.d.mts +13 -1548
  59. package/dist/index.mjs +13 -1636
  60. package/dist/prepared-admission-DU0_T-ev.mjs +73 -0
  61. package/dist/prepared-admission-DU0_T-ev.mjs.map +1 -0
  62. package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
  63. package/package.json +1 -53
  64. package/src/Alarm.ts +973 -0
  65. package/src/BrowserRestCapture.ts +477 -0
  66. package/src/BrowserRestCrawl.ts +540 -0
  67. package/src/CloudflareAiGateway.ts +170 -0
  68. package/src/CloudflareBindings.ts +199 -0
  69. package/src/CloudflareBrowser.ts +15 -0
  70. package/src/{code-mode-executor.ts → CloudflareCodeMode.ts} +372 -204
  71. package/src/{config.ts → CloudflareConfig.ts} +9 -8
  72. package/src/CloudflareMemory.ts +420 -0
  73. package/src/CloudflareScheduling.ts +747 -0
  74. package/src/CloudflareSubscriptions.ts +1041 -0
  75. package/src/CloudflareThreadClient.ts +809 -0
  76. package/src/InteractiveBrowser.ts +2354 -0
  77. package/src/ProtectedBrowser.ts +9 -0
  78. package/src/ThreadObject.ts +1179 -0
  79. package/src/{wake-scheduler.ts → WakeScheduler.ts} +32 -26
  80. package/src/index.ts +12 -23
  81. package/src/internal/boundary.ts +55 -0
  82. package/src/internal/browser-quick-action.ts +857 -0
  83. package/src/internal/browser-session-lifecycle.ts +160 -0
  84. package/src/internal/layers.ts +751 -0
  85. package/src/internal/message-delivery.ts +152 -0
  86. package/src/internal/prepared-admission.ts +116 -0
  87. package/src/internal/progress-wait.ts +121 -0
  88. package/src/internal/transport.ts +44 -0
  89. package/src/protected-browser/binding.ts +313 -0
  90. package/src/protected-browser/host.ts +344 -0
  91. package/src/protected-browser/inspect-frame.ts +125 -0
  92. package/src/protected-browser/native.ts +445 -0
  93. package/src/protected-browser/policy.ts +821 -0
  94. package/dist/index.mjs.map +0 -1
  95. package/src/alarm.ts +0 -334
  96. package/src/bindings.ts +0 -145
  97. package/src/client.ts +0 -646
  98. package/src/conversation-object.ts +0 -768
  99. package/src/layers.ts +0 -376
  100. package/src/transport.ts +0 -38
package/src/client.ts DELETED
@@ -1,646 +0,0 @@
1
- import { AgentId, AgentInputError, type ConversationId } from "@effect-agent/core";
2
- import {
3
- AbortCommand,
4
- AbortIntent,
5
- AdmissionConflict,
6
- AppendConflict,
7
- ApprovalConflict,
8
- ApprovalDecisionCommand,
9
- ApprovalDecisionIntent,
10
- CanonicalRecordEnvelope,
11
- CanonicalSequence,
12
- ConversationNotMaterialized,
13
- ConversationStoreError,
14
- DefinitionDigests,
15
- DigestError,
16
- DurableRuntimeFailpointError,
17
- FenceRejected,
18
- IdempotencyKey,
19
- JoinedToHost,
20
- LedgerError,
21
- PersistedJson,
22
- Principal,
23
- Receipt,
24
- Settlement,
25
- SettlementConflict,
26
- UnknownResolutionCommand,
27
- UnknownResolutionConflict,
28
- UnknownResolutionIntent,
29
- type DurableSubmitAgent,
30
- type DurableSubmitOptions,
31
- } from "@effect-agent/session";
32
- import { Context, Effect, Layer, Schema } from "effect";
33
-
34
- import { DurableAlarmError } from "./alarm.ts";
35
- import { ConversationObjectNamespace, type ConversationObjectRpc } from "./bindings.ts";
36
- import { AdmissionLimitExceeded } from "./config.ts";
37
-
38
- /**
39
- * The Worker↔Conversation-Object host protocol (plan §1.4): Schema envelopes for the host
40
- * entry points (`submitEncoded`, `awaitSettlementEncoded`, `observePage`, `abortEncoded`,
41
- * `resolveApprovalEncoded`, `resolveUnknownEncoded`) plus the Worker-side client that speaks
42
- * it. Mirrors the WP2 port protocol: requests and responses are closed Schema unions, typed
43
- * failures travel as their own tagged classes and RE-DECODE to identical tags on the caller
44
- * (error-tag fidelity), and protocol anomalies are answered typed instead of thrown.
45
- */
46
-
47
- /** Ceiling for host protocol diagnostic strings. */
48
- const MAX_HOST_DIAGNOSTIC_LENGTH = 4_096;
49
-
50
- const BoundedDiagnostic = Schema.String.check(Schema.isMaxLength(MAX_HOST_DIAGNOSTIC_LENGTH));
51
-
52
- /** Truncate a diagnostic string to the host protocol's bounded length. */
53
- export const boundHostDiagnostic = (value: string): string =>
54
- value.length > MAX_HOST_DIAGNOSTIC_LENGTH
55
- ? `${value.slice(0, MAX_HOST_DIAGNOSTIC_LENGTH - 3)}...`
56
- : value;
57
-
58
- /**
59
- * The envelope itself could not be honored: the Object could not decode the request, or a
60
- * response could not be encoded/decoded. Never carries operation semantics.
61
- */
62
- export class HostProtocolError extends Schema.TaggedError<HostProtocolError>()(
63
- "HostProtocolError",
64
- {
65
- message: BoundedDiagnostic,
66
- },
67
- ) {}
68
-
69
- /** The Worker-side stub call itself failed (RPC rejection, overload, eviction mid-call). */
70
- export class ConversationClientError extends Schema.TaggedError<ConversationClientError>()(
71
- "ConversationClientError",
72
- {
73
- conversationId: Schema.String,
74
- message: Schema.String,
75
- cause: Schema.optionalKey(Schema.Defect()),
76
- },
77
- ) {}
78
-
79
- // ---------------------------------------------------------------------------
80
- // Requests
81
- // ---------------------------------------------------------------------------
82
-
83
- /**
84
- * One durable submission, input ALREADY encoded by the caller through the Agent Binding's
85
- * input schema (the Worker bundles the same Agent definitions as the Object, so schema
86
- * validation happens client-side; the resolved Binding re-validates at claim time). The
87
- * Conversation identity is deliberately absent — the addressed Object IS the lane.
88
- */
89
- export class SubmitRequest extends Schema.Class<SubmitRequest>(
90
- "@effect-agent/platform-cloudflare/SubmitRequest",
91
- )({
92
- agentId: AgentId,
93
- principal: Principal,
94
- idempotencyKey: IdempotencyKey,
95
- definitions: DefinitionDigests,
96
- inputPayload: PersistedJson,
97
- }) {}
98
-
99
- /** One bounded page of canonical records after an optional sequence. */
100
- export class ObservePageRequest extends Schema.Class<ObservePageRequest>(
101
- "@effect-agent/platform-cloudflare/ObservePageRequest",
102
- )({
103
- afterSequence: Schema.optionalKey(CanonicalSequence),
104
- limit: Schema.Int.check(Schema.isGreaterThan(0), Schema.isLessThanOrEqualTo(1_024)),
105
- }) {}
106
-
107
- // ---------------------------------------------------------------------------
108
- // Responses
109
- // ---------------------------------------------------------------------------
110
-
111
- /**
112
- * Every typed failure a host entry point can produce, plus the protocol's own errors. Same
113
- * closed-union discipline as the WP2 `PortFailure`: members re-decode to the SAME tagged
114
- * classes on the Worker side; `cause` chains travel as Schema defects without instance
115
- * fidelity (plan §2.8).
116
- */
117
- export const HostFailure = Schema.Union([
118
- AgentInputError,
119
- DigestError,
120
- AdmissionConflict,
121
- SettlementConflict,
122
- ApprovalConflict,
123
- UnknownResolutionConflict,
124
- JoinedToHost,
125
- LedgerError,
126
- ConversationStoreError,
127
- ConversationNotMaterialized,
128
- AppendConflict,
129
- FenceRejected,
130
- DurableRuntimeFailpointError,
131
- AdmissionLimitExceeded,
132
- DurableAlarmError,
133
- HostProtocolError,
134
- ]);
135
- export type HostFailure = typeof HostFailure.Type;
136
-
137
- export class SubmitSucceeded extends Schema.TaggedClass<SubmitSucceeded>(
138
- "@effect-agent/platform-cloudflare/SubmitSucceeded",
139
- )("SubmitSucceeded", {
140
- receipt: Receipt,
141
- }) {}
142
-
143
- export class SettlementReached extends Schema.TaggedClass<SettlementReached>(
144
- "@effect-agent/platform-cloudflare/SettlementReached",
145
- )("SettlementReached", {
146
- settlement: Settlement,
147
- }) {}
148
-
149
- export class ObservedPage extends Schema.TaggedClass<ObservedPage>(
150
- "@effect-agent/platform-cloudflare/ObservedPage",
151
- )("ObservedPage", {
152
- records: Schema.Array(CanonicalRecordEnvelope).check(Schema.isMaxLength(1_024)),
153
- }) {}
154
-
155
- export class AbortRecorded extends Schema.TaggedClass<AbortRecorded>(
156
- "@effect-agent/platform-cloudflare/AbortRecorded",
157
- )("AbortRecorded", {
158
- intent: AbortIntent,
159
- }) {}
160
-
161
- export class ApprovalRecorded extends Schema.TaggedClass<ApprovalRecorded>(
162
- "@effect-agent/platform-cloudflare/ApprovalRecorded",
163
- )("ApprovalRecorded", {
164
- intent: ApprovalDecisionIntent,
165
- }) {}
166
-
167
- export class UnknownResolutionRecorded extends Schema.TaggedClass<UnknownResolutionRecorded>(
168
- "@effect-agent/platform-cloudflare/UnknownResolutionRecorded",
169
- )("UnknownResolutionRecorded", {
170
- intent: UnknownResolutionIntent,
171
- }) {}
172
-
173
- /** The entry point failed TYPED on the Object; the failure re-decodes verbatim. */
174
- export class HostFailed extends Schema.TaggedClass<HostFailed>(
175
- "@effect-agent/platform-cloudflare/HostFailed",
176
- )("HostFailed", {
177
- failure: HostFailure,
178
- }) {}
179
-
180
- /** The uniform answer of one host entry point. Callers narrow by the tag their call implies. */
181
- export const HostResponse = Schema.Union([
182
- SubmitSucceeded,
183
- SettlementReached,
184
- ObservedPage,
185
- AbortRecorded,
186
- ApprovalRecorded,
187
- UnknownResolutionRecorded,
188
- HostFailed,
189
- ]);
190
- export type HostResponse = typeof HostResponse.Type;
191
-
192
- // ---------------------------------------------------------------------------
193
- // Codecs (shared by the Object endpoints and the Worker client)
194
- // ---------------------------------------------------------------------------
195
-
196
- export const decodeSubmitRequest = Schema.decodeUnknownEffect(SubmitRequest);
197
- export const encodeSubmitRequest = Schema.encodeEffect(SubmitRequest);
198
- export const decodeReceipt = Schema.decodeUnknownEffect(Receipt);
199
- export const encodeReceipt = Schema.encodeEffect(Receipt);
200
- export const decodeObservePageRequest = Schema.decodeUnknownEffect(ObservePageRequest);
201
- export const encodeObservePageRequest = Schema.encodeEffect(ObservePageRequest);
202
- export const decodeAbortCommand = Schema.decodeUnknownEffect(AbortCommand);
203
- export const encodeAbortCommand = Schema.encodeEffect(AbortCommand);
204
- export const decodeApprovalDecisionCommand = Schema.decodeUnknownEffect(ApprovalDecisionCommand);
205
- export const encodeApprovalDecisionCommand = Schema.encodeEffect(ApprovalDecisionCommand);
206
- export const decodeUnknownResolutionCommand = Schema.decodeUnknownEffect(UnknownResolutionCommand);
207
- export const encodeUnknownResolutionCommand = Schema.encodeEffect(UnknownResolutionCommand);
208
- export const encodeHostResponse = Schema.encodeEffect(HostResponse);
209
- export const decodeHostResponse = Schema.decodeUnknownEffect(HostResponse);
210
-
211
- // ---------------------------------------------------------------------------
212
- // Worker-side client
213
- // ---------------------------------------------------------------------------
214
-
215
- /** Failure surface of `CloudflareConversationClient.submit`. */
216
- export type ClientSubmitFailure =
217
- | AgentInputError
218
- | DigestError
219
- | AdmissionConflict
220
- | LedgerError
221
- | ConversationStoreError
222
- | ConversationNotMaterialized
223
- | AppendConflict
224
- | FenceRejected
225
- | DurableRuntimeFailpointError
226
- | AdmissionLimitExceeded
227
- | DurableAlarmError
228
- | HostProtocolError
229
- | ConversationClientError;
230
-
231
- export type ClientAwaitFailure =
232
- | LedgerError
233
- | SettlementConflict
234
- | HostProtocolError
235
- | ConversationClientError;
236
-
237
- export type ClientObserveFailure =
238
- | ConversationStoreError
239
- | ConversationNotMaterialized
240
- | HostProtocolError
241
- | ConversationClientError;
242
-
243
- export type ClientAbortFailure =
244
- | LedgerError
245
- | SettlementConflict
246
- | JoinedToHost
247
- | DurableRuntimeFailpointError
248
- | DurableAlarmError
249
- | HostProtocolError
250
- | ConversationClientError;
251
-
252
- export type ClientApprovalFailure =
253
- | LedgerError
254
- | SettlementConflict
255
- | ApprovalConflict
256
- | DurableAlarmError
257
- | HostProtocolError
258
- | ConversationClientError;
259
-
260
- export type ClientUnknownFailure =
261
- | LedgerError
262
- | SettlementConflict
263
- | UnknownResolutionConflict
264
- | JoinedToHost
265
- | DurableRuntimeFailpointError
266
- | DurableAlarmError
267
- | HostProtocolError
268
- | ConversationClientError;
269
-
270
- const SUBMIT_FAILURE_TAGS: ReadonlySet<string> = new Set([
271
- "AgentInputError",
272
- "DigestError",
273
- "AdmissionConflict",
274
- "LedgerError",
275
- "ConversationStoreError",
276
- "ConversationNotMaterialized",
277
- "AppendConflict",
278
- "FenceRejected",
279
- "DurableRuntimeFailpointError",
280
- "AdmissionLimitExceeded",
281
- "DurableAlarmError",
282
- "HostProtocolError",
283
- ]);
284
- const AWAIT_FAILURE_TAGS: ReadonlySet<string> = new Set([
285
- "LedgerError",
286
- "SettlementConflict",
287
- "HostProtocolError",
288
- ]);
289
- const OBSERVE_FAILURE_TAGS: ReadonlySet<string> = new Set([
290
- "ConversationStoreError",
291
- "ConversationNotMaterialized",
292
- "HostProtocolError",
293
- ]);
294
- const ABORT_FAILURE_TAGS: ReadonlySet<string> = new Set([
295
- "LedgerError",
296
- "SettlementConflict",
297
- "JoinedToHost",
298
- "DurableRuntimeFailpointError",
299
- "DurableAlarmError",
300
- "HostProtocolError",
301
- ]);
302
- const APPROVAL_FAILURE_TAGS: ReadonlySet<string> = new Set([
303
- "LedgerError",
304
- "SettlementConflict",
305
- "ApprovalConflict",
306
- "DurableAlarmError",
307
- "HostProtocolError",
308
- ]);
309
- const UNKNOWN_FAILURE_TAGS: ReadonlySet<string> = new Set([
310
- "LedgerError",
311
- "SettlementConflict",
312
- "UnknownResolutionConflict",
313
- "JoinedToHost",
314
- "DurableRuntimeFailpointError",
315
- "DurableAlarmError",
316
- "HostProtocolError",
317
- ]);
318
-
319
- const outOfContract = (
320
- conversationId: string,
321
- operation: string,
322
- observed: string,
323
- ): ConversationClientError =>
324
- ConversationClientError.make({
325
- conversationId,
326
- message: boundHostDiagnostic(
327
- `The Conversation Object answered ${operation} with the out-of-contract ${observed}.`,
328
- ),
329
- });
330
-
331
- /**
332
- * Narrow one decoded `HostFailed.failure` to the operation's declared failure family; an
333
- * out-of-contract tag folds into `ConversationClientError` instead of being erased or
334
- * re-thrown raw (the WP2 discipline). The predicate is the single documented narrowing over
335
- * the closed `HostFailure` union.
336
- */
337
- const narrowFailure =
338
- <Failure extends HostFailure>(tags: ReadonlySet<string>) =>
339
- (failure: HostFailure): failure is Failure =>
340
- tags.has(failure._tag);
341
-
342
- /** Worker-side client over the Conversation Object namespace (DEPLOY-010). */
343
- export class CloudflareConversationClient extends Context.Service<
344
- CloudflareConversationClient,
345
- {
346
- /** Encode the input client-side, then durably submit to the owning Object. */
347
- readonly submit: <InputSchema extends Schema.Top>(
348
- agent: DurableSubmitAgent<InputSchema>,
349
- input: InputSchema["Type"],
350
- options: DurableSubmitOptions,
351
- ) => Effect.Effect<Receipt, ClientSubmitFailure, InputSchema["EncodingServices"]>;
352
- /** Wake-hinted, poll-guaranteed settlement wait executed inside the owning Object. */
353
- readonly awaitSettlement: (receipt: Receipt) => Effect.Effect<Settlement, ClientAwaitFailure>;
354
- /** One bounded page of canonical records. */
355
- readonly readPage: (
356
- conversationId: ConversationId,
357
- options?: {
358
- readonly afterSequence?: CanonicalSequence | undefined;
359
- readonly limit?: number | undefined;
360
- },
361
- ) => Effect.Effect<ReadonlyArray<CanonicalRecordEnvelope>, ClientObserveFailure>;
362
- /**
363
- * Every canonical record up to the CURRENT committed tail, via repeated pages. A
364
- * snapshot read, not a live observation — callers wanting liveness re-read after
365
- * `awaitSettlement`.
366
- */
367
- readonly readAll: (
368
- conversationId: ConversationId,
369
- ) => Effect.Effect<ReadonlyArray<CanonicalRecordEnvelope>, ClientObserveFailure>;
370
- /**
371
- * Submission-addressed operations take the owning Conversation explicitly (from the
372
- * Receipt): minted Submission identities stay OPAQUE outside the storage adapter that
373
- * minted them (D-P6-5), so the client never parses one to find the lane.
374
- */
375
- readonly abort: (
376
- conversationId: ConversationId,
377
- command: AbortCommand,
378
- ) => Effect.Effect<AbortIntent, ClientAbortFailure>;
379
- readonly resolveApproval: (
380
- conversationId: ConversationId,
381
- command: ApprovalDecisionCommand,
382
- ) => Effect.Effect<ApprovalDecisionIntent, ClientApprovalFailure>;
383
- readonly resolveUnknown: (
384
- conversationId: ConversationId,
385
- command: UnknownResolutionCommand,
386
- ) => Effect.Effect<UnknownResolutionIntent, ClientUnknownFailure>;
387
- }
388
- >()("@effect-agent/platform-cloudflare/CloudflareConversationClient") {
389
- static readonly layer: Layer.Layer<
390
- CloudflareConversationClient,
391
- never,
392
- ConversationObjectNamespace
393
- > = Layer.effect(CloudflareConversationClient)(
394
- Effect.gen(function* () {
395
- const { namespace } = yield* ConversationObjectNamespace;
396
-
397
- const call = (
398
- conversationId: string,
399
- operation: string,
400
- invoke: (stub: DurableObjectStub<ConversationObjectRpc>) => Promise<unknown>,
401
- ): Effect.Effect<HostResponse, ConversationClientError | HostProtocolError> =>
402
- Effect.tryPromise({
403
- try: () => invoke(namespace.get(namespace.idFromName(conversationId))),
404
- catch: (cause) =>
405
- ConversationClientError.make({
406
- conversationId,
407
- message: boundHostDiagnostic(
408
- `${operation} did not reach the Conversation Object: ${
409
- cause instanceof Error ? cause.message : String(cause)
410
- }`,
411
- ),
412
- cause,
413
- }),
414
- }).pipe(
415
- Effect.flatMap((raw) =>
416
- decodeHostResponse(raw).pipe(
417
- Effect.mapError(
418
- (error): HostProtocolError =>
419
- HostProtocolError.make({
420
- message: boundHostDiagnostic(
421
- `The ${operation} answer could not be decoded: ${error.message}`,
422
- ),
423
- }),
424
- ),
425
- ),
426
- ),
427
- Effect.withSpan("CloudflareConversationClient.call", {
428
- attributes: { conversationId, operation },
429
- }),
430
- );
431
-
432
- const expect = <
433
- Result extends Exclude<HostResponse, HostFailed>,
434
- Failure extends HostFailure,
435
- >(
436
- conversationId: string,
437
- operation: string,
438
- resultTag: Result["_tag"],
439
- tags: ReadonlySet<string>,
440
- ) => {
441
- const isExpected = narrowFailure<Failure>(tags);
442
- return (
443
- response: HostResponse,
444
- ): Effect.Effect<Result, Failure | ConversationClientError> => {
445
- if (response._tag === "HostFailed") {
446
- const failure = response.failure;
447
- return isExpected(failure)
448
- ? Effect.fail(failure)
449
- : Effect.fail(outOfContract(conversationId, operation, `failure ${failure._tag}`));
450
- }
451
- if (response._tag !== resultTag) {
452
- return Effect.fail(outOfContract(conversationId, operation, `result ${response._tag}`));
453
- }
454
- return Effect.succeed(response as Result);
455
- };
456
- };
457
-
458
- const readPage = (
459
- conversationId: ConversationId,
460
- options?: {
461
- readonly afterSequence?: CanonicalSequence | undefined;
462
- readonly limit?: number | undefined;
463
- },
464
- ) =>
465
- Effect.gen(function* () {
466
- const request = ObservePageRequest.make({
467
- ...(options?.afterSequence === undefined
468
- ? {}
469
- : { afterSequence: options.afterSequence }),
470
- limit: options?.limit ?? 256,
471
- });
472
- const encoded = yield* encodeObservePageRequest(request).pipe(
473
- Effect.mapError((error) =>
474
- HostProtocolError.make({
475
- message: boundHostDiagnostic(`observePage request encode failed: ${error.message}`),
476
- }),
477
- ),
478
- );
479
- const response = yield* call(conversationId, "observePage", (stub) =>
480
- stub.observePage(encoded),
481
- );
482
- const page = yield* expect<ObservedPage, ClientObserveFailure & HostFailure>(
483
- conversationId,
484
- "observePage",
485
- "ObservedPage",
486
- OBSERVE_FAILURE_TAGS,
487
- )(response);
488
- return page.records;
489
- });
490
-
491
- return CloudflareConversationClient.of({
492
- submit: <InputSchema extends Schema.Top>(
493
- agent: DurableSubmitAgent<InputSchema>,
494
- input: InputSchema["Type"],
495
- options: DurableSubmitOptions,
496
- ) =>
497
- Effect.gen(function* () {
498
- // Client-side half of `DurableAgentRuntime.submit`'s input boundary: encode
499
- // through the Agent's input schema and prove the canonical persistence bounds.
500
- const encodedInput = yield* Schema.encodeEffect(agent.definition.input)(input).pipe(
501
- Effect.mapError((cause) =>
502
- AgentInputError.make({ message: `Unable to encode Agent input: ${cause.message}` }),
503
- ),
504
- );
505
- const inputPayload = yield* Schema.decodeUnknownEffect(PersistedJson)(
506
- encodedInput,
507
- ).pipe(
508
- Effect.mapError(() =>
509
- AgentInputError.make({
510
- message: "Agent input does not satisfy the canonical persistence bounds",
511
- }),
512
- ),
513
- );
514
- const request = SubmitRequest.make({
515
- agentId: agent.definition.id,
516
- principal: options.principal,
517
- idempotencyKey: options.idempotencyKey,
518
- definitions: options.definitions,
519
- inputPayload,
520
- });
521
- const encoded = yield* encodeSubmitRequest(request).pipe(
522
- Effect.mapError((error) =>
523
- HostProtocolError.make({
524
- message: boundHostDiagnostic(`submit request encode failed: ${error.message}`),
525
- }),
526
- ),
527
- );
528
- const response = yield* call(options.conversationId, "submit", (stub) =>
529
- stub.submitEncoded(encoded),
530
- );
531
- const succeeded = yield* expect<SubmitSucceeded, ClientSubmitFailure & HostFailure>(
532
- options.conversationId,
533
- "submit",
534
- "SubmitSucceeded",
535
- SUBMIT_FAILURE_TAGS,
536
- )(response);
537
- return succeeded.receipt;
538
- }),
539
-
540
- awaitSettlement: (receipt) =>
541
- Effect.gen(function* () {
542
- const encoded = yield* encodeReceipt(receipt).pipe(
543
- Effect.mapError((error) =>
544
- HostProtocolError.make({
545
- message: boundHostDiagnostic(`receipt encode failed: ${error.message}`),
546
- }),
547
- ),
548
- );
549
- const response = yield* call(receipt.conversationId, "awaitSettlement", (stub) =>
550
- stub.awaitSettlementEncoded(encoded),
551
- );
552
- const settled = yield* expect<SettlementReached, ClientAwaitFailure & HostFailure>(
553
- receipt.conversationId,
554
- "awaitSettlement",
555
- "SettlementReached",
556
- AWAIT_FAILURE_TAGS,
557
- )(response);
558
- return settled.settlement;
559
- }),
560
-
561
- readPage,
562
-
563
- readAll: (conversationId) =>
564
- Effect.gen(function* () {
565
- const all: Array<CanonicalRecordEnvelope> = [];
566
- let after: CanonicalSequence | undefined;
567
- for (;;) {
568
- const page = yield* readPage(conversationId, { afterSequence: after, limit: 1_024 });
569
- all.push(...page);
570
- const last = page.at(-1);
571
- if (page.length < 1_024 || last === undefined) return all;
572
- after = last.sequence;
573
- }
574
- }),
575
-
576
- abort: (conversationId, command) =>
577
- Effect.gen(function* () {
578
- const encoded = yield* encodeAbortCommand(command).pipe(
579
- Effect.mapError((error) =>
580
- HostProtocolError.make({
581
- message: boundHostDiagnostic(`abort command encode failed: ${error.message}`),
582
- }),
583
- ),
584
- );
585
- const response = yield* call(conversationId, "abort", (stub) =>
586
- stub.abortEncoded(encoded),
587
- );
588
- const recorded = yield* expect<AbortRecorded, ClientAbortFailure & HostFailure>(
589
- conversationId,
590
- "abort",
591
- "AbortRecorded",
592
- ABORT_FAILURE_TAGS,
593
- )(response);
594
- return recorded.intent;
595
- }),
596
-
597
- resolveApproval: (conversationId, command) =>
598
- Effect.gen(function* () {
599
- const encoded = yield* encodeApprovalDecisionCommand(command).pipe(
600
- Effect.mapError((error) =>
601
- HostProtocolError.make({
602
- message: boundHostDiagnostic(`approval command encode failed: ${error.message}`),
603
- }),
604
- ),
605
- );
606
- const response = yield* call(conversationId, "resolveApproval", (stub) =>
607
- stub.resolveApprovalEncoded(encoded),
608
- );
609
- const recorded = yield* expect<ApprovalRecorded, ClientApprovalFailure & HostFailure>(
610
- conversationId,
611
- "resolveApproval",
612
- "ApprovalRecorded",
613
- APPROVAL_FAILURE_TAGS,
614
- )(response);
615
- return recorded.intent;
616
- }),
617
-
618
- resolveUnknown: (conversationId, command) =>
619
- Effect.gen(function* () {
620
- const encoded = yield* encodeUnknownResolutionCommand(command).pipe(
621
- Effect.mapError((error) =>
622
- HostProtocolError.make({
623
- message: boundHostDiagnostic(
624
- `resolution command encode failed: ${error.message}`,
625
- ),
626
- }),
627
- ),
628
- );
629
- const response = yield* call(conversationId, "resolveUnknown", (stub) =>
630
- stub.resolveUnknownEncoded(encoded),
631
- );
632
- const recorded = yield* expect<
633
- UnknownResolutionRecorded,
634
- ClientUnknownFailure & HostFailure
635
- >(
636
- conversationId,
637
- "resolveUnknown",
638
- "UnknownResolutionRecorded",
639
- UNKNOWN_FAILURE_TAGS,
640
- )(response);
641
- return recorded.intent;
642
- }),
643
- });
644
- }),
645
- );
646
- }