@effect-agent/platform-cloudflare 0.1.0-beta.42 → 0.1.0-beta.45
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/browser-quick-action.mjs.map +1 -1
- package/dist/browser-rest-capture.mjs.map +1 -1
- package/dist/browser-rest-crawl.mjs.map +1 -1
- package/dist/browser-session-lifecycle-DqntvG-Y.d.mts +21 -0
- package/dist/browser-session-lifecycle-ZGgb3pnK.mjs +84 -0
- package/dist/browser-session-lifecycle-ZGgb3pnK.mjs.map +1 -0
- package/dist/index.d.mts +47 -34
- package/dist/index.mjs +3 -3
- package/dist/index.mjs.map +1 -1
- package/dist/interactive-browser.d.mts +1 -18
- package/dist/interactive-browser.mjs +2 -81
- package/dist/interactive-browser.mjs.map +1 -1
- package/dist/{prepared-admission-BKp_Upw2.mjs → prepared-admission-BhW2eT_a.mjs} +3 -3
- package/dist/prepared-admission-BhW2eT_a.mjs.map +1 -0
- package/dist/protected-browser.d.mts +62 -0
- package/dist/protected-browser.mjs +714 -0
- package/dist/protected-browser.mjs.map +1 -0
- package/dist/scheduling.mjs +1 -1
- package/dist/scheduling.mjs.map +1 -1
- package/dist/subscriptions.mjs +1 -1
- package/dist/subscriptions.mjs.map +1 -1
- package/package.json +1 -81
- package/src/alarm.ts +277 -242
- package/src/bindings.ts +5 -0
- package/src/boundary.ts +4 -0
- package/src/browser-quick-action.ts +52 -0
- package/src/browser-rest-capture.ts +30 -0
- package/src/browser-rest-crawl.ts +43 -0
- package/src/browser-session-lifecycle.ts +18 -0
- package/src/client.ts +40 -0
- package/src/code-mode-executor.ts +50 -0
- package/src/interactive-browser.ts +176 -0
- package/src/layers.ts +13 -3
- package/src/memory.ts +42 -3
- package/src/prepared-admission.ts +1 -0
- package/src/progress-wait.ts +14 -0
- package/src/protected-browser/binding.ts +185 -0
- package/src/protected-browser/inspect-frame.ts +82 -0
- package/src/protected-browser/native.ts +384 -0
- package/src/protected-browser/policy.ts +594 -0
- package/src/protected-browser.ts +2 -0
- package/src/scheduling.ts +34 -0
- package/src/subscriptions.ts +50 -0
- package/src/thread-object.ts +55 -1
- package/src/transport.ts +1 -0
- package/src/wake-scheduler.ts +1 -0
- package/dist/prepared-admission-BKp_Upw2.mjs.map +0 -1
|
@@ -47,6 +47,7 @@ const BoundedJobId = Schema.NonEmptyString.check(Schema.isMaxLength(256));
|
|
|
47
47
|
const BoundedCursorString = Schema.NonEmptyString.check(Schema.isMaxLength(MAX_CURSOR_LENGTH));
|
|
48
48
|
// The generated API response Schema says string; the current product example returns a number.
|
|
49
49
|
const ProviderCursor = Schema.Union([BoundedCursorString, Schema.Natural]);
|
|
50
|
+
|
|
50
51
|
const ProviderJobStatus = Schema.Literals([
|
|
51
52
|
"running",
|
|
52
53
|
"completed",
|
|
@@ -55,6 +56,7 @@ const ProviderJobStatus = Schema.Literals([
|
|
|
55
56
|
"cancelled_due_to_timeout",
|
|
56
57
|
"cancelled_due_to_limits",
|
|
57
58
|
]);
|
|
59
|
+
|
|
58
60
|
const ProviderResult = Schema.Struct({
|
|
59
61
|
id: BoundedJobId,
|
|
60
62
|
status: ProviderJobStatus,
|
|
@@ -65,14 +67,17 @@ const ProviderResult = Schema.Struct({
|
|
|
65
67
|
records: Schema.Array(PageCrawlRecord).check(Schema.isMaxLength(MAX_RECORDS_PER_RESPONSE)),
|
|
66
68
|
cursor: Schema.optionalKey(ProviderCursor),
|
|
67
69
|
});
|
|
70
|
+
|
|
68
71
|
const CreateEnvelope = Schema.Struct({
|
|
69
72
|
success: Schema.Literal(true),
|
|
70
73
|
result: BoundedJobId,
|
|
71
74
|
});
|
|
75
|
+
|
|
72
76
|
const ResultEnvelope = Schema.Struct({
|
|
73
77
|
success: Schema.Literal(true),
|
|
74
78
|
result: ProviderResult,
|
|
75
79
|
});
|
|
80
|
+
|
|
76
81
|
const DeleteEnvelope = Schema.Struct({
|
|
77
82
|
success: Schema.Literal(true),
|
|
78
83
|
result: Schema.Struct({
|
|
@@ -91,8 +96,10 @@ const boundedDiagnostic = (message: string): string => message.slice(0, MAX_DIAG
|
|
|
91
96
|
|
|
92
97
|
const privateCause = (value: unknown, apiToken: Redacted.Redacted<string>): Error | undefined => {
|
|
93
98
|
const raw = boundedDiagnostic(String(value));
|
|
99
|
+
|
|
94
100
|
if (raw.length === 0) return undefined;
|
|
95
101
|
const token = Redacted.value(apiToken);
|
|
102
|
+
|
|
96
103
|
return new Error(token.length === 0 ? raw : raw.replaceAll(token, "[REDACTED]"));
|
|
97
104
|
};
|
|
98
105
|
|
|
@@ -116,6 +123,7 @@ const limitError = (
|
|
|
116
123
|
: limit === "total-bytes"
|
|
117
124
|
? request.limits.maxTotalBytes
|
|
118
125
|
: request.limits.deadlineMillis;
|
|
126
|
+
|
|
119
127
|
return PageCrawlLimitError.make({
|
|
120
128
|
implementation: browserRestCrawlImplementation,
|
|
121
129
|
limit,
|
|
@@ -129,15 +137,19 @@ const retryAfterMillis = (
|
|
|
129
137
|
headers: Readonly<Record<string, string | undefined>>,
|
|
130
138
|
): number | undefined => {
|
|
131
139
|
const seconds = Number(headers["retry-after"]);
|
|
140
|
+
|
|
132
141
|
if (!Number.isSafeInteger(seconds) || seconds < 0) return undefined;
|
|
133
142
|
const millis = seconds * 1_000;
|
|
143
|
+
|
|
134
144
|
return Number.isSafeInteger(millis) ? millis : undefined;
|
|
135
145
|
};
|
|
136
146
|
|
|
137
147
|
const isJsonResponse = (headers: Readonly<Record<string, string | undefined>>): boolean => {
|
|
138
148
|
const contentType = headers["content-type"];
|
|
149
|
+
|
|
139
150
|
if (contentType === undefined) return false;
|
|
140
151
|
const mediaType = contentType.split(";", 1)[0]?.trim().toLowerCase();
|
|
152
|
+
|
|
141
153
|
return mediaType === "application/json" || mediaType?.endsWith("+json") === true;
|
|
142
154
|
};
|
|
143
155
|
|
|
@@ -153,6 +165,7 @@ const readBoundedResponse = Effect.fn("BrowserRestCrawl.readBoundedResponse")(fu
|
|
|
153
165
|
maximum: number,
|
|
154
166
|
): Effect.fn.Return<string, PageCrawlProtocolError> {
|
|
155
167
|
const decoder = new TextDecoder("utf-8", { fatal: true, ignoreBOM: false });
|
|
168
|
+
|
|
156
169
|
const state = yield* Stream.runFoldEffect<
|
|
157
170
|
Uint8Array,
|
|
158
171
|
HttpClientError.HttpClientError,
|
|
@@ -165,6 +178,7 @@ const readBoundedResponse = Effect.fn("BrowserRestCrawl.readBoundedResponse")(fu
|
|
|
165
178
|
() => ({ observed: 0, text: "" }),
|
|
166
179
|
(current, chunk) => {
|
|
167
180
|
const observed = current.observed + chunk.byteLength;
|
|
181
|
+
|
|
168
182
|
if (observed > maximum) {
|
|
169
183
|
return Effect.fail(
|
|
170
184
|
protocolError(
|
|
@@ -172,6 +186,7 @@ const readBoundedResponse = Effect.fn("BrowserRestCrawl.readBoundedResponse")(fu
|
|
|
172
186
|
),
|
|
173
187
|
);
|
|
174
188
|
}
|
|
189
|
+
|
|
175
190
|
return Effect.try({
|
|
176
191
|
try: () => ({ observed, text: current.text + decoder.decode(chunk, { stream: true }) }),
|
|
177
192
|
catch: (cause) => protocolError("Decoding the Browser Run crawl response failed", cause),
|
|
@@ -184,6 +199,7 @@ const readBoundedResponse = Effect.fn("BrowserRestCrawl.readBoundedResponse")(fu
|
|
|
184
199
|
: protocolError("Reading the Browser Run crawl response failed", cause),
|
|
185
200
|
),
|
|
186
201
|
);
|
|
202
|
+
|
|
187
203
|
return yield* Effect.try({
|
|
188
204
|
try: () => state.text + decoder.decode(),
|
|
189
205
|
catch: (cause) => protocolError("Decoding the Browser Run crawl response failed", cause),
|
|
@@ -195,6 +211,7 @@ const deadlineFailure = Effect.fn("BrowserRestCrawl.deadlineFailure")(function*
|
|
|
195
211
|
startedAt: number,
|
|
196
212
|
) {
|
|
197
213
|
const now = yield* Effect.clockWith((clock) => clock.currentTimeMillis);
|
|
214
|
+
|
|
198
215
|
return yield* limitError(request, "deadline", Math.max(0, now - startedAt));
|
|
199
216
|
});
|
|
200
217
|
|
|
@@ -206,7 +223,9 @@ const withinDeadline = Effect.fn("BrowserRestCrawl.withinDeadline")(function* <A
|
|
|
206
223
|
const now = yield* Effect.clockWith((clock) => clock.currentTimeMillis);
|
|
207
224
|
const elapsed = Math.max(0, now - startedAt);
|
|
208
225
|
const remaining = request.limits.deadlineMillis - elapsed;
|
|
226
|
+
|
|
209
227
|
if (remaining <= 0) return yield* limitError(request, "deadline", elapsed);
|
|
228
|
+
|
|
210
229
|
return yield* effect.pipe(
|
|
211
230
|
Effect.timeoutOrElse({
|
|
212
231
|
duration: Duration.millis(remaining),
|
|
@@ -221,6 +240,7 @@ const checkDeadline = Effect.fn("BrowserRestCrawl.checkDeadline")(function* (
|
|
|
221
240
|
) {
|
|
222
241
|
const now = yield* Effect.clockWith((clock) => clock.currentTimeMillis);
|
|
223
242
|
const elapsed = Math.max(0, now - startedAt);
|
|
243
|
+
|
|
224
244
|
if (elapsed >= request.limits.deadlineMillis) {
|
|
225
245
|
return yield* limitError(request, "deadline", elapsed);
|
|
226
246
|
}
|
|
@@ -254,6 +274,7 @@ const makeCrawl =
|
|
|
254
274
|
const authorized = HttpClientRequest.bearerToken(request, options.apiToken).pipe(
|
|
255
275
|
HttpClientRequest.acceptJson,
|
|
256
276
|
);
|
|
277
|
+
|
|
257
278
|
const response = yield* client
|
|
258
279
|
.execute(authorized)
|
|
259
280
|
.pipe(
|
|
@@ -264,9 +285,12 @@ const makeCrawl =
|
|
|
264
285
|
),
|
|
265
286
|
),
|
|
266
287
|
);
|
|
288
|
+
|
|
267
289
|
const bodyText = yield* readBoundedResponse(response, maximum);
|
|
290
|
+
|
|
268
291
|
if (response.status === 429) {
|
|
269
292
|
const reason = isQuotaMessage(bodyText) ? "quota" : "rate";
|
|
293
|
+
|
|
270
294
|
return yield* PageCrawlRateLimitedError.make({
|
|
271
295
|
implementation: browserRestCrawlImplementation,
|
|
272
296
|
reason,
|
|
@@ -294,6 +318,7 @@ const makeCrawl =
|
|
|
294
318
|
privateCause(bodyText, options.apiToken),
|
|
295
319
|
);
|
|
296
320
|
}
|
|
321
|
+
|
|
297
322
|
return yield* Schema.decodeUnknownEffect(Schema.fromJsonString(schema))(bodyText).pipe(
|
|
298
323
|
Effect.mapError((cause) =>
|
|
299
324
|
protocolError(
|
|
@@ -322,11 +347,13 @@ const makeCrawl =
|
|
|
322
347
|
protocolError("Encoding the Browser Run crawl request failed", cause),
|
|
323
348
|
),
|
|
324
349
|
);
|
|
350
|
+
|
|
325
351
|
const created = yield* withinDeadline(
|
|
326
352
|
executeJson(requestWithBody, CreateEnvelope, MAX_CONTROL_RESPONSE_BYTES),
|
|
327
353
|
input,
|
|
328
354
|
startedAt,
|
|
329
355
|
);
|
|
356
|
+
|
|
330
357
|
return created.result;
|
|
331
358
|
});
|
|
332
359
|
|
|
@@ -344,6 +371,7 @@ const makeCrawl =
|
|
|
344
371
|
).pipe(
|
|
345
372
|
Effect.flatMap((shouldCancel) => {
|
|
346
373
|
if (!shouldCancel) return Effect.void;
|
|
374
|
+
|
|
347
375
|
const cancellation = executeJson(
|
|
348
376
|
HttpClientRequest.delete(endpoint(options, id)),
|
|
349
377
|
DeleteEnvelope,
|
|
@@ -355,6 +383,7 @@ const makeCrawl =
|
|
|
355
383
|
: protocolError("Browser Run cancelled a different crawl job"),
|
|
356
384
|
),
|
|
357
385
|
);
|
|
386
|
+
|
|
358
387
|
return cancellation.pipe(
|
|
359
388
|
Effect.timeoutOrElse({
|
|
360
389
|
duration: CANCEL_TIMEOUT,
|
|
@@ -373,6 +402,7 @@ const makeCrawl =
|
|
|
373
402
|
),
|
|
374
403
|
),
|
|
375
404
|
);
|
|
405
|
+
|
|
376
406
|
return { id, state } as const;
|
|
377
407
|
}),
|
|
378
408
|
),
|
|
@@ -384,19 +414,23 @@ const makeCrawl =
|
|
|
384
414
|
statusOnly: boolean,
|
|
385
415
|
) {
|
|
386
416
|
let request = HttpClientRequest.get(endpoint(options, job.id));
|
|
417
|
+
|
|
387
418
|
if (statusOnly) request = HttpClientRequest.setUrlParam(request, "limit", "1");
|
|
388
419
|
if (Option.isSome(cursor)) {
|
|
389
420
|
request = HttpClientRequest.setUrlParam(request, "cursor", cursor.value);
|
|
390
421
|
}
|
|
422
|
+
|
|
391
423
|
// `limit=1` still permits one complete record, so poll GETs use the bounded result cap.
|
|
392
424
|
const envelope = yield* withinDeadline(
|
|
393
425
|
executeJson(request, ResultEnvelope, MAX_RESULTS_RESPONSE_BYTES),
|
|
394
426
|
input,
|
|
395
427
|
startedAt,
|
|
396
428
|
);
|
|
429
|
+
|
|
397
430
|
if (envelope.result.id !== job.id) {
|
|
398
431
|
return yield* protocolError("Browser Run returned a different crawl job identity");
|
|
399
432
|
}
|
|
433
|
+
|
|
400
434
|
return envelope.result;
|
|
401
435
|
});
|
|
402
436
|
|
|
@@ -412,6 +446,7 @@ const makeCrawl =
|
|
|
412
446
|
),
|
|
413
447
|
).pipe(Effect.tap(() => Ref.set(job.state, "terminal"))),
|
|
414
448
|
);
|
|
449
|
+
|
|
415
450
|
if (terminal.status === "running") {
|
|
416
451
|
return yield* protocolError("Browser Run polling stopped before a terminal status");
|
|
417
452
|
}
|
|
@@ -428,6 +463,7 @@ const makeCrawl =
|
|
|
428
463
|
(state) =>
|
|
429
464
|
Effect.gen(function* () {
|
|
430
465
|
const result = yield* fetchResult(state.cursor, false);
|
|
466
|
+
|
|
431
467
|
if (result.status !== "completed") {
|
|
432
468
|
return yield* protocolError(
|
|
433
469
|
"Browser Run changed crawl status during result pagination",
|
|
@@ -437,12 +473,14 @@ const makeCrawl =
|
|
|
437
473
|
return [result.records, Option.none()] as const;
|
|
438
474
|
}
|
|
439
475
|
const cursor = normalizedCursor(result.cursor);
|
|
476
|
+
|
|
440
477
|
if (state.seen.includes(cursor)) {
|
|
441
478
|
return yield* protocolError("Browser Run repeated a crawl result cursor");
|
|
442
479
|
}
|
|
443
480
|
if (state.seen.length >= input.limits.maxPages) {
|
|
444
481
|
return yield* protocolError("Browser Run returned too many crawl result cursors");
|
|
445
482
|
}
|
|
483
|
+
|
|
446
484
|
return [
|
|
447
485
|
result.records,
|
|
448
486
|
Option.some({ cursor: Option.some(cursor), seen: [...state.seen, cursor] }),
|
|
@@ -458,6 +496,7 @@ const makeCrawl =
|
|
|
458
496
|
Effect.gen(function* () {
|
|
459
497
|
yield* checkDeadline(input, startedAt);
|
|
460
498
|
const pages = state.pages + 1;
|
|
499
|
+
|
|
461
500
|
if (pages > input.limits.maxPages) {
|
|
462
501
|
return yield* limitError(input, "pages", pages);
|
|
463
502
|
}
|
|
@@ -467,17 +506,21 @@ const makeCrawl =
|
|
|
467
506
|
if (record.metadata !== undefined && !sameHost(startHost, record.metadata.url)) {
|
|
468
507
|
return yield* protocolError("Browser Run returned off-host crawl metadata");
|
|
469
508
|
}
|
|
509
|
+
|
|
470
510
|
const pageBytes =
|
|
471
511
|
record.markdown === undefined
|
|
472
512
|
? 0
|
|
473
513
|
: new TextEncoder().encode(record.markdown).byteLength;
|
|
514
|
+
|
|
474
515
|
if (pageBytes > input.limits.maxPageBytes) {
|
|
475
516
|
return yield* limitError(input, "page-bytes", pageBytes);
|
|
476
517
|
}
|
|
477
518
|
const totalBytes = state.totalBytes + pageBytes;
|
|
519
|
+
|
|
478
520
|
if (totalBytes > input.limits.maxTotalBytes) {
|
|
479
521
|
return yield* limitError(input, "total-bytes", totalBytes);
|
|
480
522
|
}
|
|
523
|
+
|
|
481
524
|
return [{ pages, totalBytes }, [record]] as const;
|
|
482
525
|
}),
|
|
483
526
|
),
|
|
@@ -49,11 +49,13 @@ export class BrowserRunSessionLifecycle extends Context.Service<
|
|
|
49
49
|
return yield* new BrowserRunCleanupError({ reason: "configuration" });
|
|
50
50
|
}
|
|
51
51
|
const client = yield* HttpClient.HttpClient;
|
|
52
|
+
|
|
52
53
|
const request = Effect.fn("BrowserRunSessionLifecycle.request")(function* (
|
|
53
54
|
method: "GET" | "DELETE",
|
|
54
55
|
sessionId: string,
|
|
55
56
|
) {
|
|
56
57
|
const path = method === "DELETE" ? "browser" : "session";
|
|
58
|
+
|
|
57
59
|
const response = yield* client
|
|
58
60
|
.execute(
|
|
59
61
|
HttpClientRequest.make(method)(
|
|
@@ -65,6 +67,7 @@ export class BrowserRunSessionLifecycle extends Context.Service<
|
|
|
65
67
|
Effect.provideService(FetchHttpClient.RequestInit, { redirect: "manual" }),
|
|
66
68
|
Effect.mapError(() => new BrowserRunCleanupError({ reason: "provider" })),
|
|
67
69
|
);
|
|
70
|
+
|
|
68
71
|
if (response.status === 401 || response.status === 403)
|
|
69
72
|
return yield* new BrowserRunCleanupError({
|
|
70
73
|
reason: "authorization",
|
|
@@ -82,6 +85,7 @@ export class BrowserRunSessionLifecycle extends Context.Service<
|
|
|
82
85
|
});
|
|
83
86
|
if (response.headers["content-type"]?.split(";", 1)[0]?.trim() !== "application/json")
|
|
84
87
|
return yield* new BrowserRunCleanupError({ reason: "malformed" });
|
|
88
|
+
|
|
85
89
|
const bytes = yield* Stream.runFoldEffect(
|
|
86
90
|
response.stream,
|
|
87
91
|
() => new Uint8Array(),
|
|
@@ -89,44 +93,57 @@ export class BrowserRunSessionLifecycle extends Context.Service<
|
|
|
89
93
|
if (body.byteLength + chunk.byteLength > 16_384)
|
|
90
94
|
return Effect.fail(new BrowserRunCleanupError({ reason: "malformed" }));
|
|
91
95
|
const combined = new Uint8Array(body.byteLength + chunk.byteLength);
|
|
96
|
+
|
|
92
97
|
combined.set(body);
|
|
93
98
|
combined.set(chunk, body.byteLength);
|
|
99
|
+
|
|
94
100
|
return Effect.succeed(combined);
|
|
95
101
|
},
|
|
96
102
|
).pipe(Effect.mapError(() => new BrowserRunCleanupError({ reason: "malformed" })));
|
|
103
|
+
|
|
97
104
|
const body = yield* Effect.try({
|
|
98
105
|
try: () => new TextDecoder("utf-8", { fatal: true, ignoreBOM: false }).decode(bytes),
|
|
99
106
|
catch: () => new BrowserRunCleanupError({ reason: "malformed" }),
|
|
100
107
|
});
|
|
108
|
+
|
|
101
109
|
if (response.status === 404) {
|
|
102
110
|
const absent = Schema.decodeUnknownOption(Schema.fromJsonString(Absent))(body, {
|
|
103
111
|
onExcessProperty: "error",
|
|
104
112
|
});
|
|
113
|
+
|
|
105
114
|
if (Option.isSome(absent)) return true;
|
|
115
|
+
|
|
106
116
|
return yield* new BrowserRunCleanupError({ reason: "malformed" });
|
|
107
117
|
}
|
|
108
118
|
if (method === "DELETE") {
|
|
109
119
|
const result = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(Closed))(
|
|
110
120
|
body,
|
|
111
121
|
).pipe(Effect.mapError(() => new BrowserRunCleanupError({ reason: "malformed" })));
|
|
122
|
+
|
|
112
123
|
return result.status === "closed";
|
|
113
124
|
}
|
|
125
|
+
|
|
114
126
|
const result = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(Metadata))(
|
|
115
127
|
body,
|
|
116
128
|
).pipe(Effect.mapError(() => new BrowserRunCleanupError({ reason: "malformed" })));
|
|
129
|
+
|
|
117
130
|
if (result.sessionId !== sessionId)
|
|
118
131
|
return yield* new BrowserRunCleanupError({ reason: "malformed" });
|
|
132
|
+
|
|
119
133
|
return result.endTime !== undefined && result.endTime > 0;
|
|
120
134
|
});
|
|
135
|
+
|
|
121
136
|
const close = Effect.fn("BrowserRunSessionLifecycle.close")(
|
|
122
137
|
function* (sessionId: Redacted.Redacted<string>) {
|
|
123
138
|
const id = yield* Schema.decodeUnknownEffect(Identity)(Redacted.value(sessionId)).pipe(
|
|
124
139
|
Effect.mapError(() => new BrowserRunCleanupError({ reason: "configuration" })),
|
|
125
140
|
);
|
|
141
|
+
|
|
126
142
|
if (yield* request("DELETE", id)) return;
|
|
127
143
|
for (let read = 0; read < 2; read++) {
|
|
128
144
|
if (yield* request("GET", id)) return;
|
|
129
145
|
}
|
|
146
|
+
|
|
130
147
|
return yield* new BrowserRunCleanupError({ reason: "pending" });
|
|
131
148
|
},
|
|
132
149
|
Effect.timeoutOrElse({
|
|
@@ -135,6 +152,7 @@ export class BrowserRunSessionLifecycle extends Context.Service<
|
|
|
135
152
|
}),
|
|
136
153
|
Effect.withTracerEnabled(false),
|
|
137
154
|
);
|
|
155
|
+
|
|
138
156
|
return { close };
|
|
139
157
|
}),
|
|
140
158
|
);
|
package/src/client.ts
CHANGED
|
@@ -156,6 +156,7 @@ export const HostFailure = Schema.Union([
|
|
|
156
156
|
OperationDenied,
|
|
157
157
|
HostProtocolError,
|
|
158
158
|
]);
|
|
159
|
+
|
|
159
160
|
export type HostFailure = typeof HostFailure.Type;
|
|
160
161
|
|
|
161
162
|
export class SubmitSucceeded extends Schema.TaggedClass<SubmitSucceeded>(
|
|
@@ -222,6 +223,7 @@ export const HostResponse = Schema.Union([
|
|
|
222
223
|
UnknownResolutionRecorded,
|
|
223
224
|
HostFailed,
|
|
224
225
|
]);
|
|
226
|
+
|
|
225
227
|
export type HostResponse = typeof HostResponse.Type;
|
|
226
228
|
|
|
227
229
|
// ---------------------------------------------------------------------------
|
|
@@ -266,18 +268,21 @@ const ClientSubmitHostFailure = Schema.Union([
|
|
|
266
268
|
DurableAlarmError,
|
|
267
269
|
HostProtocolError,
|
|
268
270
|
]);
|
|
271
|
+
|
|
269
272
|
const ClientAwaitHostFailure = Schema.Union([
|
|
270
273
|
LedgerError,
|
|
271
274
|
SettlementConflict,
|
|
272
275
|
OperationDenied,
|
|
273
276
|
HostProtocolError,
|
|
274
277
|
]);
|
|
278
|
+
|
|
275
279
|
const ClientObserveHostFailure = Schema.Union([
|
|
276
280
|
ThreadStoreError,
|
|
277
281
|
ThreadNotMaterialized,
|
|
278
282
|
OperationDenied,
|
|
279
283
|
HostProtocolError,
|
|
280
284
|
]);
|
|
285
|
+
|
|
281
286
|
const ClientAbortHostFailure = Schema.Union([
|
|
282
287
|
OperationDenied,
|
|
283
288
|
LedgerError,
|
|
@@ -287,6 +292,7 @@ const ClientAbortHostFailure = Schema.Union([
|
|
|
287
292
|
DurableAlarmError,
|
|
288
293
|
HostProtocolError,
|
|
289
294
|
]);
|
|
295
|
+
|
|
290
296
|
const ClientApprovalHostFailure = Schema.Union([
|
|
291
297
|
LedgerError,
|
|
292
298
|
SettlementConflict,
|
|
@@ -295,6 +301,7 @@ const ClientApprovalHostFailure = Schema.Union([
|
|
|
295
301
|
DurableAlarmError,
|
|
296
302
|
HostProtocolError,
|
|
297
303
|
]);
|
|
304
|
+
|
|
298
305
|
const ClientUnknownHostFailure = Schema.Union([
|
|
299
306
|
LedgerError,
|
|
300
307
|
SettlementConflict,
|
|
@@ -420,9 +427,11 @@ export class CloudflareThreadClient extends Context.Service<
|
|
|
420
427
|
// Empty arguments preserve native arity. Passing `undefined` still adds an argument.
|
|
421
428
|
const traceArgs =
|
|
422
429
|
rpcTracing === undefined ? [] : yield* RpcTracing.withRpcTraceContext([]);
|
|
430
|
+
|
|
423
431
|
const raw = yield* Effect.tryPromise({
|
|
424
432
|
try: () => {
|
|
425
433
|
const stub = namespace.get(namespace.idFromName(threadId));
|
|
434
|
+
|
|
426
435
|
return stub[hostRpcMethods[operation]](encoded, ...traceArgs);
|
|
427
436
|
},
|
|
428
437
|
catch: (cause) =>
|
|
@@ -438,6 +447,7 @@ export class CloudflareThreadClient extends Context.Service<
|
|
|
438
447
|
...cloudflareFailureSignals(cause),
|
|
439
448
|
}),
|
|
440
449
|
});
|
|
450
|
+
|
|
441
451
|
return yield* decodeHostResponse(raw).pipe(
|
|
442
452
|
Effect.mapError((error): HostProtocolError =>
|
|
443
453
|
HostProtocolError.make({
|
|
@@ -464,11 +474,13 @@ export class CloudflareThreadClient extends Context.Service<
|
|
|
464
474
|
) => {
|
|
465
475
|
const isExpectedResult = Schema.is(resultSchema);
|
|
466
476
|
const isExpectedFailure = Schema.is(failureSchema);
|
|
477
|
+
|
|
467
478
|
return (
|
|
468
479
|
response: HostResponse,
|
|
469
480
|
): Effect.Effect<ResultSchema["Type"], FailureSchema["Type"] | ThreadClientError> => {
|
|
470
481
|
if (response._tag === "HostFailed") {
|
|
471
482
|
const failure = response.failure;
|
|
483
|
+
|
|
472
484
|
return isExpectedFailure(failure)
|
|
473
485
|
? Effect.fail(failure)
|
|
474
486
|
: Effect.fail(outOfContract(threadId, operation, `failure ${failure._tag}`));
|
|
@@ -476,6 +488,7 @@ export class CloudflareThreadClient extends Context.Service<
|
|
|
476
488
|
if (!isExpectedResult(response)) {
|
|
477
489
|
return Effect.fail(outOfContract(threadId, operation, `result ${response._tag}`));
|
|
478
490
|
}
|
|
491
|
+
|
|
479
492
|
return Effect.succeed(response);
|
|
480
493
|
};
|
|
481
494
|
};
|
|
@@ -494,6 +507,7 @@ export class CloudflareThreadClient extends Context.Service<
|
|
|
494
507
|
: { afterSequence: options.afterSequence }),
|
|
495
508
|
limit: options?.limit ?? 256,
|
|
496
509
|
});
|
|
510
|
+
|
|
497
511
|
const encoded = yield* encodeObservePageRequest(request).pipe(
|
|
498
512
|
Effect.mapError((error) =>
|
|
499
513
|
HostProtocolError.make({
|
|
@@ -501,13 +515,16 @@ export class CloudflareThreadClient extends Context.Service<
|
|
|
501
515
|
}),
|
|
502
516
|
),
|
|
503
517
|
);
|
|
518
|
+
|
|
504
519
|
const response = yield* call(threadId, "observePage", encoded);
|
|
520
|
+
|
|
505
521
|
const page = yield* expect(
|
|
506
522
|
threadId,
|
|
507
523
|
"observePage",
|
|
508
524
|
ObservedPage,
|
|
509
525
|
ClientObserveHostFailure,
|
|
510
526
|
)(response);
|
|
527
|
+
|
|
511
528
|
return page.records;
|
|
512
529
|
});
|
|
513
530
|
|
|
@@ -533,6 +550,7 @@ export class CloudflareThreadClient extends Context.Service<
|
|
|
533
550
|
AgentInputError.make({ message: `Unable to encode Agent input: ${cause.message}` }),
|
|
534
551
|
),
|
|
535
552
|
);
|
|
553
|
+
|
|
536
554
|
const inputPayload = yield* Schema.decodeUnknownEffect(PersistedJson)(
|
|
537
555
|
encodedInput,
|
|
538
556
|
).pipe(
|
|
@@ -542,6 +560,7 @@ export class CloudflareThreadClient extends Context.Service<
|
|
|
542
560
|
}),
|
|
543
561
|
),
|
|
544
562
|
);
|
|
563
|
+
|
|
545
564
|
const request = SubmitRequest.make({
|
|
546
565
|
agentId: agent.definition.id,
|
|
547
566
|
principal: options.principal,
|
|
@@ -549,6 +568,7 @@ export class CloudflareThreadClient extends Context.Service<
|
|
|
549
568
|
definitions: options.definitions,
|
|
550
569
|
inputPayload,
|
|
551
570
|
});
|
|
571
|
+
|
|
552
572
|
const encoded = yield* encodeSubmitRequest(request).pipe(
|
|
553
573
|
Effect.mapError((error) =>
|
|
554
574
|
HostProtocolError.make({
|
|
@@ -556,13 +576,16 @@ export class CloudflareThreadClient extends Context.Service<
|
|
|
556
576
|
}),
|
|
557
577
|
),
|
|
558
578
|
);
|
|
579
|
+
|
|
559
580
|
const response = yield* call(options.threadId, "submit", encoded);
|
|
581
|
+
|
|
560
582
|
const succeeded = yield* expect(
|
|
561
583
|
options.threadId,
|
|
562
584
|
"submit",
|
|
563
585
|
SubmitSucceeded,
|
|
564
586
|
ClientSubmitHostFailure,
|
|
565
587
|
)(response);
|
|
588
|
+
|
|
566
589
|
return succeeded.receipt;
|
|
567
590
|
}),
|
|
568
591
|
|
|
@@ -575,13 +598,16 @@ export class CloudflareThreadClient extends Context.Service<
|
|
|
575
598
|
}),
|
|
576
599
|
),
|
|
577
600
|
);
|
|
601
|
+
|
|
578
602
|
const response = yield* call(receipt.threadId, "awaitSettlement", encoded);
|
|
603
|
+
|
|
579
604
|
const settled = yield* expect(
|
|
580
605
|
receipt.threadId,
|
|
581
606
|
"awaitSettlement",
|
|
582
607
|
SettlementReached,
|
|
583
608
|
ClientAwaitHostFailure,
|
|
584
609
|
)(response);
|
|
610
|
+
|
|
585
611
|
return settled.settlement;
|
|
586
612
|
}),
|
|
587
613
|
|
|
@@ -596,7 +622,9 @@ export class CloudflareThreadClient extends Context.Service<
|
|
|
596
622
|
}),
|
|
597
623
|
),
|
|
598
624
|
);
|
|
625
|
+
|
|
599
626
|
const request = AwaitProgressRequest.make({ afterSequence, waiterId });
|
|
627
|
+
|
|
600
628
|
const encoded = yield* encodeAwaitProgressRequest(request).pipe(
|
|
601
629
|
Effect.mapError((error) =>
|
|
602
630
|
HostProtocolError.make({
|
|
@@ -631,10 +659,13 @@ export class CloudflareThreadClient extends Context.Service<
|
|
|
631
659
|
Effect.gen(function* () {
|
|
632
660
|
const all: Array<CanonicalRecordEnvelope> = [];
|
|
633
661
|
let after: CanonicalSequence | undefined;
|
|
662
|
+
|
|
634
663
|
for (;;) {
|
|
635
664
|
const page = yield* readPage(threadId, { afterSequence: after, limit: 1_024 });
|
|
665
|
+
|
|
636
666
|
all.push(...page);
|
|
637
667
|
const last = page.at(-1);
|
|
668
|
+
|
|
638
669
|
if (page.length < 1_024 || last === undefined) return all;
|
|
639
670
|
after = last.sequence;
|
|
640
671
|
}
|
|
@@ -649,13 +680,16 @@ export class CloudflareThreadClient extends Context.Service<
|
|
|
649
680
|
}),
|
|
650
681
|
),
|
|
651
682
|
);
|
|
683
|
+
|
|
652
684
|
const response = yield* call(threadId, "abort", encoded);
|
|
685
|
+
|
|
653
686
|
const recorded = yield* expect(
|
|
654
687
|
threadId,
|
|
655
688
|
"abort",
|
|
656
689
|
AbortRecorded,
|
|
657
690
|
ClientAbortHostFailure,
|
|
658
691
|
)(response);
|
|
692
|
+
|
|
659
693
|
return recorded.intent;
|
|
660
694
|
}),
|
|
661
695
|
|
|
@@ -668,13 +702,16 @@ export class CloudflareThreadClient extends Context.Service<
|
|
|
668
702
|
}),
|
|
669
703
|
),
|
|
670
704
|
);
|
|
705
|
+
|
|
671
706
|
const response = yield* call(threadId, "resolveApproval", encoded);
|
|
707
|
+
|
|
672
708
|
const recorded = yield* expect(
|
|
673
709
|
threadId,
|
|
674
710
|
"resolveApproval",
|
|
675
711
|
ApprovalRecorded,
|
|
676
712
|
ClientApprovalHostFailure,
|
|
677
713
|
)(response);
|
|
714
|
+
|
|
678
715
|
return recorded.intent;
|
|
679
716
|
}),
|
|
680
717
|
|
|
@@ -689,13 +726,16 @@ export class CloudflareThreadClient extends Context.Service<
|
|
|
689
726
|
}),
|
|
690
727
|
),
|
|
691
728
|
);
|
|
729
|
+
|
|
692
730
|
const response = yield* call(threadId, "resolveUnknown", encoded);
|
|
731
|
+
|
|
693
732
|
const recorded = yield* expect(
|
|
694
733
|
threadId,
|
|
695
734
|
"resolveUnknown",
|
|
696
735
|
UnknownResolutionRecorded,
|
|
697
736
|
ClientUnknownHostFailure,
|
|
698
737
|
)(response);
|
|
738
|
+
|
|
699
739
|
return recorded.intent;
|
|
700
740
|
}),
|
|
701
741
|
});
|