@effect-agent/platform-cloudflare 0.1.0-beta.42 → 0.1.0-beta.44

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 (42) hide show
  1. package/dist/browser-quick-action.mjs.map +1 -1
  2. package/dist/browser-rest-capture.mjs.map +1 -1
  3. package/dist/browser-rest-crawl.mjs.map +1 -1
  4. package/dist/browser-session-lifecycle-DqntvG-Y.d.mts +21 -0
  5. package/dist/browser-session-lifecycle-ZGgb3pnK.mjs +84 -0
  6. package/dist/browser-session-lifecycle-ZGgb3pnK.mjs.map +1 -0
  7. package/dist/index.d.mts +69 -56
  8. package/dist/index.mjs.map +1 -1
  9. package/dist/interactive-browser.d.mts +1 -18
  10. package/dist/interactive-browser.mjs +2 -81
  11. package/dist/interactive-browser.mjs.map +1 -1
  12. package/dist/prepared-admission-BKp_Upw2.mjs.map +1 -1
  13. package/dist/protected-browser.d.mts +62 -0
  14. package/dist/protected-browser.mjs +714 -0
  15. package/dist/protected-browser.mjs.map +1 -0
  16. package/dist/scheduling.mjs.map +1 -1
  17. package/dist/subscriptions.mjs.map +1 -1
  18. package/package.json +1 -81
  19. package/src/alarm.ts +41 -0
  20. package/src/bindings.ts +5 -0
  21. package/src/boundary.ts +4 -0
  22. package/src/browser-quick-action.ts +52 -0
  23. package/src/browser-rest-capture.ts +30 -0
  24. package/src/browser-rest-crawl.ts +43 -0
  25. package/src/browser-session-lifecycle.ts +18 -0
  26. package/src/client.ts +40 -0
  27. package/src/code-mode-executor.ts +50 -0
  28. package/src/interactive-browser.ts +176 -0
  29. package/src/layers.ts +10 -0
  30. package/src/memory.ts +42 -3
  31. package/src/prepared-admission.ts +1 -0
  32. package/src/progress-wait.ts +14 -0
  33. package/src/protected-browser/binding.ts +185 -0
  34. package/src/protected-browser/inspect-frame.ts +82 -0
  35. package/src/protected-browser/native.ts +384 -0
  36. package/src/protected-browser/policy.ts +594 -0
  37. package/src/protected-browser.ts +2 -0
  38. package/src/scheduling.ts +34 -0
  39. package/src/subscriptions.ts +50 -0
  40. package/src/thread-object.ts +55 -1
  41. package/src/transport.ts +1 -0
  42. package/src/wake-scheduler.ts +1 -0
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
  });
@@ -229,36 +229,45 @@ const HarnessCompleted = Schema.TaggedStruct("completed", {
229
229
  logBytes: Schema.Natural,
230
230
  resultBytes: Schema.Natural,
231
231
  });
232
+
232
233
  const HarnessSourceInvalid = Schema.TaggedStruct("source-invalid", {
233
234
  message: Schema.String,
234
235
  });
236
+
235
237
  const HarnessNotAFunction = Schema.TaggedStruct("source-not-a-function", {
236
238
  actual: Schema.String,
237
239
  });
240
+
238
241
  const HarnessProgramFailed = Schema.TaggedStruct("program-failed", {
239
242
  reason: Schema.Literals(["threw", "rejected", "non-json-result"]),
240
243
  thrown: Schema.Json,
241
244
  message: Schema.String,
242
245
  logs: BoundedLogs,
243
246
  });
247
+
244
248
  const HarnessLogLimit = Schema.TaggedStruct("log-limit", {
245
249
  observed: Schema.Natural,
246
250
  logs: BoundedLogs,
247
251
  });
252
+
248
253
  const HarnessArgumentLimit = Schema.TaggedStruct("argument-limit", {
249
254
  observed: Schema.Natural,
250
255
  logs: BoundedLogs,
251
256
  });
257
+
252
258
  const HarnessResultLimit = Schema.TaggedStruct("result-limit", {
253
259
  observed: Schema.Natural,
254
260
  logs: BoundedLogs,
255
261
  });
262
+
256
263
  const HarnessHostCallLimit = Schema.TaggedStruct("host-call-limit", {
257
264
  logs: BoundedLogs,
258
265
  });
266
+
259
267
  const HarnessProtocol = Schema.TaggedStruct("protocol", {
260
268
  message: Schema.String,
261
269
  });
270
+
262
271
  const HarnessOutcome = Schema.Union([
263
272
  HarnessCompleted,
264
273
  HarnessSourceInvalid,
@@ -321,6 +330,7 @@ export const disposeRpcHandle = (handle: unknown): Effect.Effect<void> =>
321
330
  if ((typeof handle !== "object" && typeof handle !== "function") || handle === null) return;
322
331
  if (!(Symbol.dispose in handle)) return;
323
332
  const dispose = Reflect.get(handle, Symbol.dispose);
333
+
324
334
  if (typeof dispose === "function") {
325
335
  Reflect.apply(dispose, handle, []);
326
336
  }
@@ -353,6 +363,7 @@ const encodeHostResultPayload = (
353
363
  try {
354
364
  const payload = outcome._tag === "CodeHostCallSuccess" ? outcome.value : outcome.error;
355
365
  const encodedPayload = encodeJsonPayload(payload);
366
+
356
367
  return {
357
368
  encodedPayload,
358
369
  resultBytes: utf8ByteLength(encodedPayload),
@@ -364,10 +375,13 @@ const encodeHostResultPayload = (
364
375
 
365
376
  const utf8ByteLength = (value: string): number => {
366
377
  let total = 0;
378
+
367
379
  for (const character of value) {
368
380
  const codePoint = character.codePointAt(0) ?? 0;
381
+
369
382
  total += codePoint <= 0x7f ? 1 : codePoint <= 0x7ff ? 2 : codePoint <= 0xffff ? 3 : 4;
370
383
  }
384
+
371
385
  return total;
372
386
  };
373
387
 
@@ -411,6 +425,7 @@ const makeExecute = (
411
425
  });
412
426
  }
413
427
  const sourceBytes = utf8ByteLength(request.source);
428
+
414
429
  if (sourceBytes > request.limits.maxSourceBytes) {
415
430
  return yield* CodeSourceError.make({
416
431
  implementation: dynamicWorkerImplementation,
@@ -433,22 +448,28 @@ const makeExecute = (
433
448
  // immediately. The Clock service remains the authority, so tests and hosts can replace it.
434
449
  const startedAt = clock.monotonicTimeNanosUnsafe();
435
450
  const passDeadline = startedAt + Duration.toNanosUnsafe(request.limits.maxWallTime);
451
+
436
452
  const remainingPassWallTime = (): Duration.Duration => {
437
453
  const now = clock.monotonicTimeNanosUnsafe();
454
+
438
455
  return Duration.nanos(passDeadline > now ? passDeadline - now : 0n);
439
456
  };
457
+
440
458
  let issuedHostCalls = 0;
441
459
  let passOpen = true;
442
460
  const queuedHostCalls: Array<QueuedHostCall> = [];
443
461
  let passFailure: HostDispatchError | undefined;
462
+
444
463
  const failPass = (error: HostDispatchError): void => {
445
464
  if (passFailure === undefined) passFailure = error;
446
465
  };
466
+
447
467
  const rejectQueuedHostCalls = (reason: Error): void => {
448
468
  for (const queued of queuedHostCalls.splice(0)) {
449
469
  queued.reject(reason);
450
470
  }
451
471
  };
472
+
452
473
  const queue = yield* Queue.unbounded<HostWork>();
453
474
 
454
475
  const deliverHostOutcome = (
@@ -457,15 +478,19 @@ const makeExecute = (
457
478
  ): Effect.Effect<void, CodeExecutionProtocolError | CodeOutputLimitError> =>
458
479
  Effect.gen(function* () {
459
480
  const decoded = decodeHostCallResult(outcome);
481
+
460
482
  if (Option.isNone(decoded)) {
461
483
  const error = CodeExecutionProtocolError.make({
462
484
  implementation: dynamicWorkerImplementation,
463
485
  message: "The execution host returned a value outside the CodeHostCallResult schema",
464
486
  });
487
+
465
488
  failPass(error);
489
+
466
490
  return yield* error;
467
491
  }
468
492
  const encoded = encodeHostResultPayload(decoded.value);
493
+
469
494
  if (encoded === undefined || encoded.resultBytes > request.limits.maxHostCallResultBytes) {
470
495
  const error = CodeOutputLimitError.make({
471
496
  implementation: dynamicWorkerImplementation,
@@ -474,16 +499,21 @@ const makeExecute = (
474
499
  observed: encoded?.resultBytes ?? 0,
475
500
  logs: [],
476
501
  });
502
+
477
503
  failPass(error);
504
+
478
505
  return yield* error;
479
506
  }
480
507
  const normalizedPayload = decodeJsonPayload(encoded.encodedPayload);
508
+
481
509
  if (Option.isNone(normalizedPayload)) {
482
510
  const error = CodeExecutionProtocolError.make({
483
511
  implementation: dynamicWorkerImplementation,
484
512
  message: "The execution host returned a result that could not cross the JSON boundary",
485
513
  });
514
+
486
515
  failPass(error);
516
+
487
517
  return yield* error;
488
518
  }
489
519
  queued.resolve(
@@ -499,16 +529,20 @@ const makeExecute = (
499
529
  const serveHostCalls = Effect.gen(function* () {
500
530
  while (true) {
501
531
  const work = yield* Queue.take(queue);
532
+
502
533
  if (work._tag === "limit") {
503
534
  const error = CodeHostCallLimitError.make({
504
535
  implementation: dynamicWorkerImplementation,
505
536
  limit: request.limits.maxHostCalls,
506
537
  logs: [],
507
538
  });
539
+
508
540
  failPass(error);
541
+
509
542
  return yield* error;
510
543
  }
511
544
  const queued = work.queued;
545
+
512
546
  yield* host.call(queued.call).pipe(
513
547
  Effect.timeoutOrElse({
514
548
  duration: remainingPassWallTime(),
@@ -519,7 +553,9 @@ const makeExecute = (
519
553
  maxWallTime: request.limits.maxWallTime,
520
554
  logs: [],
521
555
  });
556
+
522
557
  failPass(error);
558
+
523
559
  return error;
524
560
  },
525
561
  }),
@@ -533,6 +569,7 @@ const makeExecute = (
533
569
  );
534
570
  }
535
571
  });
572
+
536
573
  const server = yield* serveHostCalls.pipe(Effect.forkScoped);
537
574
 
538
575
  const dispatch = (hostCall: unknown): Promise<unknown> => {
@@ -546,16 +583,21 @@ const makeExecute = (
546
583
  limit: request.limits.maxHostCalls,
547
584
  logs: [],
548
585
  });
586
+
549
587
  failPass(error);
550
588
  Queue.offerUnsafe(queue, { _tag: "limit" });
589
+
551
590
  return Promise.reject(new Error("host-call limit exceeded"));
552
591
  }
553
592
  const decoded = decodeHostCall(hostCall);
593
+
554
594
  if (Option.isNone(decoded)) {
555
595
  return Promise.reject(new TypeError("host calls must match the CodeHostCall schema"));
556
596
  }
597
+
557
598
  return new Promise((resolve, reject) => {
558
599
  const queued = { call: decoded.value, resolve, reject };
600
+
559
601
  queuedHostCalls.push(queued);
560
602
  Queue.offerUnsafe(queue, { _tag: "call", queued });
561
603
  });
@@ -565,6 +607,7 @@ const makeExecute = (
565
607
  passOpen = false;
566
608
  rejectQueuedHostCalls(new Error("Code Mode pass is closing"));
567
609
  });
610
+
568
611
  yield* Effect.addFinalizer(() => closeAdmission.pipe(Effect.andThen(Fiber.interrupt(server))));
569
612
 
570
613
  // No `allowExperimental`: the runtime only accepts it when the CALLING
@@ -608,6 +651,7 @@ const makeExecute = (
608
651
  try: () => options.loader.load(workerCode),
609
652
  catch: (cause) => {
610
653
  const text = safeCauseMessage(cause, "The Worker Loader failed without a diagnostic");
654
+
611
655
  // Blame the program's source ONLY on a genuine compile diagnostic;
612
656
  // any other load rejection is an infrastructure start failure, not
613
657
  // the model's fault (see classifyWorkerFailure for the same split).
@@ -618,6 +662,7 @@ const makeExecute = (
618
662
  message: text.slice(0, 8_000),
619
663
  });
620
664
  }
665
+
621
666
  return CodeExecutorStartError.make({
622
667
  implementation: dynamicWorkerImplementation,
623
668
  message: `The Worker Loader rejected the pass: ${text}`.slice(0, 8_000),
@@ -656,6 +701,7 @@ const makeExecute = (
656
701
  ),
657
702
  Fiber.join(server),
658
703
  ).pipe(Effect.exit);
704
+
659
705
  yield* closeAdmission;
660
706
  yield* Fiber.interrupt(server);
661
707
  if (passFailure !== undefined) {
@@ -668,6 +714,7 @@ const makeExecute = (
668
714
  const finishedAt = clock.monotonicTimeNanosUnsafe();
669
715
 
670
716
  const outcome = decodeHarnessOutcome(raw);
717
+
671
718
  if (Option.isNone(outcome)) {
672
719
  return yield* CodeExecutionProtocolError.make({
673
720
  implementation: dynamicWorkerImplementation,
@@ -768,6 +815,7 @@ const classifyWorkerFailure = (
768
815
  | CodeExecutorStartError
769
816
  | CodeSourceError => {
770
817
  const text = safeCauseDiagnostic(cause, "[unserializable worker failure]");
818
+
771
819
  // `WorkerLoader.load()` is lazy, so a module-compile error in the generated
772
820
  // program surfaces here at first use. Blame the program's source ONLY on a
773
821
  // genuine compile diagnostic (a `SyntaxError` or an explicit compile
@@ -797,6 +845,7 @@ const classifyWorkerFailure = (
797
845
  cause,
798
846
  });
799
847
  }
848
+
800
849
  return CodeExecutorTerminatedError.make({
801
850
  implementation: dynamicWorkerImplementation,
802
851
  message: text.slice(0, 8_000),
@@ -811,6 +860,7 @@ export const dynamicWorkerCodeExecutorLayer = (
811
860
  CodeExecutor,
812
861
  Effect.gen(function* () {
813
862
  const clock = yield* Clock.Clock;
863
+
814
864
  return CodeExecutor.of({ execute: makeExecute(options, clock) });
815
865
  }),
816
866
  );