@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.
- package/dist/Alarm.d.mts +188 -0
- package/dist/Alarm.mjs +451 -0
- package/dist/Alarm.mjs.map +1 -0
- package/dist/BrowserRestCapture.d.mts +35 -0
- package/dist/BrowserRestCapture.mjs +238 -0
- package/dist/BrowserRestCapture.mjs.map +1 -0
- package/dist/BrowserRestCrawl.d.mts +17 -0
- package/dist/BrowserRestCrawl.mjs +244 -0
- package/dist/BrowserRestCrawl.mjs.map +1 -0
- package/dist/CloudflareAiGateway.d.mts +64 -0
- package/dist/CloudflareAiGateway.mjs +70 -0
- package/dist/CloudflareAiGateway.mjs.map +1 -0
- package/dist/CloudflareBindings.d.mts +115 -0
- package/dist/CloudflareBindings.mjs +113 -0
- package/dist/CloudflareBindings.mjs.map +1 -0
- package/dist/CloudflareBrowser-DV6kya1H.mjs +495 -0
- package/dist/CloudflareBrowser-DV6kya1H.mjs.map +1 -0
- package/dist/CloudflareBrowser-Doe1M7R5.d.mts +80 -0
- package/dist/CloudflareBrowser.d.mts +2 -0
- package/dist/CloudflareBrowser.mjs +2 -0
- package/dist/CloudflareCodeMode.d.mts +44 -0
- package/dist/CloudflareCodeMode.mjs +616 -0
- package/dist/CloudflareCodeMode.mjs.map +1 -0
- package/dist/CloudflareConfig-f3CqTel1.d.mts +101 -0
- package/dist/CloudflareConfig.d.mts +2 -0
- package/dist/CloudflareConfig.mjs +122 -0
- package/dist/CloudflareConfig.mjs.map +1 -0
- package/dist/CloudflareMemory.d.mts +142 -0
- package/dist/CloudflareMemory.mjs +202 -0
- package/dist/CloudflareMemory.mjs.map +1 -0
- package/dist/CloudflareScheduling.d.mts +52 -0
- package/dist/CloudflareScheduling.mjs +396 -0
- package/dist/CloudflareScheduling.mjs.map +1 -0
- package/dist/CloudflareSubscriptions.d.mts +87 -0
- package/dist/CloudflareSubscriptions.mjs +530 -0
- package/dist/CloudflareSubscriptions.mjs.map +1 -0
- package/dist/CloudflareThreadClient.d.mts +1496 -0
- package/dist/CloudflareThreadClient.mjs +382 -0
- package/dist/CloudflareThreadClient.mjs.map +1 -0
- package/dist/InteractiveBrowser-DUE_m12-.d.mts +161 -0
- package/dist/InteractiveBrowser-DupDtfw2.mjs +1169 -0
- package/dist/InteractiveBrowser-DupDtfw2.mjs.map +1 -0
- package/dist/InteractiveBrowser.d.mts +2 -0
- package/dist/InteractiveBrowser.mjs +2 -0
- package/dist/ProtectedBrowser.d.mts +123 -0
- package/dist/ProtectedBrowser.mjs +1135 -0
- package/dist/ProtectedBrowser.mjs.map +1 -0
- package/dist/ThreadObject-CIbmXZCY.d.mts +812 -0
- package/dist/ThreadObject-DvRG0dDz.mjs +835 -0
- package/dist/ThreadObject-DvRG0dDz.mjs.map +1 -0
- package/dist/ThreadObject.d.mts +2 -0
- package/dist/ThreadObject.mjs +3 -0
- package/dist/WakeScheduler.d.mts +23 -0
- package/dist/WakeScheduler.mjs +57 -0
- package/dist/WakeScheduler.mjs.map +1 -0
- package/dist/boundary-BguazVkh.mjs +42 -0
- package/dist/boundary-BguazVkh.mjs.map +1 -0
- package/dist/index.d.mts +13 -1548
- package/dist/index.mjs +13 -1636
- package/dist/prepared-admission-DU0_T-ev.mjs +73 -0
- package/dist/prepared-admission-DU0_T-ev.mjs.map +1 -0
- package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
- package/package.json +1 -53
- package/src/Alarm.ts +973 -0
- package/src/BrowserRestCapture.ts +477 -0
- package/src/BrowserRestCrawl.ts +540 -0
- package/src/CloudflareAiGateway.ts +170 -0
- package/src/CloudflareBindings.ts +199 -0
- package/src/CloudflareBrowser.ts +15 -0
- package/src/{code-mode-executor.ts → CloudflareCodeMode.ts} +372 -204
- package/src/{config.ts → CloudflareConfig.ts} +9 -8
- package/src/CloudflareMemory.ts +420 -0
- package/src/CloudflareScheduling.ts +747 -0
- package/src/CloudflareSubscriptions.ts +1041 -0
- package/src/CloudflareThreadClient.ts +809 -0
- package/src/InteractiveBrowser.ts +2354 -0
- package/src/ProtectedBrowser.ts +9 -0
- package/src/ThreadObject.ts +1179 -0
- package/src/{wake-scheduler.ts → WakeScheduler.ts} +32 -26
- package/src/index.ts +12 -23
- package/src/internal/boundary.ts +55 -0
- package/src/internal/browser-quick-action.ts +857 -0
- package/src/internal/browser-session-lifecycle.ts +160 -0
- package/src/internal/layers.ts +751 -0
- package/src/internal/message-delivery.ts +152 -0
- package/src/internal/prepared-admission.ts +116 -0
- package/src/internal/progress-wait.ts +121 -0
- package/src/internal/transport.ts +44 -0
- package/src/protected-browser/binding.ts +313 -0
- package/src/protected-browser/host.ts +344 -0
- package/src/protected-browser/inspect-frame.ts +125 -0
- package/src/protected-browser/native.ts +445 -0
- package/src/protected-browser/policy.ts +821 -0
- package/dist/index.mjs.map +0 -1
- package/src/alarm.ts +0 -334
- package/src/bindings.ts +0 -145
- package/src/client.ts +0 -646
- package/src/conversation-object.ts +0 -768
- package/src/layers.ts +0 -376
- 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
|
-
}
|