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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/bindings-BrVEOkfe.d.mts +102 -0
  2. package/dist/browser-quick-action.d.mts +18 -1
  3. package/dist/browser-quick-action.mjs +14 -1
  4. package/dist/browser-quick-action.mjs.map +1 -1
  5. package/dist/browser-rest-capture.d.mts +17 -2
  6. package/dist/browser-rest-capture.mjs +12 -1
  7. package/dist/browser-rest-capture.mjs.map +1 -1
  8. package/dist/browser-rest-crawl.mjs +2 -2
  9. package/dist/browser-rest-crawl.mjs.map +1 -1
  10. package/dist/index.d.mts +245 -237
  11. package/dist/index.mjs +168 -164
  12. package/dist/index.mjs.map +1 -1
  13. package/dist/interactive-browser.d.mts +160 -2
  14. package/dist/interactive-browser.mjs +1166 -2
  15. package/dist/interactive-browser.mjs.map +1 -0
  16. package/dist/{scheduling-B-OFqoS9.mjs → prepared-admission-BKp_Upw2.mjs} +134 -433
  17. package/dist/prepared-admission-BKp_Upw2.mjs.map +1 -0
  18. package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
  19. package/dist/scheduling.d.mts +47 -2
  20. package/dist/scheduling.mjs +339 -1
  21. package/dist/scheduling.mjs.map +1 -0
  22. package/dist/subscriptions.d.mts +52 -0
  23. package/dist/subscriptions.mjs +346 -0
  24. package/dist/subscriptions.mjs.map +1 -0
  25. package/package.json +20 -13
  26. package/src/alarm.ts +264 -265
  27. package/src/bindings.ts +34 -30
  28. package/src/browser-quick-action.ts +31 -0
  29. package/src/browser-rest-capture.ts +27 -0
  30. package/src/client.ts +111 -105
  31. package/src/code-mode-executor.ts +19 -0
  32. package/src/config.ts +7 -7
  33. package/src/index.ts +10 -11
  34. package/src/interactive-browser.ts +29 -1
  35. package/src/layers.ts +178 -257
  36. package/src/prepared-admission.ts +90 -0
  37. package/src/scheduling.ts +19 -55
  38. package/src/subscriptions.ts +661 -0
  39. package/src/{conversation-object.ts → thread-object.ts} +167 -136
  40. package/src/transport.ts +15 -15
  41. package/src/wake-scheduler.ts +17 -22
  42. package/dist/interactive-browser-BRo-Bfvb.d.mts +0 -144
  43. package/dist/interactive-browser-Cy5q-ldl.mjs +0 -1154
  44. package/dist/interactive-browser-Cy5q-ldl.mjs.map +0 -1
  45. package/dist/scheduling-B-OFqoS9.mjs.map +0 -1
  46. package/dist/scheduling-BJs_kHTx.d.mts +0 -142
@@ -1,15 +1,14 @@
1
- import { Clock, Context, Crypto, DateTime, Duration, Effect, Layer, Option, Predicate, Random, Ref, Schema, Semaphore, Stream } from "effect";
2
- import { AbortCommand, AbortIntent, AdmissionConflict, AgentBindingResolver, AppendConflict, ApprovalConflict, ApprovalDecisionCommand, ApprovalDecisionIntent, CanonicalRecordEnvelope, CanonicalSequence, ConversationNotMaterialized, ConversationStoreError, DEFAULT_OWNERSHIP_LEASE_DURATION, DefinitionDigests, DeploymentId, DigestError, DurableAgentRuntime, DurableRuntimeFailpointError, FenceRejected, IdempotencyKey, JoinedToHost, LedgerError, OperationDenied, PersistedJson, Principal, Receipt, ScheduleAuthorizationError, ScheduleCapacityError, ScheduleConflict, ScheduleDestination, ScheduleDriver, ScheduleFailpointError, ScheduleId, ScheduleNotFound, ScheduleOwner, ScheduleScope, ScheduleSnapshot, ScheduleSnapshotPage, ScheduleStorageError, ScheduleTimingRequest, ScheduleValidationError, ScheduleWakeNoop, ScheduledInputAdmission, ScheduledInputRetryable, Scheduling, Settlement, SettlementConflict, SubmissionLedger, UnknownResolutionCommand, UnknownResolutionConflict, UnknownResolutionIntent, defaultSchedulingLimits, scheduleOwnerKey } from "@effect-agent/session";
3
- import { DEFAULT_MAX_STORED_VALUE_BYTES, DoScheduleAlarmControl, DoScheduleTransaction, scheduleStoreLayer } from "@effect-agent/storage-cloudflare";
1
+ import { Clock, Context, Crypto, Duration, Effect, Layer, Option, Predicate, Random, Ref, Schema, Semaphore, Stream } from "effect";
2
+ import { DEFAULT_MAX_STORED_VALUE_BYTES } from "@effect-agent/storage-cloudflare";
3
+ import { AbortCommand, AbortIntent, AdmissionConflict, AppendConflict, ApprovalConflict, ApprovalDecisionCommand, ApprovalDecisionIntent, CanonicalRecordEnvelope, CanonicalSequence, DEFAULT_OWNERSHIP_LEASE_DURATION, DefinitionDigests, DeploymentId, DigestError, DurableAgentRuntime, DurableRuntimeFailpointError, FenceRejected, IdempotencyKey, JoinedToHost, LedgerError, OperationDenied, PersistedJson, PreparedInputAdmission, Principal, Receipt, ScheduleStorageError, ScheduledInputAdmission, ScheduledInputRetryable, Settlement, SettlementConflict, SubmissionLedger, ThreadNotMaterialized, ThreadStoreError, UnknownResolutionCommand, UnknownResolutionConflict, UnknownResolutionIntent } from "@effect-agent/thread";
4
4
  import { AgentId, AgentInputError } from "@effect-agent/core";
5
5
  import { BrowserCrypto } from "@effect/platform-browser";
6
- import { SqliteClient } from "@effect/sql-sqlite-do";
7
- import { DurableObject, DurableObjectAlarm, DurableObjectState, RpcTracing } from "effect-cf";
6
+ import { RpcTracing } from "effect-cf";
8
7
  //#region src/bindings.ts
9
8
  /**
10
9
  * Cloudflare platform bindings as Effect services (DEPLOY-010: "Cloudflare platform bindings
11
10
  * are supplied as Effect services/Layers"). Application code never reads `env` or touches a
12
- * `DurableObjectState` directly — the Conversation Object class constructs these Layers once
11
+ * `DurableObjectState` directly — the Thread Object class constructs these Layers once
13
12
  * per incarnation and everything downstream consumes the services.
14
13
  */
15
14
  /** A Cloudflare platform binding was missing or carried the wrong shape (DEPLOY-003/010). */
@@ -18,13 +17,16 @@ var CloudflareBindingError = class extends Schema.TaggedError()("CloudflareBindi
18
17
  message: Schema.String
19
18
  }) {};
20
19
  /**
21
- * The `DurableObjectNamespace` binding that addresses Conversation Objects. The Object
22
- * identity rule is `namespace.idFromName(conversationId)` (plan §1.2): Conversation IDs are
20
+ * The `DurableObjectNamespace` binding that addresses Thread Objects. The Object
21
+ * identity rule is `namespace.idFromName(threadId)` (plan §1.2): Thread IDs are
23
22
  * globally unique, so the mapping is total and deterministic and no directory service exists.
24
23
  */
25
- var ConversationObjectNamespace = class ConversationObjectNamespace extends Context.Service()("@effect-agent/platform-cloudflare/ConversationObjectNamespace") {
26
- static layer(namespace) {
27
- return Layer.succeed(ConversationObjectNamespace)({ namespace });
24
+ var ThreadObjectNamespace = class ThreadObjectNamespace extends Context.Service()("@effect-agent/platform-cloudflare/ThreadObjectNamespace") {
25
+ static layer(namespace, options = {}) {
26
+ return Layer.succeed(ThreadObjectNamespace)({
27
+ namespace,
28
+ ...options.rpcTracing === void 0 ? {} : { rpcTracing: options.rpcTracing }
29
+ });
28
30
  }
29
31
  };
30
32
  /**
@@ -33,7 +35,7 @@ var ConversationObjectNamespace = class ConversationObjectNamespace extends Cont
33
35
  * narrowest-boundary check (structural probe for the namespace surface the transport uses);
34
36
  * a missing or misshaped binding fails typed before any Layer is built.
35
37
  */
36
- const conversationNamespaceFromEnv = Effect.fn("conversationNamespaceFromEnv")(function* (env, binding) {
38
+ const threadNamespaceFromEnv = Effect.fn("threadNamespaceFromEnv")(function* (env, binding) {
37
39
  if (!Predicate.isObjectKeyword(env)) return yield* CloudflareBindingError.make({
38
40
  binding,
39
41
  message: "The Worker environment is not an object; no bindings are available."
@@ -54,14 +56,14 @@ const conversationNamespaceFromEnv = Effect.fn("conversationNamespaceFromEnv")(f
54
56
  if (candidate !== void 0) return candidate;
55
57
  return yield* CloudflareBindingError.make({
56
58
  binding,
57
- message: `env.${binding} is not a DurableObjectNamespace binding; declare the Conversation Object class under this binding in the Worker configuration.`
59
+ message: `env.${binding} is not a DurableObjectNamespace binding; declare the Thread Object class under this binding in the Worker configuration.`
58
60
  });
59
61
  });
60
62
  /**
61
63
  * Build the namespace from Worker `env` (fails typed). Enable `rpcTracing` only when the
62
64
  * receiver also opts into the effect-cf native RPC trace-context contract.
63
65
  */
64
- const conversationNamespaceLayer = (env, binding, options = {}) => Layer.effect(ConversationObjectNamespace)(Effect.map(conversationNamespaceFromEnv(env, binding), (namespace) => ({
66
+ const threadNamespaceLayer = (env, binding, options = {}) => Layer.effect(ThreadObjectNamespace)(Effect.map(threadNamespaceFromEnv(env, binding), (namespace) => ({
65
67
  namespace,
66
68
  ...options.rpcTracing === true ? { rpcTracing: binding } : {}
67
69
  })));
@@ -79,11 +81,11 @@ var DurableObjectContext = class DurableObjectContext extends Context.Service()(
79
81
  }
80
82
  };
81
83
  /**
82
- * The Conversation identity this Object serializes and the producer identity its Attempts
83
- * write with (`{producerPrefix}:{conversationId}`, plan §1.4). Derived once per incarnation
84
- * from `ctx.id.name` — the Object identity rule guarantees the name IS the Conversation ID.
84
+ * The Thread identity this Object serializes and the producer identity its Attempts
85
+ * write with (`{producerPrefix}:{threadId}`, plan §1.4). Derived once per incarnation
86
+ * from `ctx.id.name` — the Object identity rule guarantees the name IS the Thread ID.
85
87
  */
86
- var ConversationObjectIdentity = class extends Context.Service()("@effect-agent/platform-cloudflare/ConversationObjectIdentity") {};
88
+ var ThreadObjectIdentity = class extends Context.Service()("@effect-agent/platform-cloudflare/ThreadObjectIdentity") {};
87
89
  //#endregion
88
90
  //#region src/config.ts
89
91
  /**
@@ -103,7 +105,7 @@ var CloudflarePlatformConfigError = class extends Schema.TaggedError()("Cloudfla
103
105
  * (deployment spec §8, DEPLOY-007: "Admission has explicit bounded quota and overload
104
106
  * behavior... a typed rejection"). This is the DC analogue of `NodeDurableHost`'s
105
107
  * `AdmissionClosed` host gate: the port surface stays untouched, the refusal happens in the
106
- * Conversation Object's submit entry point before `DurableAgentRuntime.submit` runs, and
108
+ * Thread Object's submit entry point before `DurableAgentRuntime.submit` runs, and
107
109
  * nothing was admitted or written.
108
110
  */
109
111
  var AdmissionLimitExceeded = class extends Schema.TaggedError()("AdmissionLimitExceeded", {
@@ -124,11 +126,11 @@ const CLOUDFLARE_DATABASE_CAP_BYTES = 1e10;
124
126
  /** Default database-size admission ceiling: a 1 GB safety margin under the platform cap. */
125
127
  const DEFAULT_MAX_DATABASE_BYTES = 9e9;
126
128
  /**
127
- * Explicit bounded admission quotas checked by the Conversation Object BEFORE admission
129
+ * Explicit bounded admission quotas checked by the Thread Object BEFORE admission
128
130
  * (exit gate "resource limits are checked before admission").
129
131
  */
130
132
  var CloudflareAdmissionLimitsValue = class extends Schema.Class("@effect-agent/platform-cloudflare/CloudflareAdmissionLimitsValue")({
131
- /** Maximum nonterminal Submissions per Conversation lane before new admissions refuse. */
133
+ /** Maximum nonterminal Submissions per Thread lane before new admissions refuse. */
132
134
  maxQueueDepthPerLane: Schema.Int.check(Schema.isGreaterThan(0), Schema.isLessThanOrEqualTo(1e5)),
133
135
  /** Maximum encoded input bytes; never above the storage per-value bound. */
134
136
  maxInputBytes: Schema.Int.check(Schema.isGreaterThan(0), Schema.isLessThanOrEqualTo(2e6)),
@@ -137,13 +139,13 @@ var CloudflareAdmissionLimitsValue = class extends Schema.Class("@effect-agent/p
137
139
  }) {};
138
140
  /**
139
141
  * Validated Cloudflare durable runtime configuration. The producer identity of one
140
- * Conversation Object is `{producerPrefix}:{conversationId}` — stable across incarnations of
142
+ * Thread Object is `{producerPrefix}:{threadId}` — stable across incarnations of
141
143
  * the same deployment, distinct across deployments — and producer-epoch fencing (not the
142
144
  * producer name) remains the correctness authority (DUR-006).
143
145
  */
144
146
  var CloudflareDurableRuntimeConfigValue = class extends Schema.Class("@effect-agent/platform-cloudflare/CloudflareDurableRuntimeConfigValue")({
145
147
  deploymentId: DeploymentId,
146
- /** Head of the minted producer identity `{producerPrefix}:{conversationId}`. */
148
+ /** Head of the minted producer identity `{producerPrefix}:{threadId}`. */
147
149
  producerPrefix: Schema.NonEmptyString.check(Schema.isMaxLength(256)),
148
150
  /** Submission ownership lease duration (D5); fences work across Object incarnations. */
149
151
  ownershipLeaseDuration: PositiveMillis,
@@ -172,7 +174,7 @@ var CloudflareDurableRuntimeConfigValue = class extends Schema.Class("@effect-ag
172
174
  }) {};
173
175
  /** Explicit configuration authority for the assembled Cloudflare durable runtime. */
174
176
  var CloudflareDurableRuntimeConfig = class extends Context.Service()("@effect-agent/platform-cloudflare/CloudflareDurableRuntimeConfig") {};
175
- /** Documented production defaults applied by `CloudflareDurableRuntime.layer`. */
177
+ /** Documented production defaults applied by `ThreadObject.layer`. */
176
178
  const CLOUDFLARE_RUNTIME_DEFAULTS = {
177
179
  ownershipLeaseDuration: Duration.toMillis(DEFAULT_OWNERSHIP_LEASE_DURATION),
178
180
  alarmBackoffBase: 100,
@@ -300,21 +302,21 @@ var MaintenancePassReport = class extends Schema.Class("@effect-agent/platform-c
300
302
  alarm: Schema.Literals(["rearmed", "cleared"])
301
303
  }) {};
302
304
  /** Test-only fault authority; production uses the inert layer. */
303
- var ConversationMaintenanceFailpoint = class extends Context.Service()("@effect-agent/platform-cloudflare/ConversationMaintenanceFailpoint") {
305
+ var ThreadMaintenanceFailpoint = class extends Context.Service()("@effect-agent/platform-cloudflare/ThreadMaintenanceFailpoint") {
304
306
  static layer = Layer.succeed(this)({ hit: () => Effect.void });
305
307
  };
306
308
  const MaintenanceGeneration = Schema.BigIntFromString.check(Schema.isGreaterThanOrEqualToBigInt(0n));
307
309
  /** Versioned, platform-private maintenance state stored through Durable Object KV. */
308
- var ConversationMaintenanceState = class extends Schema.Class("@effect-agent/platform-cloudflare/ConversationMaintenanceState")({
310
+ var ThreadMaintenanceState = class extends Schema.Class("@effect-agent/platform-cloudflare/ThreadMaintenanceState")({
309
311
  schemaVersion: Schema.Literal(1),
310
312
  dirty: MaintenanceGeneration,
311
313
  processed: MaintenanceGeneration,
312
314
  nonterminal: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0))
313
315
  }) {};
314
- const MAINTENANCE_STATE_KEY = "effect-agent:conversation-maintenance:v1";
315
- const decodeMaintenanceState = Schema.decodeUnknownSync(ConversationMaintenanceState);
316
- const encodeMaintenanceState = Schema.encodeSync(ConversationMaintenanceState);
317
- const initialMaintenanceState = () => ConversationMaintenanceState.make({
316
+ const MAINTENANCE_STATE_KEY = "effect-agent:thread-maintenance:v1";
317
+ const decodeMaintenanceState = Schema.decodeUnknownSync(ThreadMaintenanceState);
318
+ const encodeMaintenanceState = Schema.encodeSync(ThreadMaintenanceState);
319
+ const initialMaintenanceState = () => ThreadMaintenanceState.make({
318
320
  schemaVersion: 1,
319
321
  dirty: 1n,
320
322
  processed: 0n,
@@ -363,16 +365,15 @@ const stableExternalWait = (snapshot, reports) => {
363
365
  * 4. Stable external waits acknowledge and clear. Autonomous retry, indeterminate, and lease
364
366
  * recovery states leave their generation dirty and retain bounded backoff rearming.
365
367
  */
366
- var ConversationMaintenance = class ConversationMaintenance extends Context.Service()("@effect-agent/platform-cloudflare/ConversationMaintenance") {
367
- static layer = Layer.effect(ConversationMaintenance)(Effect.gen(function* () {
368
+ var ThreadMaintenance = class ThreadMaintenance extends Context.Service()("@effect-agent/platform-cloudflare/ThreadMaintenance") {
369
+ static layer = (bindings) => Layer.effect(ThreadMaintenance)(Effect.gen(function* () {
368
370
  const runtime = yield* DurableAgentRuntime;
369
- const resolver = yield* AgentBindingResolver;
370
371
  const ledger = yield* SubmissionLedger;
371
372
  const alarm = yield* DurableAlarmService;
372
373
  const config = yield* CloudflareDurableRuntimeConfig;
373
- const identity = yield* ConversationObjectIdentity;
374
+ const identity = yield* ThreadObjectIdentity;
374
375
  const { ctx } = yield* DurableObjectContext;
375
- const failpoint = yield* ConversationMaintenanceFailpoint;
376
+ const failpoint = yield* ThreadMaintenanceFailpoint;
376
377
  /**
377
378
  * Consecutive no-progress passes — an in-memory CACHE, not state: a fresh incarnation
378
379
  * restarts at zero and merely re-arms sooner than a long-lived one would have.
@@ -392,12 +393,12 @@ var ConversationMaintenance = class ConversationMaintenance extends Context.Serv
392
393
  try: transaction,
393
394
  catch: alarmFailure(operation)
394
395
  });
395
- const beginMutation = Effect.fn("ConversationMaintenance.beginMutation")(function* () {
396
+ const beginMutation = Effect.fn("ThreadMaintenance.beginMutation")(function* () {
396
397
  yield* failpoint.hit("maintenance:dirty:before");
397
398
  const now = yield* Clock.currentTimeMillis;
398
399
  yield* runTransaction("advance maintenance generation", () => ctx.storage.transaction(async (transaction) => {
399
400
  const { state } = await readMaintenanceState(transaction);
400
- const next = ConversationMaintenanceState.make({
401
+ const next = ThreadMaintenanceState.make({
401
402
  ...state,
402
403
  dirty: state.dirty + 1n
403
404
  });
@@ -409,7 +410,7 @@ var ConversationMaintenance = class ConversationMaintenance extends Context.Serv
409
410
  });
410
411
  const endMutation = generationGate.withPermit(Ref.update(activeMutations, (active) => Math.max(0, active - 1)));
411
412
  const withMutation = (body) => Effect.acquireUseRelease(generationGate.withPermit(beginMutation()), () => failpoint.hit("maintenance:mutation:armed").pipe(Effect.andThen(body), Effect.tap(() => failpoint.hit("maintenance:mutation:finished"))), () => endMutation);
412
- const ensureAlarm = Effect.fn("ConversationMaintenance.ensureAlarm")(function* () {
413
+ const ensureAlarm = Effect.fn("ThreadMaintenance.ensureAlarm")(function* () {
413
414
  yield* failpoint.hit("maintenance:ensure:before");
414
415
  const now = yield* Clock.currentTimeMillis;
415
416
  yield* runTransaction("ensure maintenance alarm", () => ctx.storage.transaction(async (transaction) => {
@@ -419,7 +420,7 @@ var ConversationMaintenance = class ConversationMaintenance extends Context.Serv
419
420
  }));
420
421
  yield* failpoint.hit("maintenance:ensure:after");
421
422
  });
422
- const beginPass = Effect.fn("ConversationMaintenance.beginPass")(function* () {
423
+ const beginPass = Effect.fn("ThreadMaintenance.beginPass")(function* () {
423
424
  yield* failpoint.hit("maintenance:begin:before");
424
425
  const now = yield* Clock.currentTimeMillis;
425
426
  const result = yield* runTransaction("begin maintenance pass", () => ctx.storage.transaction(async (transaction) => {
@@ -441,7 +442,7 @@ var ConversationMaintenance = class ConversationMaintenance extends Context.Serv
441
442
  yield* failpoint.hit("maintenance:begin:after");
442
443
  return result;
443
444
  });
444
- const rearmDelay = Effect.fn("ConversationMaintenance.rearmDelay")(function* (progressed) {
445
+ const rearmDelay = Effect.fn("ThreadMaintenance.rearmDelay")(function* (progressed) {
445
446
  const priorStalls = yield* Ref.getAndUpdate(stalls, (count) => progressed ? 0 : count + 1);
446
447
  if (progressed) return config.alarmBackoffBase;
447
448
  const exponent = Math.min(priorStalls, 30);
@@ -450,7 +451,7 @@ var ConversationMaintenance = class ConversationMaintenance extends Context.Serv
450
451
  const jittered = Math.ceil(backoff / 2 + backoff / 2 * jitter);
451
452
  return Math.min(jittered, config.wakeScanInterval);
452
453
  });
453
- const pass = Effect.fn("ConversationMaintenance.pass")(function* () {
454
+ const pass = Effect.fn("ThreadMaintenance.pass")(function* () {
454
455
  const annotate = (report) => Effect.annotateCurrentSpan({
455
456
  phase: report.phase,
456
457
  recovered: report.recovered,
@@ -473,7 +474,7 @@ var ConversationMaintenance = class ConversationMaintenance extends Context.Serv
473
474
  alarm: "cleared"
474
475
  }));
475
476
  const recovered = yield* runtime.runRecovery;
476
- const settlements = yield* runtime.processConversationResolved(identity.conversationId).pipe(Effect.provideService(AgentBindingResolver, resolver));
477
+ const settlements = yield* runtime.processThreadResolved(identity.threadId, bindings);
477
478
  const remaining = yield* Stream.runCollect(ledger.scanNonterminal);
478
479
  const reports = new Map(recovered.map((report) => [report.submissionId, report]));
479
480
  const head = remaining[0];
@@ -491,7 +492,7 @@ var ConversationMaintenance = class ConversationMaintenance extends Context.Serv
491
492
  return yield* runTransaction("finish maintenance pass", () => ctx.storage.transaction(async (transaction) => {
492
493
  const { state } = await readMaintenanceState(transaction);
493
494
  const processed = autonomous || started.activeAtStart > 0 || active > 0 ? state.processed : state.processed > started.generation ? state.processed : started.generation;
494
- const next = ConversationMaintenanceState.make({
495
+ const next = ThreadMaintenanceState.make({
495
496
  ...state,
496
497
  processed,
497
498
  nonterminal: remaining.length
@@ -519,7 +520,7 @@ var ConversationMaintenance = class ConversationMaintenance extends Context.Serv
519
520
  alarm: alarmDisposition
520
521
  }));
521
522
  });
522
- return ConversationMaintenance.of({
523
+ return ThreadMaintenance.of({
523
524
  pass: alarm.withWakesDeferred(maintenancePassGate.withPermit(pass())),
524
525
  ensureAlarm: ensureAlarm(),
525
526
  withMutation
@@ -529,7 +530,7 @@ var ConversationMaintenance = class ConversationMaintenance extends Context.Serv
529
530
  //#endregion
530
531
  //#region src/client.ts
531
532
  /**
532
- * The Worker↔Conversation-Object host protocol (plan §1.4): Schema envelopes for the host
533
+ * The Worker↔Thread-Object host protocol (plan §1.4): Schema envelopes for the host
533
534
  * entry points (`submitEncoded`, `awaitSettlementEncoded`, `observePage`, `abortEncoded`,
534
535
  * `resolveApprovalEncoded`, `resolveUnknownEncoded`) plus the Worker-side client that speaks
535
536
  * it. Mirrors the WP2 port protocol: requests and responses are closed Schema unions, typed
@@ -540,15 +541,15 @@ var ConversationMaintenance = class ConversationMaintenance extends Context.Serv
540
541
  const MAX_HOST_DIAGNOSTIC_LENGTH = 4096;
541
542
  const BoundedDiagnostic = Schema.String.check(Schema.isMaxLength(MAX_HOST_DIAGNOSTIC_LENGTH));
542
543
  /** Truncate a diagnostic string to the host protocol's bounded length. */
543
- const boundHostDiagnostic = (value) => value.length > MAX_HOST_DIAGNOSTIC_LENGTH ? `${value.slice(0, MAX_HOST_DIAGNOSTIC_LENGTH - 3)}...` : value;
544
+ const boundHostDiagnostic = (value) => value.length > MAX_HOST_DIAGNOSTIC_LENGTH ? `${value.slice(0, 4093)}...` : value;
544
545
  /**
545
546
  * The envelope itself could not be honored: the Object could not decode the request, or a
546
547
  * response could not be encoded/decoded. Never carries operation semantics.
547
548
  */
548
549
  var HostProtocolError = class extends Schema.TaggedError()("HostProtocolError", { message: BoundedDiagnostic }) {};
549
550
  /** The Worker-side stub call itself failed (RPC rejection, overload, eviction mid-call). */
550
- var ConversationClientError = class extends Schema.TaggedError()("ConversationClientError", {
551
- conversationId: Schema.String,
551
+ var ThreadClientError = class extends Schema.TaggedError()("ThreadClientError", {
552
+ threadId: Schema.String,
552
553
  message: Schema.String,
553
554
  cause: Schema.optionalKey(Schema.Defect()),
554
555
  /** Cloudflare's own classification for a failure safe to retry with a fresh stub. */
@@ -560,7 +561,7 @@ var ConversationClientError = class extends Schema.TaggedError()("ConversationCl
560
561
  * One durable submission, input ALREADY encoded by the caller through the Agent Binding's
561
562
  * input schema (the Worker bundles the same Agent definitions as the Object, so schema
562
563
  * validation happens client-side; the resolved Binding re-validates at claim time). The
563
- * Conversation identity is deliberately absent — the addressed Object IS the lane.
564
+ * Thread identity is deliberately absent — the addressed Object IS the lane.
564
565
  */
565
566
  var SubmitRequest = class extends Schema.Class("@effect-agent/platform-cloudflare/SubmitRequest")({
566
567
  agentId: AgentId,
@@ -596,8 +597,8 @@ const HostFailure = Schema.Union([
596
597
  UnknownResolutionConflict,
597
598
  JoinedToHost,
598
599
  LedgerError,
599
- ConversationStoreError,
600
- ConversationNotMaterialized,
600
+ ThreadStoreError,
601
+ ThreadNotMaterialized,
601
602
  AppendConflict,
602
603
  FenceRejected,
603
604
  DurableRuntimeFailpointError,
@@ -647,14 +648,14 @@ const decodeUnknownResolutionCommand = Schema.decodeUnknownEffect(UnknownResolut
647
648
  const encodeUnknownResolutionCommand = Schema.encodeEffect(UnknownResolutionCommand);
648
649
  const encodeHostResponse = Schema.encodeEffect(HostResponse);
649
650
  const decodeHostResponse = Schema.decodeUnknownEffect(HostResponse);
650
- /** Failure surface of `CloudflareConversationClient.submit`. */
651
+ /** Failure surface of `CloudflareThreadClient.submit`. */
651
652
  const ClientSubmitHostFailure = Schema.Union([
652
653
  AgentInputError,
653
654
  DigestError,
654
655
  AdmissionConflict,
655
656
  LedgerError,
656
- ConversationStoreError,
657
- ConversationNotMaterialized,
657
+ ThreadStoreError,
658
+ ThreadNotMaterialized,
658
659
  AppendConflict,
659
660
  FenceRejected,
660
661
  DurableRuntimeFailpointError,
@@ -665,15 +666,17 @@ const ClientSubmitHostFailure = Schema.Union([
665
666
  const ClientAwaitHostFailure = Schema.Union([
666
667
  LedgerError,
667
668
  SettlementConflict,
669
+ OperationDenied,
668
670
  HostProtocolError
669
671
  ]);
670
672
  const ClientObserveHostFailure = Schema.Union([
671
- ConversationStoreError,
672
- ConversationNotMaterialized,
673
+ ThreadStoreError,
674
+ ThreadNotMaterialized,
673
675
  OperationDenied,
674
676
  HostProtocolError
675
677
  ]);
676
678
  const ClientAbortHostFailure = Schema.Union([
679
+ OperationDenied,
677
680
  LedgerError,
678
681
  SettlementConflict,
679
682
  JoinedToHost,
@@ -699,9 +702,9 @@ const ClientUnknownHostFailure = Schema.Union([
699
702
  DurableAlarmError,
700
703
  HostProtocolError
701
704
  ]);
702
- const outOfContract = (conversationId, operation, observed) => ConversationClientError.make({
703
- conversationId,
704
- message: boundHostDiagnostic(`The Conversation Object answered ${operation} with the out-of-contract ${observed}.`)
705
+ const outOfContract = (threadId, operation, observed) => ThreadClientError.make({
706
+ threadId,
707
+ message: boundHostDiagnostic(`The Thread Object answered ${operation} with the out-of-contract ${observed}.`)
705
708
  });
706
709
  const hostRpcMethods = {
707
710
  submit: "submitEncoded",
@@ -713,52 +716,60 @@ const hostRpcMethods = {
713
716
  resolveApproval: "resolveApprovalEncoded",
714
717
  resolveUnknown: "resolveUnknownEncoded"
715
718
  };
716
- /** Worker-side client over the Conversation Object namespace (DEPLOY-010). */
717
- var CloudflareConversationClient = class CloudflareConversationClient extends Context.Service()("@effect-agent/platform-cloudflare/CloudflareConversationClient") {
718
- static layer = Layer.effect(CloudflareConversationClient)(Effect.gen(function* () {
719
- const { namespace, rpcTracing } = yield* ConversationObjectNamespace;
719
+ /** Worker-side client over the Thread Object namespace (DEPLOY-010). */
720
+ var CloudflareThreadClient = class CloudflareThreadClient extends Context.Service()("@effect-agent/platform-cloudflare/CloudflareThreadClient") {
721
+ /**
722
+ * Assemble the client from a resolved namespace and the platform Crypto implementation.
723
+ * rpcTracing is the binding name and remains opt-in. Caller authentication, principals,
724
+ * idempotency keys, and definition digests are still explicit submission inputs.
725
+ */
726
+ static layerFromBinding(options) {
727
+ return CloudflareThreadClient.layer.pipe(Layer.provide([ThreadObjectNamespace.layer(options.namespace, options), BrowserCrypto.layer]));
728
+ }
729
+ static layer = Layer.effect(CloudflareThreadClient)(Effect.gen(function* () {
730
+ const { namespace, rpcTracing } = yield* ThreadObjectNamespace;
720
731
  const crypto = yield* Crypto.Crypto;
721
- const call = Effect.fn(function* (conversationId, operation, encoded) {
732
+ const call = Effect.fn(function* (threadId, operation, encoded) {
722
733
  const traceArgs = rpcTracing === void 0 ? [] : yield* RpcTracing.withRpcTraceContext([]);
723
734
  const raw = yield* Effect.tryPromise({
724
735
  try: () => {
725
- return namespace.get(namespace.idFromName(conversationId))[hostRpcMethods[operation]](encoded, ...traceArgs);
736
+ return namespace.get(namespace.idFromName(threadId))[hostRpcMethods[operation]](encoded, ...traceArgs);
726
737
  },
727
- catch: (cause) => ConversationClientError.make({
728
- conversationId,
729
- message: boundHostDiagnostic(`${operation} did not reach the Conversation Object: ${safeCauseMessage(cause, "the RPC failed without a diagnostic")}`),
738
+ catch: (cause) => ThreadClientError.make({
739
+ threadId,
740
+ message: boundHostDiagnostic(`${operation} did not reach the Thread Object: ${safeCauseMessage(cause, "the RPC failed without a diagnostic")}`),
730
741
  cause,
731
742
  ...cloudflareFailureSignals(cause)
732
743
  })
733
744
  });
734
745
  return yield* decodeHostResponse(raw).pipe(Effect.mapError((error) => HostProtocolError.make({ message: boundHostDiagnostic(`The ${operation} answer could not be decoded: ${error.message}`) })));
735
- }, (effect, conversationId, operation) => rpcTracing === void 0 ? Effect.withSpan(effect, "CloudflareConversationClient.call", { attributes: {
736
- conversationId,
746
+ }, (effect, threadId, operation) => rpcTracing === void 0 ? Effect.withSpan(effect, "CloudflareThreadClient.call", { attributes: {
747
+ threadId,
737
748
  operation
738
749
  } }) : RpcTracing.withRpcClientSpan(effect, rpcTracing, hostRpcMethods[operation]));
739
- const expect = (conversationId, operation, resultSchema, failureSchema) => {
750
+ const expect = (threadId, operation, resultSchema, failureSchema) => {
740
751
  const isExpectedResult = Schema.is(resultSchema);
741
752
  const isExpectedFailure = Schema.is(failureSchema);
742
753
  return (response) => {
743
754
  if (response._tag === "HostFailed") {
744
755
  const failure = response.failure;
745
- return isExpectedFailure(failure) ? Effect.fail(failure) : Effect.fail(outOfContract(conversationId, operation, `failure ${failure._tag}`));
756
+ return isExpectedFailure(failure) ? Effect.fail(failure) : Effect.fail(outOfContract(threadId, operation, `failure ${failure._tag}`));
746
757
  }
747
- if (!isExpectedResult(response)) return Effect.fail(outOfContract(conversationId, operation, `result ${response._tag}`));
758
+ if (!isExpectedResult(response)) return Effect.fail(outOfContract(threadId, operation, `result ${response._tag}`));
748
759
  return Effect.succeed(response);
749
760
  };
750
761
  };
751
- const readPage = (conversationId, options) => Effect.gen(function* () {
762
+ const readPage = (threadId, options) => Effect.gen(function* () {
752
763
  const request = ObservePageRequest.make({
753
764
  ...options?.afterSequence === void 0 ? {} : { afterSequence: options.afterSequence },
754
765
  limit: options?.limit ?? 256
755
766
  });
756
767
  const encoded = yield* encodeObservePageRequest(request).pipe(Effect.mapError((error) => HostProtocolError.make({ message: boundHostDiagnostic(`observePage request encode failed: ${error.message}`) })));
757
- const response = yield* call(conversationId, "observePage", encoded);
758
- return (yield* expect(conversationId, "observePage", ObservedPage, ClientObserveHostFailure)(response)).records;
768
+ const response = yield* call(threadId, "observePage", encoded);
769
+ return (yield* expect(threadId, "observePage", ObservedPage, ClientObserveHostFailure)(response)).records;
759
770
  });
760
- const cancelProgress = (conversationId, waiterId) => encodeCancelProgressRequest(CancelProgressRequest.make({ waiterId })).pipe(Effect.mapError(() => void 0), Effect.flatMap((encoded) => call(conversationId, "cancelProgress", encoded)), Effect.asVoid, Effect.ignore);
761
- return CloudflareConversationClient.of({
771
+ const cancelProgress = (threadId, waiterId) => encodeCancelProgressRequest(CancelProgressRequest.make({ waiterId })).pipe(Effect.mapError(() => void 0), Effect.flatMap((encoded) => call(threadId, "cancelProgress", encoded)), Effect.asVoid, Effect.ignore);
772
+ return CloudflareThreadClient.of({
762
773
  submit: (agent, input, options) => Effect.gen(function* () {
763
774
  const encodedInput = yield* Schema.encodeEffect(agent.definition.input)(input).pipe(Effect.mapError((cause) => AgentInputError.make({ message: `Unable to encode Agent input: ${cause.message}` })));
764
775
  const inputPayload = yield* Schema.decodeUnknownEffect(PersistedJson)(encodedInput).pipe(Effect.mapError(() => AgentInputError.make({ message: "Agent input does not satisfy the canonical persistence bounds" })));
@@ -770,30 +781,30 @@ var CloudflareConversationClient = class CloudflareConversationClient extends Co
770
781
  inputPayload
771
782
  });
772
783
  const encoded = yield* encodeSubmitRequest(request).pipe(Effect.mapError((error) => HostProtocolError.make({ message: boundHostDiagnostic(`submit request encode failed: ${error.message}`) })));
773
- const response = yield* call(options.conversationId, "submit", encoded);
774
- return (yield* expect(options.conversationId, "submit", SubmitSucceeded, ClientSubmitHostFailure)(response)).receipt;
784
+ const response = yield* call(options.threadId, "submit", encoded);
785
+ return (yield* expect(options.threadId, "submit", SubmitSucceeded, ClientSubmitHostFailure)(response)).receipt;
775
786
  }),
776
787
  awaitSettlement: (receipt) => Effect.gen(function* () {
777
788
  const encoded = yield* encodeReceipt(receipt).pipe(Effect.mapError((error) => HostProtocolError.make({ message: boundHostDiagnostic(`receipt encode failed: ${error.message}`) })));
778
- const response = yield* call(receipt.conversationId, "awaitSettlement", encoded);
779
- return (yield* expect(receipt.conversationId, "awaitSettlement", SettlementReached, ClientAwaitHostFailure)(response)).settlement;
789
+ const response = yield* call(receipt.threadId, "awaitSettlement", encoded);
790
+ return (yield* expect(receipt.threadId, "awaitSettlement", SettlementReached, ClientAwaitHostFailure)(response)).settlement;
780
791
  }),
781
- awaitProgress: (conversationId, afterSequence) => Effect.gen(function* () {
792
+ awaitProgress: (threadId, afterSequence) => Effect.gen(function* () {
782
793
  const waiterId = yield* crypto.randomUUIDv4.pipe(Effect.mapError((error) => HostProtocolError.make({ message: boundHostDiagnostic(`awaitProgress cancellation identity generation failed: ${error.message}`) })));
783
794
  const request = AwaitProgressRequest.make({
784
795
  afterSequence,
785
796
  waiterId
786
797
  });
787
798
  const encoded = yield* encodeAwaitProgressRequest(request).pipe(Effect.mapError((error) => HostProtocolError.make({ message: boundHostDiagnostic(`awaitProgress request encode failed: ${error.message}`) })));
788
- const attempt = (retry) => call(conversationId, "awaitProgress", encoded).pipe(Effect.flatMap(expect(conversationId, "awaitProgress", ProgressObserved, ClientObserveHostFailure)), Effect.asVoid, Effect.catchTag("ConversationClientError", (error) => error.retryable === true && error.overloaded !== true && retry < 5 ? Effect.sleep(Duration.millis(10 * 2 ** retry)).pipe(Effect.andThen(attempt(retry + 1))) : Effect.fail(error)));
789
- yield* attempt(0).pipe(Effect.onInterrupt(() => cancelProgress(conversationId, waiterId)));
799
+ const attempt = (retry) => call(threadId, "awaitProgress", encoded).pipe(Effect.flatMap(expect(threadId, "awaitProgress", ProgressObserved, ClientObserveHostFailure)), Effect.asVoid, Effect.catchTag("ThreadClientError", (error) => error.retryable === true && error.overloaded !== true && retry < 5 ? Effect.sleep(Duration.millis(10 * 2 ** retry)).pipe(Effect.andThen(attempt(retry + 1))) : Effect.fail(error)));
800
+ yield* attempt(0).pipe(Effect.onInterrupt(() => cancelProgress(threadId, waiterId)));
790
801
  }),
791
802
  readPage,
792
- readAll: (conversationId) => Effect.gen(function* () {
803
+ readAll: (threadId) => Effect.gen(function* () {
793
804
  const all = [];
794
805
  let after;
795
806
  for (;;) {
796
- const page = yield* readPage(conversationId, {
807
+ const page = yield* readPage(threadId, {
797
808
  afterSequence: after,
798
809
  limit: 1024
799
810
  });
@@ -803,387 +814,77 @@ var CloudflareConversationClient = class CloudflareConversationClient extends Co
803
814
  after = last.sequence;
804
815
  }
805
816
  }),
806
- abort: (conversationId, command) => Effect.gen(function* () {
817
+ abort: (threadId, command) => Effect.gen(function* () {
807
818
  const encoded = yield* encodeAbortCommand(command).pipe(Effect.mapError((error) => HostProtocolError.make({ message: boundHostDiagnostic(`abort command encode failed: ${error.message}`) })));
808
- const response = yield* call(conversationId, "abort", encoded);
809
- return (yield* expect(conversationId, "abort", AbortRecorded, ClientAbortHostFailure)(response)).intent;
819
+ const response = yield* call(threadId, "abort", encoded);
820
+ return (yield* expect(threadId, "abort", AbortRecorded, ClientAbortHostFailure)(response)).intent;
810
821
  }),
811
- resolveApproval: (conversationId, command) => Effect.gen(function* () {
822
+ resolveApproval: (threadId, command) => Effect.gen(function* () {
812
823
  const encoded = yield* encodeApprovalDecisionCommand(command).pipe(Effect.mapError((error) => HostProtocolError.make({ message: boundHostDiagnostic(`approval command encode failed: ${error.message}`) })));
813
- const response = yield* call(conversationId, "resolveApproval", encoded);
814
- return (yield* expect(conversationId, "resolveApproval", ApprovalRecorded, ClientApprovalHostFailure)(response)).intent;
824
+ const response = yield* call(threadId, "resolveApproval", encoded);
825
+ return (yield* expect(threadId, "resolveApproval", ApprovalRecorded, ClientApprovalHostFailure)(response)).intent;
815
826
  }),
816
- resolveUnknown: (conversationId, command) => Effect.gen(function* () {
827
+ resolveUnknown: (threadId, command) => Effect.gen(function* () {
817
828
  const encoded = yield* encodeUnknownResolutionCommand(command).pipe(Effect.mapError((error) => HostProtocolError.make({ message: boundHostDiagnostic(`resolution command encode failed: ${error.message}`) })));
818
- const response = yield* call(conversationId, "resolveUnknown", encoded);
819
- return (yield* expect(conversationId, "resolveUnknown", UnknownResolutionRecorded, ClientUnknownHostFailure)(response)).intent;
829
+ const response = yield* call(threadId, "resolveUnknown", encoded);
830
+ return (yield* expect(threadId, "resolveUnknown", UnknownResolutionRecorded, ClientUnknownHostFailure)(response)).intent;
820
831
  })
821
832
  });
822
833
  }));
823
834
  };
824
835
  //#endregion
825
- //#region src/scheduling.ts
826
- const SCHEDULE_ALARM_TAG = "effect-agent/ScheduleOwnerWake";
827
- const SCHEDULE_ALARM_ID = "driver";
828
- const ScheduleAlarmPayload = Schema.Struct({
829
- schemaVersion: Schema.Literal(1),
830
- generation: Schema.Int.check(Schema.isGreaterThan(0))
831
- });
832
- var ScheduleAlarmProtocolError = class extends Schema.TaggedError()("ScheduleAlarmProtocolError", { message: Schema.String }) {};
833
- const boundedProtocolMessage = (message) => message.length <= 4096 ? message : `${message.slice(0, 4093)}...`;
834
- var ScheduleOwnerProtocolError = class extends Schema.TaggedError()("ScheduleOwnerProtocolError", { message: Schema.String.check(Schema.isMaxLength(4096)) }) {};
835
- const ScheduleMutationRequestFields = {
836
- schemaVersion: Schema.Literal(1),
837
- agentId: AgentId,
838
- input: PersistedJson,
839
- scope: ScheduleScope,
840
- scheduleId: ScheduleId,
841
- timing: ScheduleTimingRequest,
842
- destination: ScheduleDestination,
843
- deliveryPrincipal: ScheduleScope.fields.principal,
844
- definitions: DefinitionDigests
845
- };
846
- const ScheduleCreateRequest = Schema.TaggedStruct("Create", ScheduleMutationRequestFields);
847
- const ScheduleUpdateRequest = Schema.TaggedStruct("Update", {
848
- ...ScheduleMutationRequestFields,
849
- expectedRevision: Schema.Int.check(Schema.isGreaterThan(0))
850
- });
851
- const ScheduleGetRequest = Schema.TaggedStruct("Get", {
852
- schemaVersion: Schema.Literal(1),
853
- scope: ScheduleScope,
854
- scheduleId: ScheduleId
855
- });
856
- const ScheduleListRequest = Schema.TaggedStruct("List", {
857
- schemaVersion: Schema.Literal(1),
858
- scope: ScheduleScope,
859
- after: Schema.optionalKey(ScheduleId),
860
- limit: Schema.optionalKey(Schema.Int.check(Schema.isGreaterThan(0), Schema.isLessThanOrEqualTo(100)))
861
- });
862
- const ScheduleControlRequest = Schema.TaggedStruct("Control", {
863
- schemaVersion: Schema.Literal(1),
864
- operation: Schema.Literals([
865
- "pause",
866
- "resume",
867
- "cancel"
868
- ]),
869
- scope: ScheduleScope,
870
- scheduleId: ScheduleId,
871
- expectedRevision: Schema.Int.check(Schema.isGreaterThan(0))
872
- });
873
- const ScheduleOwnerRequest = Schema.Union([
874
- ScheduleCreateRequest,
875
- ScheduleUpdateRequest,
876
- ScheduleGetRequest,
877
- ScheduleListRequest,
878
- ScheduleControlRequest
879
- ]);
880
- const ScheduleOwnerFailure = Schema.Union([
881
- ScheduleValidationError,
882
- ScheduleAuthorizationError,
883
- ScheduleConflict,
884
- ScheduleNotFound,
885
- ScheduleCapacityError,
886
- ScheduleStorageError,
887
- ScheduleFailpointError,
888
- ScheduleOwnerProtocolError
889
- ]);
890
- const ScheduleOwnerResponse = Schema.Union([
891
- Schema.TaggedStruct("Snapshot", { value: ScheduleSnapshot }),
892
- Schema.TaggedStruct("Page", { value: ScheduleSnapshotPage }),
893
- Schema.TaggedStruct("Failed", { failure: ScheduleOwnerFailure })
894
- ]);
895
- const decodeScheduleOwnerRequest = Schema.decodeUnknownEffect(ScheduleOwnerRequest);
896
- const encodeScheduleOwnerRequest = Schema.encodeEffect(ScheduleOwnerRequest);
897
- const decodeScheduleOwnerResponse = Schema.decodeUnknownEffect(ScheduleOwnerResponse);
898
- const encodeScheduleOwnerResponse = Schema.encodeEffect(ScheduleOwnerResponse);
899
- const scheduleProtocolFailure = (message) => ({
900
- _tag: "Failed",
901
- failure: ScheduleOwnerProtocolError.make({ message: boundedProtocolMessage(message) })
902
- });
903
- var ScheduleOwnerNamespace = class extends Context.Service()("@effect-agent/platform-cloudflare/ScheduleOwnerNamespace") {};
836
+ //#region src/prepared-admission.ts
904
837
  const passthroughAgent = (agentId) => ({ definition: {
905
838
  id: agentId,
906
839
  input: PersistedJson
907
840
  } });
908
- const requestOwner = (request) => request.scope.owner;
909
- /** Provides the same authorized management service as NodeScheduling.layer. */
910
- var CloudflareSchedulingClient = class {
911
- static layer = Layer.effect(Scheduling, Effect.gen(function* () {
912
- const { namespace } = yield* ScheduleOwnerNamespace;
913
- const call = Effect.fn("CloudflareSchedulingClient.call")(function* (owner, request) {
914
- const encoded = yield* encodeScheduleOwnerRequest(request).pipe(Effect.mapError(() => ScheduleStorageError.make({
915
- operation: "Schedule Owner protocol",
916
- reason: "corrupt"
917
- })));
918
- const raw = yield* Effect.tryPromise({
919
- try: () => namespace.get(namespace.idFromName(scheduleOwnerKey(owner))).schedule(encoded),
920
- catch: () => ScheduleStorageError.make({
921
- operation: "call Schedule Owner",
922
- reason: "unavailable"
923
- })
924
- });
925
- const response = yield* decodeScheduleOwnerResponse(raw).pipe(Effect.mapError(() => ScheduleStorageError.make({
926
- operation: "Schedule Owner protocol",
927
- reason: "corrupt"
928
- })));
929
- if (response._tag !== "Failed") return response;
930
- return yield* response.failure._tag === "ScheduleOwnerProtocolError" ? ScheduleStorageError.make({
931
- operation: "Schedule Owner protocol",
932
- reason: "corrupt"
933
- }) : response.failure;
934
- });
935
- const encodeInput = Effect.fn("CloudflareSchedulingClient.encodeInput")(function* (agent, input) {
936
- const encoded = yield* Schema.encodeEffect(agent.definition.input)(input).pipe(Effect.mapError(() => ScheduleValidationError.make({ message: "Unable to encode Agent input" })));
937
- return yield* Schema.decodeUnknownEffect(PersistedJson)(encoded).pipe(Effect.mapError(() => ScheduleValidationError.make({ message: "Agent input does not satisfy the canonical persistence bounds" })));
938
- });
939
- const create = (agent, input, options) => Effect.gen(function* () {
940
- const payload = yield* encodeInput(agent, input);
941
- const response = yield* call(options.scope.owner, {
942
- _tag: "Create",
943
- schemaVersion: 1,
944
- agentId: agent.definition.id,
945
- input: payload,
946
- ...options
947
- });
948
- return response._tag === "Snapshot" ? response.value : yield* ScheduleStorageError.make({
949
- operation: "Schedule Owner protocol",
950
- reason: "corrupt"
951
- });
952
- });
953
- const update = (agent, input, options) => Effect.gen(function* () {
954
- const payload = yield* encodeInput(agent, input);
955
- const response = yield* call(options.scope.owner, {
956
- _tag: "Update",
957
- schemaVersion: 1,
958
- agentId: agent.definition.id,
959
- input: payload,
960
- ...options
961
- });
962
- return response._tag === "Snapshot" ? response.value : yield* ScheduleStorageError.make({
963
- operation: "Schedule Owner protocol",
964
- reason: "corrupt"
965
- });
966
- });
967
- const get = (scope, scheduleId) => Effect.gen(function* () {
968
- const response = yield* call(scope.owner, {
969
- _tag: "Get",
970
- schemaVersion: 1,
971
- scope,
972
- scheduleId
973
- });
974
- return response._tag === "Snapshot" ? response.value : yield* ScheduleStorageError.make({
975
- operation: "Schedule Owner protocol",
976
- reason: "corrupt"
977
- });
978
- });
979
- const list = (scope, options = {}) => Effect.gen(function* () {
980
- const response = yield* call(scope.owner, {
981
- _tag: "List",
982
- schemaVersion: 1,
983
- scope,
984
- ...options.after === void 0 ? {} : { after: options.after },
985
- ...options.limit === void 0 ? {} : { limit: options.limit }
986
- });
987
- return response._tag === "Page" ? response.value : yield* ScheduleStorageError.make({
988
- operation: "Schedule Owner protocol",
989
- reason: "corrupt"
990
- });
991
- });
992
- const control = (operation, scope, scheduleId, expectedRevision) => Effect.gen(function* () {
993
- const response = yield* call(scope.owner, {
994
- _tag: "Control",
995
- schemaVersion: 1,
996
- operation,
997
- scope,
998
- scheduleId,
999
- expectedRevision
1000
- });
1001
- return response._tag === "Snapshot" ? response.value : yield* ScheduleStorageError.make({
1002
- operation: "Schedule Owner protocol",
1003
- reason: "corrupt"
1004
- });
1005
- });
1006
- return Scheduling.of({
1007
- create,
1008
- update,
1009
- get,
1010
- list,
1011
- pause: (scope, id, revision) => control("pause", scope, id, revision),
1012
- resume: (scope, id, revision) => control("resume", scope, id, revision),
1013
- cancel: (scope, id, revision) => control("cancel", scope, id, revision)
1014
- });
1015
- }));
1016
- };
1017
- var ScheduleOwnerIdentity = class extends Context.Service()("@effect-agent/platform-cloudflare/ScheduleOwnerIdentity") {};
1018
- const decodeOwnerName = Effect.fn("decodeScheduleOwnerName")(function* (name) {
1019
- if (name === null || name === void 0) return yield* ScheduleOwnerProtocolError.make({ message: "Schedule Owner objects require an idFromName identity" });
1020
- const tuple = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(Schema.Tuple([Schema.String, Schema.String])))(name).pipe(Effect.mapError(() => ScheduleOwnerProtocolError.make({ message: "Schedule Owner object name is malformed" })));
1021
- return yield* Schema.decodeUnknownEffect(ScheduleOwner)({
1022
- tenantId: tuple[0],
1023
- ownerId: tuple[1]
1024
- }).pipe(Effect.mapError(() => ScheduleOwnerProtocolError.make({ message: "Schedule Owner object identity is invalid" })));
1025
- });
1026
- const alarmStorageError = (operation) => (error) => ScheduleStorageError.make({
1027
- operation,
1028
- reason: error._tag === "StorageOperationError" ? "unavailable" : "corrupt"
1029
- });
1030
- const transactionLayer = Layer.effect(DoScheduleTransaction, Effect.gen(function* () {
1031
- const alarms = yield* DurableObjectAlarm.DurableObjectAlarm;
1032
- return DoScheduleTransaction.of({ run: (body) => Effect.gen(function* () {
1033
- const nowMillis = yield* Clock.currentTimeMillis;
1034
- return yield* alarms.transaction((transaction) => body((replacement) => replacement.deadlineAtMillis === null ? transaction.cancelAlarm({
1035
- id: SCHEDULE_ALARM_ID,
1036
- tag: SCHEDULE_ALARM_TAG
1037
- }).pipe(Effect.mapError(alarmStorageError("cancel Schedule Owner alarm"))) : Effect.fromOption(DateTime.make(Math.max(replacement.deadlineAtMillis, nowMillis + 1))).pipe(Effect.mapError(() => ScheduleStorageError.make({
1038
- operation: "validate Schedule Owner alarm deadline",
1039
- reason: "corrupt"
1040
- })), Effect.flatMap((runAt) => transaction.scheduleAlarm({
1041
- id: SCHEDULE_ALARM_ID,
1042
- tag: SCHEDULE_ALARM_TAG,
1043
- runAt,
1044
- payload: {
1045
- schemaVersion: 1,
1046
- generation: replacement.generation
1047
- }
1048
- }).pipe(Effect.mapError(alarmStorageError("schedule Schedule Owner alarm"))))))).pipe(Effect.catchTag("StorageOperationError", () => ScheduleStorageError.make({
1049
- operation: "commit Schedule Owner transaction",
1050
- reason: "unavailable"
1051
- })));
1052
- }) });
1053
- }));
1054
- const admissionLayer = Layer.effect(ScheduledInputAdmission, Effect.gen(function* () {
1055
- const client = yield* CloudflareConversationClient;
1056
- const submit = (envelope) => client.submit(passthroughAgent(envelope.agentId), envelope.input, {
1057
- conversationId: envelope.conversationId,
841
+ /** Ordinary prepared admission through one freshly addressed Thread Object call. */
842
+ const cloudflarePreparedInputAdmissionLayer = Layer.effect(PreparedInputAdmission, Effect.gen(function* () {
843
+ const client = yield* CloudflareThreadClient;
844
+ return PreparedInputAdmission.of({ submit: (envelope) => client.submit(passthroughAgent(envelope.agentId), envelope.input, {
845
+ threadId: envelope.threadId,
1058
846
  principal: envelope.deliveryPrincipal,
1059
847
  idempotencyKey: envelope.admissionKey,
1060
848
  definitions: envelope.definitions
1061
849
  }).pipe(Effect.catchTags({
1062
850
  AdmissionConflict: () => ScheduleStorageError.make({
1063
- operation: "scheduled admission",
851
+ operation: "prepared admission",
1064
852
  reason: "corrupt"
1065
853
  }),
1066
854
  AdmissionLimitExceeded: () => ScheduledInputRetryable.make({ reason: "capacity" }),
1067
- ConversationClientError: (error) => ScheduledInputRetryable.make({ reason: error.overloaded === true ? "capacity" : "transport" }),
855
+ ThreadClientError: (error) => ScheduledInputRetryable.make({ reason: error.overloaded === true ? "capacity" : "transport" }),
1068
856
  HostProtocolError: () => ScheduledInputRetryable.make({ reason: "ambiguous" }),
1069
857
  LedgerError: () => ScheduledInputRetryable.make({ reason: "storage" }),
1070
- ConversationStoreError: () => ScheduledInputRetryable.make({ reason: "storage" }),
858
+ ThreadStoreError: () => ScheduledInputRetryable.make({ reason: "storage" }),
1071
859
  DurableAlarmError: () => ScheduledInputRetryable.make({ reason: "storage" }),
1072
860
  AgentInputError: () => ScheduleStorageError.make({
1073
- operation: "scheduled admission",
861
+ operation: "prepared admission",
1074
862
  reason: "corrupt"
1075
863
  }),
1076
864
  DigestError: () => ScheduleStorageError.make({
1077
- operation: "scheduled admission",
865
+ operation: "prepared admission",
1078
866
  reason: "corrupt"
1079
867
  }),
1080
- ConversationNotMaterialized: () => ScheduledInputRetryable.make({ reason: "storage" }),
868
+ ThreadNotMaterialized: () => ScheduledInputRetryable.make({ reason: "storage" }),
1081
869
  AppendConflict: () => ScheduledInputRetryable.make({ reason: "ambiguous" }),
1082
870
  FenceRejected: () => ScheduledInputRetryable.make({ reason: "ambiguous" }),
1083
871
  DurableRuntimeFailpointError: () => ScheduledInputRetryable.make({ reason: "ambiguous" })
1084
- }));
1085
- return ScheduledInputAdmission.of({ submit });
872
+ })) });
1086
873
  }));
1087
- const ensureOwner = (expected, request) => {
1088
- const observed = requestOwner(request);
1089
- return observed.tenantId === expected.tenantId && observed.ownerId === expected.ownerId ? Effect.void : Effect.fail(ScheduleOwnerProtocolError.make({ message: "The request owner does not match the addressed Schedule Owner object" }));
1090
- };
1091
- const handleScheduleRequest = Effect.fn("ScheduleOwner.handleRequest")(function* (encoded) {
1092
- const decoded = yield* decodeScheduleOwnerRequest(encoded).pipe(Effect.result);
1093
- if (decoded._tag === "Failure") return yield* encodeScheduleOwnerResponse(scheduleProtocolFailure("The Schedule request could not be decoded")).pipe(Effect.orDie);
1094
- const request = decoded.success;
1095
- const { owner } = yield* ScheduleOwnerIdentity;
1096
- const scheduling = yield* Scheduling;
1097
- const response = yield* Effect.gen(function* () {
1098
- yield* ensureOwner(owner, request);
1099
- switch (request._tag) {
1100
- case "Create": return {
1101
- _tag: "Snapshot",
1102
- value: yield* scheduling.create(passthroughAgent(request.agentId), request.input, {
1103
- scope: request.scope,
1104
- scheduleId: request.scheduleId,
1105
- timing: request.timing,
1106
- destination: request.destination,
1107
- deliveryPrincipal: request.deliveryPrincipal,
1108
- definitions: request.definitions
1109
- })
1110
- };
1111
- case "Update": return {
1112
- _tag: "Snapshot",
1113
- value: yield* scheduling.update(passthroughAgent(request.agentId), request.input, {
1114
- scope: request.scope,
1115
- scheduleId: request.scheduleId,
1116
- timing: request.timing,
1117
- destination: request.destination,
1118
- deliveryPrincipal: request.deliveryPrincipal,
1119
- definitions: request.definitions,
1120
- expectedRevision: request.expectedRevision
1121
- })
1122
- };
1123
- case "Get": return {
1124
- _tag: "Snapshot",
1125
- value: yield* scheduling.get(request.scope, request.scheduleId)
1126
- };
1127
- case "List": return {
1128
- _tag: "Page",
1129
- value: yield* scheduling.list(request.scope, {
1130
- ...request.after === void 0 ? {} : { after: request.after },
1131
- ...request.limit === void 0 ? {} : { limit: request.limit }
1132
- })
1133
- };
1134
- case "Control": return {
1135
- _tag: "Snapshot",
1136
- value: request.operation === "pause" ? yield* scheduling.pause(request.scope, request.scheduleId, request.expectedRevision) : request.operation === "resume" ? yield* scheduling.resume(request.scope, request.scheduleId, request.expectedRevision) : yield* scheduling.cancel(request.scope, request.scheduleId, request.expectedRevision)
1137
- };
1138
- }
1139
- }).pipe(Effect.map((value) => value), Effect.catch((failure) => Schema.is(ScheduleOwnerFailure)(failure) ? Effect.succeed({
1140
- _tag: "Failed",
1141
- failure
1142
- }) : Effect.succeed(scheduleProtocolFailure("The Schedule operation failed outside its public contract"))));
1143
- return yield* encodeScheduleOwnerResponse(response).pipe(Effect.orDie);
874
+ const preparedFromSchedule = (envelope) => ({
875
+ schemaVersion: 1,
876
+ threadId: envelope.threadId,
877
+ deliveryPrincipal: envelope.deliveryPrincipal,
878
+ agentId: envelope.agentId,
879
+ definitions: envelope.definitions,
880
+ input: envelope.input,
881
+ inputDigest: envelope.inputDigest,
882
+ admissionKey: envelope.admissionKey,
883
+ authorization: envelope.authorization
1144
884
  });
1145
- const scheduleAlarmHandler = (limits) => DurableObjectAlarm.processDue((event) => Effect.gen(function* () {
1146
- if (event.tag !== SCHEDULE_ALARM_TAG || event.id !== SCHEDULE_ALARM_ID) return yield* ScheduleAlarmProtocolError.make({ message: `Unsupported Schedule Owner alarm ${event.tag}/${event.id}` });
1147
- yield* Schema.decodeUnknownEffect(ScheduleAlarmPayload)(event.payload).pipe(Effect.mapError(() => ScheduleAlarmProtocolError.make({ message: "Unsupported Schedule Owner alarm payload version" })));
1148
- const scheduling = yield* ScheduleDriver;
1149
- const alarmControl = yield* DoScheduleAlarmControl;
1150
- const { owner } = yield* ScheduleOwnerIdentity;
1151
- const nowMillis = yield* Clock.currentTimeMillis;
1152
- yield* alarmControl.prearm(nowMillis + limits.recoveryPollMillis);
1153
- if ((yield* scheduling.runDue(owner)).failed > 0) yield* alarmControl.prearm((yield* Clock.currentTimeMillis) + limits.recoveryPollMillis);
1154
- else yield* alarmControl.reconcile;
1155
- }), { mode: "ordered" }).pipe(Effect.asVoid);
1156
- /**
1157
- * The host Layer supplies authorization and routing and is cached for the object incarnation.
1158
- * Cloudflare eviction does not guarantee its finalizers run. Do not acquire resources requiring
1159
- * cleanup in this Layer; acquire them inside scoped `manage` / `prepare` operations instead.
1160
- * Native services belong to effect-cf; the database and alarm runtime remain instance-owned.
1161
- */
1162
- const makeScheduleOwnerObjectClass = (host, limits = defaultSchedulingLimits) => {
1163
- const ownerLayer = Layer.effect(ScheduleOwnerIdentity, Effect.gen(function* () {
1164
- const state = yield* DurableObjectState.DurableObjectState;
1165
- return ScheduleOwnerIdentity.of({ owner: yield* decodeOwnerName(state.raw.id.name) });
1166
- }));
1167
- const sqlLayer = Layer.unwrap(Effect.map(DurableObjectState.DurableObjectState, (state) => SqliteClient.layer({ storage: state.raw.storage })));
1168
- const application = Layer.merge(Scheduling.layer(limits), ScheduleDriver.layer(limits)).pipe(Layer.provideMerge(scheduleStoreLayer.pipe(Layer.provide(transactionLayer), Layer.provide(sqlLayer))), Layer.provide(admissionLayer.pipe(Layer.provide(CloudflareConversationClient.layer))), Layer.provide(ScheduleWakeNoop), Layer.provide(BrowserCrypto.layer), Layer.provideMerge(DurableObjectAlarm.DurableObjectAlarm.layer), Layer.provide(host), Layer.provideMerge(ownerLayer));
1169
- const runtime = Layer.effectContext(Effect.gen(function* () {
1170
- const state = yield* DurableObjectState.DurableObjectState;
1171
- const scope = yield* Effect.scope;
1172
- return yield* state.blockConcurrencyWhile(Layer.buildWithScope(application, scope));
1173
- }));
1174
- const Base = DurableObject.make(runtime, {
1175
- initialize: Effect.void,
1176
- rpc: { schedule: (encoded) => handleScheduleRequest(encoded) },
1177
- alarms: scheduleAlarmHandler(limits)
1178
- });
1179
- class ScheduleOwnerObject extends Base {
1180
- alarm(alarmInfo) {
1181
- return super.alarm?.(alarmInfo);
1182
- }
1183
- }
1184
- return ScheduleOwnerObject;
1185
- };
885
+ /** Compatibility adapter retaining Scheduling's public admission port. */
886
+ const cloudflareScheduledInputAdmissionLayer = Layer.effect(ScheduledInputAdmission, Effect.map(PreparedInputAdmission, (admission) => ScheduledInputAdmission.of({ submit: (envelope) => admission.submit(preparedFromSchedule(envelope)) })));
1186
887
  //#endregion
1187
- export { CLOUDFLARE_RUNTIME_DEFAULTS as $, decodeHostResponse as A, encodeObservePageRequest as B, SubmitSucceeded as C, decodeApprovalDecisionCommand as D, decodeAbortCommand as E, encodeAbortCommand as F, ConversationMaintenanceFailpoint as G, encodeSubmitRequest as H, encodeApprovalDecisionCommand as I, MaintenancePassReport as J, DurableAlarmError as K, encodeAwaitProgressRequest as L, decodeReceipt as M, decodeSubmitRequest as N, decodeAwaitProgressRequest as O, decodeUnknownResolutionCommand as P, CLOUDFLARE_DATABASE_CAP_BYTES as Q, encodeCancelProgressRequest as R, SubmitRequest as S, boundHostDiagnostic as T, encodeUnknownResolutionCommand as U, encodeReceipt as V, ConversationMaintenance as W, safeCauseMessage as X, safeCauseDiagnostic as Y, AdmissionLimitExceeded as Z, ObservePageRequest as _, ScheduleOwnerProtocolError as a, CloudflareBindingError as at, ProgressObserved as b, ApprovalRecorded as c, DurableObjectContext as ct, CloudflareConversationClient as d, CloudflareAdmissionLimitsValue as et, ConversationClientError as f, HostResponse as g, HostProtocolError as h, ScheduleOwnerNamespace as i, DEFAULT_MAX_DATABASE_BYTES as it, decodeObservePageRequest as j, decodeCancelProgressRequest as k, AwaitProgressRequest as l, conversationNamespaceFromEnv as lt, HostFailure as m, ScheduleAlarmProtocolError as n, CloudflareDurableRuntimeConfigValue as nt, makeScheduleOwnerObjectClass as o, ConversationObjectIdentity as ot, HostFailed as p, DurableAlarmService as q, ScheduleOwnerIdentity as r, CloudflarePlatformConfigError as rt, AbortRecorded as s, ConversationObjectNamespace as st, CloudflareSchedulingClient as t, CloudflareDurableRuntimeConfig as tt, CancelProgressRequest as u, conversationNamespaceLayer as ut, ObservedPage as v, UnknownResolutionRecorded as w, SettlementReached as x, ProgressCancelled as y, encodeHostResponse as z };
888
+ export { CloudflarePlatformConfigError as $, decodeUnknownResolutionCommand as A, DurableAlarmError as B, decodeApprovalDecisionCommand as C, decodeObservePageRequest as D, decodeHostResponse as E, encodeHostResponse as F, safeCauseDiagnostic as G, MaintenancePassReport as H, encodeObservePageRequest as I, CLOUDFLARE_DATABASE_CAP_BYTES as J, safeCauseMessage as K, encodeReceipt as L, encodeApprovalDecisionCommand as M, encodeAwaitProgressRequest as N, decodeReceipt as O, encodeCancelProgressRequest as P, CloudflareDurableRuntimeConfigValue as Q, encodeSubmitRequest as R, decodeAbortCommand as S, decodeCancelProgressRequest as T, ThreadMaintenance as U, DurableAlarmService as V, ThreadMaintenanceFailpoint as W, CloudflareAdmissionLimitsValue as X, CLOUDFLARE_RUNTIME_DEFAULTS as Y, CloudflareDurableRuntimeConfig as Z, SubmitRequest as _, AwaitProgressRequest as a, threadNamespaceFromEnv as at, UnknownResolutionRecorded as b, HostFailed as c, HostResponse as d, DEFAULT_MAX_DATABASE_BYTES as et, ObservePageRequest as f, SettlementReached as g, ProgressObserved as h, ApprovalRecorded as i, ThreadObjectNamespace as it, encodeAbortCommand as j, decodeSubmitRequest as k, HostFailure as l, ProgressCancelled as m, cloudflareScheduledInputAdmissionLayer as n, DurableObjectContext as nt, CancelProgressRequest as o, threadNamespaceLayer as ot, ObservedPage as p, AdmissionLimitExceeded as q, AbortRecorded as r, ThreadObjectIdentity as rt, CloudflareThreadClient as s, cloudflarePreparedInputAdmissionLayer as t, CloudflareBindingError as tt, HostProtocolError as u, SubmitSucceeded as v, decodeAwaitProgressRequest as w, boundHostDiagnostic as x, ThreadClientError as y, encodeUnknownResolutionCommand as z };
1188
889
 
1189
- //# sourceMappingURL=scheduling-B-OFqoS9.mjs.map
890
+ //# sourceMappingURL=prepared-admission-BKp_Upw2.mjs.map