@effect-agent/platform-cloudflare 0.0.1-beta.0 → 0.0.1-beta.3
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/LICENSE +21 -0
- package/dist/index.d.mts +129 -133
- package/dist/index.mjs +16 -19
- package/dist/index.mjs.map +1 -1
- package/package.json +12 -17
- package/src/alarm.ts +1 -1
- package/src/bindings.ts +1 -1
- package/src/client.ts +2 -2
- package/src/config.ts +2 -2
- package/src/conversation-object.ts +30 -23
- package/src/layers.ts +14 -42
- package/src/wake-scheduler.ts +1 -1
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effect-agent/platform-cloudflare",
|
|
3
|
-
"version": "0.0.1-beta.
|
|
3
|
+
"version": "0.0.1-beta.3",
|
|
4
4
|
"description": "Class DC layer assembly for Effect Agent: SQLite-backed Conversation Durable Objects with alarm-driven recovery.",
|
|
5
|
-
"license": "
|
|
5
|
+
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "git+https://github.com/danieljvdm/effect-agent.git",
|
|
@@ -28,29 +28,24 @@
|
|
|
28
28
|
"test": "vitest run"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@effect-agent/core": "0.0.1-beta.
|
|
32
|
-
"@effect-agent/session": "0.0.1-beta.
|
|
33
|
-
"@effect-agent/storage-cloudflare": "0.0.1-beta.
|
|
31
|
+
"@effect-agent/core": "0.0.1-beta.3",
|
|
32
|
+
"@effect-agent/session": "0.0.1-beta.3",
|
|
33
|
+
"@effect-agent/storage-cloudflare": "0.0.1-beta.3",
|
|
34
|
+
"@effect/platform-browser": "4.0.0-beta.102",
|
|
35
|
+
"@effect/sql-sqlite-do": "4.0.0-beta.102",
|
|
36
|
+
"effect": "4.0.0-beta.102"
|
|
34
37
|
},
|
|
35
38
|
"devDependencies": {
|
|
36
39
|
"@cloudflare/vitest-pool-workers": "0.21.3",
|
|
37
40
|
"@cloudflare/workers-types": "5.20260813.1",
|
|
38
|
-
"@effect-agent/capabilities": "0.0.1-beta.
|
|
39
|
-
"@effect-agent/engine": "0.0.1-beta.
|
|
40
|
-
"@effect-agent/testing": "0.0.1-beta.
|
|
41
|
-
"@effect/
|
|
42
|
-
"@effect/sql-sqlite-do": "4.0.0-beta.105",
|
|
43
|
-
"@effect/vitest": "4.0.0-beta.105",
|
|
44
|
-
"effect": "4.0.0-beta.105",
|
|
41
|
+
"@effect-agent/capabilities": "0.0.1-beta.3",
|
|
42
|
+
"@effect-agent/engine": "0.0.1-beta.3",
|
|
43
|
+
"@effect-agent/testing": "0.0.1-beta.3",
|
|
44
|
+
"@effect/vitest": "4.0.0-beta.102",
|
|
45
45
|
"esbuild": "0.28.1",
|
|
46
46
|
"miniflare": "4.20260730.0",
|
|
47
47
|
"typescript": "7.0.2",
|
|
48
48
|
"vite-plus": "0.2.6",
|
|
49
49
|
"vitest": "4.1.10"
|
|
50
|
-
},
|
|
51
|
-
"peerDependencies": {
|
|
52
|
-
"@effect/platform-browser": "4.0.0-beta.105",
|
|
53
|
-
"@effect/sql-sqlite-do": "4.0.0-beta.105",
|
|
54
|
-
"effect": "4.0.0-beta.105"
|
|
55
50
|
}
|
|
56
51
|
}
|
package/src/alarm.ts
CHANGED
|
@@ -25,7 +25,7 @@ import { CloudflareDurableRuntimeConfig } from "./config.ts";
|
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
27
|
/** The Durable Object alarm API failed; surfaces on host entry points as a typed refusal. */
|
|
28
|
-
export class DurableAlarmError extends Schema.
|
|
28
|
+
export class DurableAlarmError extends Schema.TaggedErrorClass<DurableAlarmError>()(
|
|
29
29
|
"DurableAlarmError",
|
|
30
30
|
{
|
|
31
31
|
operation: Schema.String,
|
package/src/bindings.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { Context, Effect, Layer, Schema } from "effect";
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
/** A Cloudflare platform binding was missing or carried the wrong shape (DEPLOY-003/010). */
|
|
13
|
-
export class CloudflareBindingError extends Schema.
|
|
13
|
+
export class CloudflareBindingError extends Schema.TaggedErrorClass<CloudflareBindingError>()(
|
|
14
14
|
"CloudflareBindingError",
|
|
15
15
|
{
|
|
16
16
|
binding: Schema.String,
|
package/src/client.ts
CHANGED
|
@@ -59,7 +59,7 @@ export const boundHostDiagnostic = (value: string): string =>
|
|
|
59
59
|
* The envelope itself could not be honored: the Object could not decode the request, or a
|
|
60
60
|
* response could not be encoded/decoded. Never carries operation semantics.
|
|
61
61
|
*/
|
|
62
|
-
export class HostProtocolError extends Schema.
|
|
62
|
+
export class HostProtocolError extends Schema.TaggedErrorClass<HostProtocolError>()(
|
|
63
63
|
"HostProtocolError",
|
|
64
64
|
{
|
|
65
65
|
message: BoundedDiagnostic,
|
|
@@ -67,7 +67,7 @@ export class HostProtocolError extends Schema.TaggedError<HostProtocolError>()(
|
|
|
67
67
|
) {}
|
|
68
68
|
|
|
69
69
|
/** The Worker-side stub call itself failed (RPC rejection, overload, eviction mid-call). */
|
|
70
|
-
export class ConversationClientError extends Schema.
|
|
70
|
+
export class ConversationClientError extends Schema.TaggedErrorClass<ConversationClientError>()(
|
|
71
71
|
"ConversationClientError",
|
|
72
72
|
{
|
|
73
73
|
conversationId: Schema.String,
|
package/src/config.ts
CHANGED
|
@@ -12,7 +12,7 @@ const PositiveMillis = Schema.Int.check(Schema.isGreaterThan(0));
|
|
|
12
12
|
const NonNegativeMillis = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0));
|
|
13
13
|
|
|
14
14
|
/** The supplied Cloudflare durable runtime configuration failed validation (DEPLOY-003). */
|
|
15
|
-
export class CloudflarePlatformConfigError extends Schema.
|
|
15
|
+
export class CloudflarePlatformConfigError extends Schema.TaggedErrorClass<CloudflarePlatformConfigError>()(
|
|
16
16
|
"CloudflarePlatformConfigError",
|
|
17
17
|
{
|
|
18
18
|
message: Schema.String,
|
|
@@ -28,7 +28,7 @@ export class CloudflarePlatformConfigError extends Schema.TaggedError<Cloudflare
|
|
|
28
28
|
* Conversation Object's submit entry point before `DurableAgentRuntime.submit` runs, and
|
|
29
29
|
* nothing was admitted or written.
|
|
30
30
|
*/
|
|
31
|
-
export class AdmissionLimitExceeded extends Schema.
|
|
31
|
+
export class AdmissionLimitExceeded extends Schema.TaggedErrorClass<AdmissionLimitExceeded>()(
|
|
32
32
|
"AdmissionLimitExceeded",
|
|
33
33
|
{
|
|
34
34
|
limit: Schema.Literals(["queue-depth", "input-bytes", "database-bytes"]),
|
|
@@ -38,7 +38,6 @@ import {
|
|
|
38
38
|
DurableObjectContext,
|
|
39
39
|
conversationNamespaceLayer,
|
|
40
40
|
type CloudflareBindingError,
|
|
41
|
-
type ConversationObjectRpc,
|
|
42
41
|
} from "./bindings.ts";
|
|
43
42
|
import {
|
|
44
43
|
AbortRecorded,
|
|
@@ -96,25 +95,6 @@ export interface ConversationObjectOptions extends CloudflareDurableRuntimeOptio
|
|
|
96
95
|
readonly namespaceBinding: string;
|
|
97
96
|
}
|
|
98
97
|
|
|
99
|
-
/**
|
|
100
|
-
* Public instance surface of the class returned by `makeConversationObjectClass`. It includes
|
|
101
|
-
* the Worker/sibling RPC contract, the administrative RPC entry points, the platform alarm
|
|
102
|
-
* handler, and the inherited Object context used by application subclasses.
|
|
103
|
-
*/
|
|
104
|
-
export interface ConversationObjectInstance
|
|
105
|
-
extends DurableObject<Cloudflare.Env>, ConversationObjectRpc {
|
|
106
|
-
explainEncoded(encoded: unknown): Promise<unknown>;
|
|
107
|
-
verifyEncoded(encoded: unknown): Promise<unknown>;
|
|
108
|
-
retryEncoded(encoded: unknown): Promise<unknown>;
|
|
109
|
-
obligationsEncoded(encoded: unknown): Promise<unknown>;
|
|
110
|
-
alarm(): Promise<void>;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/** Public constructor returned by `makeConversationObjectClass`. */
|
|
114
|
-
export interface ConversationObjectConstructor {
|
|
115
|
-
new (ctx: DurableObjectState, env: Cloudflare.Env): ConversationObjectInstance;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
98
|
type ConversationObjectError = CloudflareDurableRuntimeInitializationError | CloudflareBindingError;
|
|
119
99
|
|
|
120
100
|
type EndpointServices = CloudflareDurableRuntimeServices | DurableObjectContext;
|
|
@@ -628,10 +608,37 @@ const gateEndpoint: Effect.Effect<void, unknown, EndpointServices> = Effect.gen(
|
|
|
628
608
|
yield* maintenance.ensureAlarm;
|
|
629
609
|
});
|
|
630
610
|
|
|
631
|
-
/**
|
|
611
|
+
/** The public endpoint surface of one Conversation Object instance. */
|
|
612
|
+
export interface ConversationObjectInstance extends DurableObject {
|
|
613
|
+
submitEncoded(encoded: unknown): Promise<unknown>;
|
|
614
|
+
awaitSettlementEncoded(encoded: unknown): Promise<unknown>;
|
|
615
|
+
observePage(encoded: unknown): Promise<unknown>;
|
|
616
|
+
abortEncoded(encoded: unknown): Promise<unknown>;
|
|
617
|
+
resolveApprovalEncoded(encoded: unknown): Promise<unknown>;
|
|
618
|
+
resolveUnknownEncoded(encoded: unknown): Promise<unknown>;
|
|
619
|
+
explainEncoded(encoded: unknown): Promise<unknown>;
|
|
620
|
+
verifyEncoded(encoded: unknown): Promise<unknown>;
|
|
621
|
+
retryEncoded(encoded: unknown): Promise<unknown>;
|
|
622
|
+
obligationsEncoded(encoded: unknown): Promise<unknown>;
|
|
623
|
+
portCall(encoded: unknown): Promise<unknown>;
|
|
624
|
+
wake(): Promise<void>;
|
|
625
|
+
alarm(): Promise<void>;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/** The constructor shape workerd instantiates for each Conversation Object. */
|
|
629
|
+
export interface ConversationObjectClass {
|
|
630
|
+
new (ctx: DurableObjectState, env: Cloudflare.Env): ConversationObjectInstance;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/**
|
|
634
|
+
* Build the application's Conversation Object class (export it from the
|
|
635
|
+
* Worker entry). The explicit return type is what makes declaration emit
|
|
636
|
+
* possible: the class body carries a private runtime field, and TS4094
|
|
637
|
+
* rejects inferring an exported anonymous class type around it.
|
|
638
|
+
*/
|
|
632
639
|
export const makeConversationObjectClass = (
|
|
633
640
|
options: ConversationObjectOptions,
|
|
634
|
-
):
|
|
641
|
+
): ConversationObjectClass => {
|
|
635
642
|
class ConversationObject extends DurableObject {
|
|
636
643
|
readonly #runtime: ManagedRuntime.ManagedRuntime<EndpointServices, ConversationObjectError>;
|
|
637
644
|
|
|
@@ -649,7 +656,7 @@ export const makeConversationObjectClass = (
|
|
|
649
656
|
);
|
|
650
657
|
// The constructor gate: local-only checks; never the recovery pass (deadlock argument,
|
|
651
658
|
// plan §1.4). A failure here fails every delivery with the typed construction error.
|
|
652
|
-
|
|
659
|
+
ctx.blockConcurrencyWhile(() => this.#runtime.runPromise(gateEndpoint));
|
|
653
660
|
}
|
|
654
661
|
|
|
655
662
|
async submitEncoded(encoded: unknown): Promise<unknown> {
|
package/src/layers.ts
CHANGED
|
@@ -97,35 +97,16 @@ export interface CloudflareDurableRuntimeOptions {
|
|
|
97
97
|
readonly toolReconciler?: Layer.Layer<ToolReconciler> | undefined;
|
|
98
98
|
/**
|
|
99
99
|
* Registered worker Bindings resolved at durable claim time (S2, spec/subagents.md §11):
|
|
100
|
-
* build each with `DurableWorkerBinding.make(binding, digests)`. An Effect
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
* to the empty registration (every resolved claim fails closed).
|
|
100
|
+
* build each with `DurableWorkerBinding.make(binding, digests)`. An Effect form is accepted
|
|
101
|
+
* because the capture is effectful; it runs once per incarnation during Layer construction.
|
|
102
|
+
* Defaults to the empty registration (every resolved claim fails closed).
|
|
104
103
|
*/
|
|
105
|
-
readonly bindings?:
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
export interface CloudflareBindingSourceContext {
|
|
110
|
-
readonly ctx: DurableObjectState;
|
|
111
|
-
readonly env: unknown;
|
|
112
|
-
readonly conversationId: ConversationId;
|
|
113
|
-
readonly producerId: ProducerId;
|
|
104
|
+
readonly bindings?:
|
|
105
|
+
| ReadonlyArray<ResolvedBinding>
|
|
106
|
+
| Effect.Effect<ReadonlyArray<ResolvedBinding>>
|
|
107
|
+
| undefined;
|
|
114
108
|
}
|
|
115
109
|
|
|
116
|
-
/**
|
|
117
|
-
* Registered worker Bindings, or a closed Effect/callback that captures them once for each
|
|
118
|
-
* Durable Object incarnation. Callback Effects cannot require services or fail typed.
|
|
119
|
-
*/
|
|
120
|
-
export type CloudflareBindingSource =
|
|
121
|
-
| ReadonlyArray<ResolvedBinding>
|
|
122
|
-
| Effect.Effect<ReadonlyArray<ResolvedBinding>, never, never>
|
|
123
|
-
| ((
|
|
124
|
-
context: CloudflareBindingSourceContext,
|
|
125
|
-
) =>
|
|
126
|
-
| ReadonlyArray<ResolvedBinding>
|
|
127
|
-
| Effect.Effect<ReadonlyArray<ResolvedBinding>, never, never>);
|
|
128
|
-
|
|
129
110
|
/** Every construction failure of the assembled Cloudflare durable runtime stack. */
|
|
130
111
|
export type CloudflareDurableRuntimeInitializationError =
|
|
131
112
|
| CloudflarePlatformConfigError
|
|
@@ -227,19 +208,13 @@ const conversationIdFromState = (
|
|
|
227
208
|
);
|
|
228
209
|
|
|
229
210
|
const resolveBindings = (
|
|
230
|
-
|
|
231
|
-
context: CloudflareBindingSourceContext,
|
|
211
|
+
bindings: CloudflareDurableRuntimeOptions["bindings"],
|
|
232
212
|
): Effect.Effect<ReadonlyArray<ResolvedBinding>> =>
|
|
233
|
-
|
|
213
|
+
bindings === undefined
|
|
234
214
|
? Effect.succeed([])
|
|
235
|
-
: Effect.isEffect(
|
|
236
|
-
?
|
|
237
|
-
:
|
|
238
|
-
? Effect.suspend(() => {
|
|
239
|
-
const bindings = source(context);
|
|
240
|
-
return Effect.isEffect(bindings) ? bindings : Effect.succeed(bindings);
|
|
241
|
-
})
|
|
242
|
-
: Effect.succeed(source);
|
|
215
|
+
: Effect.isEffect(bindings)
|
|
216
|
+
? bindings
|
|
217
|
+
: Effect.succeed(bindings);
|
|
243
218
|
|
|
244
219
|
/**
|
|
245
220
|
* The DC Layer assembly (deployment §12: a Layer-assembly library, not an app entrypoint;
|
|
@@ -268,7 +243,7 @@ export class CloudflareDurableRuntime {
|
|
|
268
243
|
> {
|
|
269
244
|
return Layer.unwrap(
|
|
270
245
|
Effect.gen(function* () {
|
|
271
|
-
const { ctx
|
|
246
|
+
const { ctx } = yield* DurableObjectContext;
|
|
272
247
|
const config = yield* configFromOptions(options);
|
|
273
248
|
const conversationId = yield* conversationIdFromState(ctx);
|
|
274
249
|
const producerId = yield* decodeProducerId(
|
|
@@ -342,10 +317,7 @@ export class CloudflareDurableRuntime {
|
|
|
342
317
|
: Layer.succeed(DurableRuntimeFailpoint)({ hit: options.runtimeFailpoint(ctx) });
|
|
343
318
|
const reconcilerLayer = options.toolReconciler ?? ToolReconciler.uncertain;
|
|
344
319
|
const bindingResolverLayer = Layer.effect(AgentBindingResolver)(
|
|
345
|
-
Effect.map(
|
|
346
|
-
resolveBindings(options.bindings, { ctx, env, conversationId, producerId }),
|
|
347
|
-
(bindings) => AgentBindingResolver.fromBindings(bindings),
|
|
348
|
-
),
|
|
320
|
+
Effect.map(resolveBindings(options.bindings), AgentBindingResolver.fromBindings),
|
|
349
321
|
);
|
|
350
322
|
|
|
351
323
|
const base = Layer.mergeAll(
|
package/src/wake-scheduler.ts
CHANGED
|
@@ -14,7 +14,7 @@ import { ConversationObjectIdentity, ConversationObjectNamespace } from "./bindi
|
|
|
14
14
|
const WAKE_BUFFER_CAPACITY = 1_024;
|
|
15
15
|
|
|
16
16
|
/** A remote wake stub call failed; always swallowed and logged (hints are droppable). */
|
|
17
|
-
class RemoteWakeDropped extends Schema.
|
|
17
|
+
class RemoteWakeDropped extends Schema.TaggedErrorClass<RemoteWakeDropped>()("RemoteWakeDropped", {
|
|
18
18
|
conversationId: Schema.String,
|
|
19
19
|
message: Schema.String,
|
|
20
20
|
cause: Schema.optionalKey(Schema.Defect()),
|