@yolk-sdk/vercel-workflows 0.1.0-canary.38 → 0.1.0-canary.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.
package/README.md CHANGED
@@ -71,23 +71,30 @@ Host apps keep concrete Workflow directives local and pass them into the package
71
71
 
72
72
  ```ts
73
73
  import { createHook } from 'workflow'
74
+ import { Effect } from 'effect'
74
75
  import { runVercelAgentWorkflow } from '@yolk-sdk/vercel-workflows'
75
76
 
77
+ const workflowStep = <A>(body: () => Promise<A>) =>
78
+ Effect.tryPromise({ try: body, catch: error => error })
79
+
76
80
  export async function runAgentWorkflow(input: { request: unknown; context: unknown }) {
77
81
  'use workflow'
78
82
 
79
- return await runVercelAgentWorkflow({
80
- input,
81
- runModelStep,
82
- runToolBatchStep,
83
- closeStream,
84
- writeError,
85
- awaitInput: async awaitingInput => {
86
- using hook = createHook<unknown>({ token: awaitingInput.hookToken })
87
-
88
- return await hook
89
- }
90
- })
83
+ return await Effect.runPromise(
84
+ runVercelAgentWorkflow({
85
+ input,
86
+ runModelStep: input => workflowStep(() => runModelStep(input)),
87
+ runToolBatchStep: input => workflowStep(() => runToolBatchStep(input)),
88
+ closeStream: workflowStep(closeStream),
89
+ writeError: error => workflowStep(() => writeError(error)),
90
+ awaitInput: awaitingInput =>
91
+ workflowStep(async () => {
92
+ using hook = createHook<unknown>({ token: awaitingInput.hookToken })
93
+
94
+ return await hook
95
+ })
96
+ })
97
+ )
91
98
  }
92
99
  ```
93
100
 
@@ -122,10 +129,10 @@ Use `writeDurableAgentEvent` to assign deterministic ids and write NDJSON:
122
129
 
123
130
  ```ts
124
131
  const state = makeDurableAgentEventSequencerState(eventSequence)
125
- const sequenced = await writeDurableAgentEvent({
132
+ const sequenced = yield* writeDurableAgentEvent({
126
133
  writer,
127
134
  event,
128
- streamId: 'workflow',
135
+ streamId: `workflow:${runId}`,
129
136
  turn,
130
137
  state
131
138
  })
@@ -133,9 +140,12 @@ const sequenced = await writeDurableAgentEvent({
133
140
  eventSequence = sequenced.nextEventSequence
134
141
  ```
135
142
 
136
- The id format is `${streamId}:${turn}:${eventSequence}`. Keep `eventSequence` in Workflow state.
137
- Resume route reads should use `startIndex` when available. Host apps still own active-run locking,
138
- stale-run guards, and cancellation behavior.
143
+ The id format is `${streamId}:${turn}:${eventSequence}`. Scope `streamId` to one logical durable
144
+ run (for example `workflow:${runId}`), not just one route or feature. Replay-safe clients de-dupe by
145
+ `eventId`; reusing a stream id across independent runs can make a follow-up run's live deltas look
146
+ like old replayed events. Keep `eventSequence` in Workflow state and reset it when starting a fresh
147
+ logical stream. Resume route reads should use `startIndex` when available. Host apps still own
148
+ active-run locking, stale-run guards, and cancellation behavior.
139
149
 
140
150
  ## Terminal barriers
141
151
 
@@ -154,13 +164,13 @@ Use `commitThenWriteTerminalEvent` when a step must commit host state before wri
154
164
  event:
155
165
 
156
166
  ```ts
157
- const result = await commitThenWriteTerminalEvent({
167
+ const result = yield* commitThenWriteTerminalEvent({
158
168
  terminal,
159
- commit: () => persistState(),
169
+ commit: persistState,
160
170
  write: event => writeDurableAgentEvent({ writer, event, streamId, turn, state }),
161
171
  writeCommitError: error =>
162
172
  writeDurableAgentEvent({ writer, event: commitErrorEvent(error), streamId, turn, state }),
163
- close: () => writer.close()
173
+ close: Effect.tryPromise({ try: () => writer.close(), catch: error => error })
164
174
  })
165
175
  ```
166
176
 
@@ -175,7 +185,8 @@ failures are returned separately and do not turn a successful durable commit int
175
185
  - Preserve tool result order and never advance the next model step with dangling host tool calls.
176
186
  - Decide cancellation/resume/conflict UX.
177
187
  - Own hook tokens and response validation for HITL resume.
178
- - Emit replay-safe event ids for durable streams and de-dupe by `eventId` client-side.
188
+ - Emit replay-safe event ids for durable streams; scope stream ids per independent run and de-dupe
189
+ by `eventId` client-side.
179
190
  - Write durable terminal events only after host persistence has settled.
180
191
  - Test directive behavior with `@workflow/vitest` when changing package-owned Workflow files.
181
192
 
package/dist/effect.d.mts CHANGED
@@ -25,7 +25,7 @@ type VercelWorkflowsSdkRun<TResult> = {
25
25
  type VercelWorkflowsSdkClient = {
26
26
  readonly start: <TArgs extends unknown[], TResult>(workflow: VercelWorkflowFunction<TArgs, TResult>, args: TArgs) => Promise<VercelWorkflowsSdkRun<TResult>>;
27
27
  readonly getRun: <TResult>(runId: string) => VercelWorkflowsSdkRun<TResult>;
28
- readonly resumeHook: (token: string, payload: unknown) => Promise<unknown>;
28
+ readonly resumeHook: (token: string, payload: unknown) => Promise<void>;
29
29
  };
30
30
  type VercelWorkflowRun<TResult> = {
31
31
  readonly runId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"effect.d.mts","names":[],"sources":["../src/effect.ts"],"mappings":";;;;KAUY,wBAAA;AAAA,cAQK,yBAAA;;;cAEJ,oBAAA,SAA6B,yBAAA;EAAA,SAC/B,SAAA,EAAW,wBAAA;EAAA,SACX,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,KAGC,sBAAA,yCACP,IAAA,EAAM,KAAA,KACN,OAAA,CAAQ,OAAA;AAAA,KAED,6BAAA,GAAgC,6BAA6B;AAAA,KAC7D,4BAAA,UAAsC,sBAAsB,CAAC,KAAA;AAAA,KAC7D,uBAAA,GAA0B,WAAW;AAAA,KAErC,qBAAA;EAAA,SACD,KAAA;EAAA,SACA,WAAA,UACP,OAAA,GAAU,6BAAA,KACP,4BAAA,CAA6B,KAAA;EAAA,SACzB,MAAA,QAAc,OAAA;EAAA,SACd,MAAA,EAAQ,OAAA,CAAQ,uBAAA;EAAA,SAChB,WAAA,EAAa,OAAA,CAAQ,OAAA;AAAA;AAAA,KAGpB,wBAAA;EAAA,SACD,KAAA,qCACP,QAAA,EAAU,sBAAA,CAAuB,KAAA,EAAO,OAAA,GACxC,IAAA,EAAM,KAAA,KACH,OAAA,CAAQ,qBAAA,CAAsB,OAAA;EAAA,SAC1B,MAAA,YAAkB,KAAA,aAAkB,qBAAA,CAAsB,OAAA;EAAA,SAC1D,UAAA,GAAa,KAAA,UAAe,OAAA,cAAqB,OAAA;AAAA;AAAA,KAGhD,iBAAA;EAAA,SACD,KAAA;EAAA,SACA,WAAA,UACP,OAAA,GAAU,6BAAA,KACP,MAAA,CAAO,MAAA,CAAO,4BAAA,CAA6B,KAAA,GAAQ,oBAAA;EAAA,SAC/C,MAAA,EAAQ,MAAA,CAAO,MAAA,OAAa,oBAAA;EAAA,SAC5B,MAAA,EAAQ,MAAA,CAAO,MAAA,CAAO,uBAAA,EAAyB,oBAAA;EAAA,SAC/C,WAAA,EAAa,MAAA,CAAO,MAAA,CAAO,OAAA,EAAS,oBAAA;AAAA;AAAA,KAGnC,qBAAA;EAAA,SACD,KAAA,qCACP,QAAA,EAAU,sBAAA,CAAuB,KAAA,EAAO,OAAA,GACxC,IAAA,EAAM,KAAA,KACH,MAAA,CAAO,MAAA,CAAO,iBAAA,CAAkB,OAAA,GAAU,oBAAA;EAAA,SACtC,MAAA,YACP,KAAA,aACG,MAAA,CAAO,MAAA,CAAO,iBAAA,CAAkB,OAAA,GAAU,oBAAA;EAAA,SACtC,WAAA,UACP,KAAA,UACA,OAAA,GAAU,6BAAA,KACP,MAAA,CAAO,MAAA,CAAO,4BAAA,CAA6B,KAAA,GAAQ,oBAAA;EAAA,SAC/C,SAAA,GAAY,KAAA,aAAkB,MAAA,CAAO,MAAA,SAAe,oBAAA;EAAA,SACpD,UAAA,GACP,KAAA,UACA,OAAA,cACG,MAAA,CAAO,MAAA,OAAa,oBAAA;EAAA,SAChB,MAAA,GAAS,KAAA,aAAkB,MAAA,CAAO,MAAA,OAAa,oBAAA;AAAA;AAAA,cACzD,uBAAA;cAEY,kBAAA,SAA2B,uBAGY;AAAA,cAAG,oBAAA;;;cA2D1C,eAAA,SAAwB,oBAAA;EAAA,OAwE5B,KAAA,EAAK,KAAA,CAAA,KAAA,CAAA,eAAA;EAAA,OACL,YAAA,EAAY,KAAA,CAAA,KAAA,CAAA,eAAA,SAAA,kBAAA;AAAA"}
1
+ {"version":3,"file":"effect.d.mts","names":[],"sources":["../src/effect.ts"],"mappings":";;;;KAUY,wBAAA;AAAA,cAQK,yBAAA;;;cAEJ,oBAAA,SAA6B,yBAAA;EAAA,SAC/B,SAAA,EAAW,wBAAA;EAAA,SACX,OAAA;EAAA,SACA,KAAA;AAAA;AAAA,KAGC,sBAAA,yCACP,IAAA,EAAM,KAAA,KACN,OAAA,CAAQ,OAAA;AAAA,KAED,6BAAA,GAAgC,6BAA6B;AAAA,KAC7D,4BAAA,UAAsC,sBAAsB,CAAC,KAAA;AAAA,KAC7D,uBAAA,GAA0B,WAAW;AAAA,KAErC,qBAAA;EAAA,SACD,KAAA;EAAA,SACA,WAAA,UACP,OAAA,GAAU,6BAAA,KACP,4BAAA,CAA6B,KAAA;EAAA,SACzB,MAAA,QAAc,OAAA;EAAA,SACd,MAAA,EAAQ,OAAA,CAAQ,uBAAA;EAAA,SAChB,WAAA,EAAa,OAAA,CAAQ,OAAA;AAAA;AAAA,KAGpB,wBAAA;EAAA,SACD,KAAA,qCACP,QAAA,EAAU,sBAAA,CAAuB,KAAA,EAAO,OAAA,GACxC,IAAA,EAAM,KAAA,KACH,OAAA,CAAQ,qBAAA,CAAsB,OAAA;EAAA,SAC1B,MAAA,YAAkB,KAAA,aAAkB,qBAAA,CAAsB,OAAA;EAAA,SAC1D,UAAA,GAAa,KAAA,UAAe,OAAA,cAAqB,OAAA;AAAA;AAAA,KAGhD,iBAAA;EAAA,SACD,KAAA;EAAA,SACA,WAAA,UACP,OAAA,GAAU,6BAAA,KACP,MAAA,CAAO,MAAA,CAAO,4BAAA,CAA6B,KAAA,GAAQ,oBAAA;EAAA,SAC/C,MAAA,EAAQ,MAAA,CAAO,MAAA,OAAa,oBAAA;EAAA,SAC5B,MAAA,EAAQ,MAAA,CAAO,MAAA,CAAO,uBAAA,EAAyB,oBAAA;EAAA,SAC/C,WAAA,EAAa,MAAA,CAAO,MAAA,CAAO,OAAA,EAAS,oBAAA;AAAA;AAAA,KAGnC,qBAAA;EAAA,SACD,KAAA,qCACP,QAAA,EAAU,sBAAA,CAAuB,KAAA,EAAO,OAAA,GACxC,IAAA,EAAM,KAAA,KACH,MAAA,CAAO,MAAA,CAAO,iBAAA,CAAkB,OAAA,GAAU,oBAAA;EAAA,SACtC,MAAA,YACP,KAAA,aACG,MAAA,CAAO,MAAA,CAAO,iBAAA,CAAkB,OAAA,GAAU,oBAAA;EAAA,SACtC,WAAA,UACP,KAAA,UACA,OAAA,GAAU,6BAAA,KACP,MAAA,CAAO,MAAA,CAAO,4BAAA,CAA6B,KAAA,GAAQ,oBAAA;EAAA,SAC/C,SAAA,GAAY,KAAA,aAAkB,MAAA,CAAO,MAAA,SAAe,oBAAA;EAAA,SACpD,UAAA,GACP,KAAA,UACA,OAAA,cACG,MAAA,CAAO,MAAA,OAAa,oBAAA;EAAA,SAChB,MAAA,GAAS,KAAA,aAAkB,MAAA,CAAO,MAAA,OAAa,oBAAA;AAAA;AAAA,cACzD,uBAAA;cAEY,kBAAA,SAA2B,uBAGY;AAAA,cAAG,oBAAA;;;cAiE1C,eAAA,SAAwB,oBAAA;EAAA,OA2E5B,KAAA,EAAK,KAAA,CAAA,KAAA,CAAA,eAAA;EAAA,OACL,YAAA,EAAY,KAAA,CAAA,KAAA,CAAA,eAAA,SAAA,kBAAA;AAAA"}
package/dist/effect.mjs CHANGED
@@ -9,51 +9,43 @@ const workflowsError = (operation, cause) => new VercelWorkflowsError({
9
9
  cause
10
10
  });
11
11
  const spanAttributes = (runId) => ({ "workflow.run.id": runId });
12
+ const trySdkPromise = (body) => Effect.tryPromise({
13
+ try: body,
14
+ catch: (error) => error
15
+ });
16
+ const mapSdkError = (operation) => (effect) => effect.pipe(Effect.mapError((cause) => workflowsError(operation, cause)));
12
17
  const makeWorkflowRun = (run) => ({
13
18
  runId: run.runId,
14
19
  getReadable: (options) => Effect.try({
15
20
  try: () => run.getReadable(options),
16
21
  catch: (cause) => workflowsError("getReadable", cause)
17
22
  }).pipe(Effect.withSpan("VercelWorkflows.run.getReadable", { attributes: spanAttributes(run.runId) })),
18
- cancel: Effect.tryPromise({
19
- try: () => run.cancel(),
20
- catch: (cause) => workflowsError("cancel", cause)
21
- }).pipe(Effect.withSpan("VercelWorkflows.run.cancel", { attributes: spanAttributes(run.runId) })),
22
- status: Effect.tryPromise({
23
- try: () => run.status,
24
- catch: (cause) => workflowsError("status", cause)
25
- }).pipe(Effect.withSpan("VercelWorkflows.run.status", { attributes: spanAttributes(run.runId) })),
26
- returnValue: Effect.tryPromise({
27
- try: () => run.returnValue,
28
- catch: (cause) => workflowsError("returnValue", cause)
29
- }).pipe(Effect.withSpan("VercelWorkflows.run.returnValue", { attributes: spanAttributes(run.runId) }))
23
+ cancel: trySdkPromise(() => run.cancel()).pipe(mapSdkError("cancel"), Effect.withSpan("VercelWorkflows.run.cancel", { attributes: spanAttributes(run.runId) })),
24
+ status: trySdkPromise(() => run.status).pipe(mapSdkError("status"), Effect.withSpan("VercelWorkflows.run.status", { attributes: spanAttributes(run.runId) })),
25
+ returnValue: trySdkPromise(() => run.returnValue).pipe(mapSdkError("returnValue"), Effect.withSpan("VercelWorkflows.run.returnValue", { attributes: spanAttributes(run.runId) }))
30
26
  });
31
27
  const VercelWorkflowsSdkLive = Layer.succeed(VercelWorkflowsSdk, {
32
28
  start: (workflow, args) => start(workflow, args),
33
29
  getRun: (runId) => getRun(runId),
34
- resumeHook: (token, payload) => resumeHook(token, payload)
30
+ resumeHook: async (token, payload) => {
31
+ await resumeHook(token, payload);
32
+ }
35
33
  });
36
34
  var VercelWorkflows = class extends Context.Service()("@yolk-sdk/vercel-workflows/VercelWorkflows", { make: Effect.gen(function* () {
37
35
  const sdk = yield* VercelWorkflowsSdk;
38
36
  const getRun = (runId) => Effect.try({
39
- try: () => makeWorkflowRun(sdk.getRun(runId)),
40
- catch: (cause) => workflowsError("getRun", cause)
41
- }).pipe(Effect.withSpan("VercelWorkflows.getRun", { attributes: spanAttributes(runId) }));
37
+ try: () => sdk.getRun(runId),
38
+ catch: (error) => error
39
+ }).pipe(mapSdkError("getRun"), Effect.map(makeWorkflowRun), Effect.withSpan("VercelWorkflows.getRun", { attributes: spanAttributes(runId) }));
42
40
  return {
43
- start: (workflow, args) => Effect.tryPromise({
44
- try: () => sdk.start(workflow, args),
45
- catch: (cause) => workflowsError("start", cause)
46
- }).pipe(Effect.map(makeWorkflowRun), Effect.withSpan("VercelWorkflows.start")),
41
+ start: (workflow, args) => trySdkPromise(() => sdk.start(workflow, args)).pipe(mapSdkError("start"), Effect.map(makeWorkflowRun), Effect.withSpan("VercelWorkflows.start")),
47
42
  getRun,
48
43
  getReadable: (runId, options) => getRun(runId).pipe(Effect.flatMap((run) => run.getReadable(options)), Effect.withSpan("VercelWorkflows.getReadable", { attributes: spanAttributes(runId) })),
49
44
  tailIndex: (runId) => getRun(runId).pipe(Effect.flatMap((run) => run.getReadable({ startIndex: -1 })), Effect.flatMap((readable) => Effect.tryPromise({
50
45
  try: () => readable.getTailIndex(),
51
46
  catch: (cause) => workflowsError("tailIndex", cause)
52
47
  })), Effect.withSpan("VercelWorkflows.tailIndex", { attributes: spanAttributes(runId) })),
53
- resumeHook: (token, payload) => Effect.tryPromise({
54
- try: () => sdk.resumeHook(token, payload).then(() => void 0),
55
- catch: (cause) => workflowsError("resumeHook", cause)
56
- }).pipe(Effect.withSpan("VercelWorkflows.resumeHook")),
48
+ resumeHook: (token, payload) => trySdkPromise(() => sdk.resumeHook(token, payload)).pipe(mapSdkError("resumeHook"), Effect.withSpan("VercelWorkflows.resumeHook")),
57
49
  cancel: (runId) => getRun(runId).pipe(Effect.flatMap((run) => run.cancel), Effect.withSpan("VercelWorkflows.cancel", { attributes: spanAttributes(runId) }))
58
50
  };
59
51
  }) }) {
@@ -1 +1 @@
1
- {"version":3,"file":"effect.mjs","names":["workflowStart","workflowGetRun","workflowResumeHook"],"sources":["../src/effect.ts"],"sourcesContent":["import { Context, Data, Effect, Layer } from 'effect'\nimport {\n getRun as workflowGetRun,\n resumeHook as workflowResumeHook,\n start as workflowStart,\n type WorkflowReadableStream,\n type WorkflowReadableStreamOptions,\n type WorkflowRun\n} from 'workflow/api'\n\nexport type VercelWorkflowsOperation =\n | 'start'\n | 'getRun'\n | 'getReadable'\n | 'tailIndex'\n | 'resumeHook'\n | 'cancel'\n | 'status'\n | 'returnValue'\n\nexport class VercelWorkflowsError extends Data.TaggedError('VercelWorkflowsError')<{\n readonly operation: VercelWorkflowsOperation\n readonly message: string\n readonly cause: unknown\n}> {}\n\nexport type VercelWorkflowFunction<TArgs extends unknown[], TResult> = (\n ...args: TArgs\n) => Promise<TResult>\n\nexport type VercelWorkflowReadableOptions = WorkflowReadableStreamOptions\nexport type VercelWorkflowReadableStream<Chunk> = WorkflowReadableStream<Chunk>\nexport type VercelWorkflowRunStatus = WorkflowRun['status']\n\nexport type VercelWorkflowsSdkRun<TResult> = {\n readonly runId: string\n readonly getReadable: <Chunk>(\n options?: VercelWorkflowReadableOptions\n ) => VercelWorkflowReadableStream<Chunk>\n readonly cancel: () => Promise<void>\n readonly status: Promise<VercelWorkflowRunStatus>\n readonly returnValue: Promise<TResult>\n}\n\nexport type VercelWorkflowsSdkClient = {\n readonly start: <TArgs extends unknown[], TResult>(\n workflow: VercelWorkflowFunction<TArgs, TResult>,\n args: TArgs\n ) => Promise<VercelWorkflowsSdkRun<TResult>>\n readonly getRun: <TResult>(runId: string) => VercelWorkflowsSdkRun<TResult>\n readonly resumeHook: (token: string, payload: unknown) => Promise<unknown>\n}\n\nexport type VercelWorkflowRun<TResult> = {\n readonly runId: string\n readonly getReadable: <Chunk>(\n options?: VercelWorkflowReadableOptions\n ) => Effect.Effect<VercelWorkflowReadableStream<Chunk>, VercelWorkflowsError>\n readonly cancel: Effect.Effect<void, VercelWorkflowsError>\n readonly status: Effect.Effect<VercelWorkflowRunStatus, VercelWorkflowsError>\n readonly returnValue: Effect.Effect<TResult, VercelWorkflowsError>\n}\n\nexport type VercelWorkflowsClient = {\n readonly start: <TArgs extends unknown[], TResult>(\n workflow: VercelWorkflowFunction<TArgs, TResult>,\n args: TArgs\n ) => Effect.Effect<VercelWorkflowRun<TResult>, VercelWorkflowsError>\n readonly getRun: <TResult>(\n runId: string\n ) => Effect.Effect<VercelWorkflowRun<TResult>, VercelWorkflowsError>\n readonly getReadable: <Chunk>(\n runId: string,\n options?: VercelWorkflowReadableOptions\n ) => Effect.Effect<VercelWorkflowReadableStream<Chunk>, VercelWorkflowsError>\n readonly tailIndex: (runId: string) => Effect.Effect<number, VercelWorkflowsError>\n readonly resumeHook: (\n token: string,\n payload: unknown\n ) => Effect.Effect<void, VercelWorkflowsError>\n readonly cancel: (runId: string) => Effect.Effect<void, VercelWorkflowsError>\n}\n\nexport class VercelWorkflowsSdk extends Context.Service<\n VercelWorkflowsSdk,\n VercelWorkflowsSdkClient\n>()('@yolk-sdk/vercel-workflows/VercelWorkflowsSdk') {}\n\nconst workflowsError = (operation: VercelWorkflowsOperation, cause: unknown) =>\n new VercelWorkflowsError({\n operation,\n message: `Vercel Workflow ${operation} failed`,\n cause\n })\n\nconst spanAttributes = (runId: string) => ({ 'workflow.run.id': runId })\n\nconst makeWorkflowRun = <TResult>(\n run: VercelWorkflowsSdkRun<TResult>\n): VercelWorkflowRun<TResult> => ({\n runId: run.runId,\n getReadable: <Chunk>(options?: VercelWorkflowReadableOptions) =>\n Effect.try({\n try: () => run.getReadable<Chunk>(options),\n catch: cause => workflowsError('getReadable', cause)\n }).pipe(\n Effect.withSpan('VercelWorkflows.run.getReadable', {\n attributes: spanAttributes(run.runId)\n })\n ),\n cancel: Effect.tryPromise({\n try: () => run.cancel(),\n catch: cause => workflowsError('cancel', cause)\n }).pipe(\n Effect.withSpan('VercelWorkflows.run.cancel', {\n attributes: spanAttributes(run.runId)\n })\n ),\n status: Effect.tryPromise({\n try: () => run.status,\n catch: cause => workflowsError('status', cause)\n }).pipe(\n Effect.withSpan('VercelWorkflows.run.status', {\n attributes: spanAttributes(run.runId)\n })\n ),\n returnValue: Effect.tryPromise({\n try: () => run.returnValue,\n catch: cause => workflowsError('returnValue', cause)\n }).pipe(\n Effect.withSpan('VercelWorkflows.run.returnValue', {\n attributes: spanAttributes(run.runId)\n })\n )\n})\n\nconst VercelWorkflowsSdkLive = Layer.succeed(VercelWorkflowsSdk, {\n start: <TArgs extends unknown[], TResult>(\n workflow: VercelWorkflowFunction<TArgs, TResult>,\n args: TArgs\n ) => workflowStart(workflow, args),\n getRun: <TResult>(runId: string) => workflowGetRun<TResult>(runId),\n resumeHook: (token: string, payload: unknown) => workflowResumeHook<unknown>(token, payload)\n})\n\nexport class VercelWorkflows extends Context.Service<VercelWorkflows, VercelWorkflowsClient>()(\n '@yolk-sdk/vercel-workflows/VercelWorkflows',\n {\n make: Effect.gen(function* () {\n const sdk = yield* VercelWorkflowsSdk\n\n const getRun = <TResult>(\n runId: string\n ): Effect.Effect<VercelWorkflowRun<TResult>, VercelWorkflowsError> =>\n Effect.try({\n try: () => makeWorkflowRun(sdk.getRun<TResult>(runId)),\n catch: cause => workflowsError('getRun', cause)\n }).pipe(\n Effect.withSpan('VercelWorkflows.getRun', {\n attributes: spanAttributes(runId)\n })\n )\n\n return {\n start: <TArgs extends unknown[], TResult>(\n workflow: VercelWorkflowFunction<TArgs, TResult>,\n args: TArgs\n ): Effect.Effect<VercelWorkflowRun<TResult>, VercelWorkflowsError> =>\n Effect.tryPromise({\n try: () => sdk.start(workflow, args),\n catch: cause => workflowsError('start', cause)\n }).pipe(Effect.map(makeWorkflowRun), Effect.withSpan('VercelWorkflows.start')),\n\n getRun,\n\n getReadable: <Chunk>(\n runId: string,\n options?: VercelWorkflowReadableOptions\n ): Effect.Effect<VercelWorkflowReadableStream<Chunk>, VercelWorkflowsError> =>\n getRun<unknown>(runId).pipe(\n Effect.flatMap(run => run.getReadable<Chunk>(options)),\n Effect.withSpan('VercelWorkflows.getReadable', {\n attributes: spanAttributes(runId)\n })\n ),\n\n tailIndex: (runId: string): Effect.Effect<number, VercelWorkflowsError> =>\n getRun<unknown>(runId).pipe(\n Effect.flatMap(run => run.getReadable<unknown>({ startIndex: -1 })),\n Effect.flatMap(readable =>\n Effect.tryPromise({\n try: () => readable.getTailIndex(),\n catch: cause => workflowsError('tailIndex', cause)\n })\n ),\n Effect.withSpan('VercelWorkflows.tailIndex', {\n attributes: spanAttributes(runId)\n })\n ),\n\n resumeHook: (token: string, payload: unknown): Effect.Effect<void, VercelWorkflowsError> =>\n Effect.tryPromise({\n try: () => sdk.resumeHook(token, payload).then(() => undefined),\n catch: cause => workflowsError('resumeHook', cause)\n }).pipe(Effect.withSpan('VercelWorkflows.resumeHook')),\n\n cancel: (runId: string): Effect.Effect<void, VercelWorkflowsError> =>\n getRun<unknown>(runId).pipe(\n Effect.flatMap(run => run.cancel),\n Effect.withSpan('VercelWorkflows.cancel', {\n attributes: spanAttributes(runId)\n })\n )\n }\n })\n }\n) {\n static layer = Layer.effect(this, this.make).pipe(Layer.provide(VercelWorkflowsSdkLive))\n static layerFromSdk = Layer.effect(this, this.make)\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"effect.mjs","names":["workflowStart","workflowGetRun","workflowResumeHook"],"sources":["../src/effect.ts"],"sourcesContent":["import { Context, Data, Effect, Layer } from 'effect'\nimport {\n getRun as workflowGetRun,\n resumeHook as workflowResumeHook,\n start as workflowStart,\n type WorkflowReadableStream,\n type WorkflowReadableStreamOptions,\n type WorkflowRun\n} from 'workflow/api'\n\nexport type VercelWorkflowsOperation =\n | 'start'\n | 'getRun'\n | 'getReadable'\n | 'tailIndex'\n | 'resumeHook'\n | 'cancel'\n | 'status'\n | 'returnValue'\n\nexport class VercelWorkflowsError extends Data.TaggedError('VercelWorkflowsError')<{\n readonly operation: VercelWorkflowsOperation\n readonly message: string\n readonly cause: unknown\n}> {}\n\nexport type VercelWorkflowFunction<TArgs extends unknown[], TResult> = (\n ...args: TArgs\n) => Promise<TResult>\n\nexport type VercelWorkflowReadableOptions = WorkflowReadableStreamOptions\nexport type VercelWorkflowReadableStream<Chunk> = WorkflowReadableStream<Chunk>\nexport type VercelWorkflowRunStatus = WorkflowRun['status']\n\nexport type VercelWorkflowsSdkRun<TResult> = {\n readonly runId: string\n readonly getReadable: <Chunk>(\n options?: VercelWorkflowReadableOptions\n ) => VercelWorkflowReadableStream<Chunk>\n readonly cancel: () => Promise<void>\n readonly status: Promise<VercelWorkflowRunStatus>\n readonly returnValue: Promise<TResult>\n}\n\nexport type VercelWorkflowsSdkClient = {\n readonly start: <TArgs extends unknown[], TResult>(\n workflow: VercelWorkflowFunction<TArgs, TResult>,\n args: TArgs\n ) => Promise<VercelWorkflowsSdkRun<TResult>>\n readonly getRun: <TResult>(runId: string) => VercelWorkflowsSdkRun<TResult>\n readonly resumeHook: (token: string, payload: unknown) => Promise<void>\n}\n\nexport type VercelWorkflowRun<TResult> = {\n readonly runId: string\n readonly getReadable: <Chunk>(\n options?: VercelWorkflowReadableOptions\n ) => Effect.Effect<VercelWorkflowReadableStream<Chunk>, VercelWorkflowsError>\n readonly cancel: Effect.Effect<void, VercelWorkflowsError>\n readonly status: Effect.Effect<VercelWorkflowRunStatus, VercelWorkflowsError>\n readonly returnValue: Effect.Effect<TResult, VercelWorkflowsError>\n}\n\nexport type VercelWorkflowsClient = {\n readonly start: <TArgs extends unknown[], TResult>(\n workflow: VercelWorkflowFunction<TArgs, TResult>,\n args: TArgs\n ) => Effect.Effect<VercelWorkflowRun<TResult>, VercelWorkflowsError>\n readonly getRun: <TResult>(\n runId: string\n ) => Effect.Effect<VercelWorkflowRun<TResult>, VercelWorkflowsError>\n readonly getReadable: <Chunk>(\n runId: string,\n options?: VercelWorkflowReadableOptions\n ) => Effect.Effect<VercelWorkflowReadableStream<Chunk>, VercelWorkflowsError>\n readonly tailIndex: (runId: string) => Effect.Effect<number, VercelWorkflowsError>\n readonly resumeHook: (\n token: string,\n payload: unknown\n ) => Effect.Effect<void, VercelWorkflowsError>\n readonly cancel: (runId: string) => Effect.Effect<void, VercelWorkflowsError>\n}\n\nexport class VercelWorkflowsSdk extends Context.Service<\n VercelWorkflowsSdk,\n VercelWorkflowsSdkClient\n>()('@yolk-sdk/vercel-workflows/VercelWorkflowsSdk') {}\n\nconst workflowsError = (operation: VercelWorkflowsOperation, cause: unknown) =>\n new VercelWorkflowsError({\n operation,\n message: `Vercel Workflow ${operation} failed`,\n cause\n })\n\nconst spanAttributes = (runId: string) => ({ 'workflow.run.id': runId })\n\nconst trySdkPromise = <A>(body: () => Promise<A>) =>\n Effect.tryPromise({\n try: body,\n catch: error => error\n })\n\nconst mapSdkError = (operation: VercelWorkflowsOperation) =>\n <A>(effect: Effect.Effect<A, unknown>) =>\n effect.pipe(Effect.mapError(cause => workflowsError(operation, cause)))\n\nconst makeWorkflowRun = <TResult>(\n run: VercelWorkflowsSdkRun<TResult>\n): VercelWorkflowRun<TResult> => ({\n runId: run.runId,\n getReadable: <Chunk>(options?: VercelWorkflowReadableOptions) =>\n Effect.try({\n try: () => run.getReadable<Chunk>(options),\n catch: cause => workflowsError('getReadable', cause)\n }).pipe(\n Effect.withSpan('VercelWorkflows.run.getReadable', {\n attributes: spanAttributes(run.runId)\n })\n ),\n cancel: trySdkPromise(() => run.cancel()).pipe(\n mapSdkError('cancel'),\n Effect.withSpan('VercelWorkflows.run.cancel', {\n attributes: spanAttributes(run.runId)\n })\n ),\n status: trySdkPromise(() => run.status).pipe(\n mapSdkError('status'),\n Effect.withSpan('VercelWorkflows.run.status', {\n attributes: spanAttributes(run.runId)\n })\n ),\n returnValue: trySdkPromise(() => run.returnValue).pipe(\n mapSdkError('returnValue'),\n Effect.withSpan('VercelWorkflows.run.returnValue', {\n attributes: spanAttributes(run.runId)\n })\n )\n})\n\nconst VercelWorkflowsSdkLive = Layer.succeed(VercelWorkflowsSdk, {\n start: <TArgs extends unknown[], TResult>(\n workflow: VercelWorkflowFunction<TArgs, TResult>,\n args: TArgs\n ) => workflowStart(workflow, args),\n getRun: <TResult>(runId: string) => workflowGetRun<TResult>(runId),\n resumeHook: async (token: string, payload: unknown) => {\n await workflowResumeHook<unknown>(token, payload)\n }\n})\n\nexport class VercelWorkflows extends Context.Service<VercelWorkflows, VercelWorkflowsClient>()(\n '@yolk-sdk/vercel-workflows/VercelWorkflows',\n {\n make: Effect.gen(function* () {\n const sdk = yield* VercelWorkflowsSdk\n\n const getRun = <TResult>(\n runId: string\n ): Effect.Effect<VercelWorkflowRun<TResult>, VercelWorkflowsError> =>\n Effect.try({\n try: () => sdk.getRun<TResult>(runId),\n catch: error => error\n }).pipe(\n mapSdkError('getRun'),\n Effect.map(makeWorkflowRun),\n Effect.withSpan('VercelWorkflows.getRun', {\n attributes: spanAttributes(runId)\n })\n )\n\n return {\n start: <TArgs extends unknown[], TResult>(\n workflow: VercelWorkflowFunction<TArgs, TResult>,\n args: TArgs\n ): Effect.Effect<VercelWorkflowRun<TResult>, VercelWorkflowsError> =>\n trySdkPromise(() => sdk.start(workflow, args)).pipe(\n mapSdkError('start'),\n Effect.map(makeWorkflowRun),\n Effect.withSpan('VercelWorkflows.start')\n ),\n\n getRun,\n\n getReadable: <Chunk>(\n runId: string,\n options?: VercelWorkflowReadableOptions\n ): Effect.Effect<VercelWorkflowReadableStream<Chunk>, VercelWorkflowsError> =>\n getRun<unknown>(runId).pipe(\n Effect.flatMap(run => run.getReadable<Chunk>(options)),\n Effect.withSpan('VercelWorkflows.getReadable', {\n attributes: spanAttributes(runId)\n })\n ),\n\n tailIndex: (runId: string): Effect.Effect<number, VercelWorkflowsError> =>\n getRun<unknown>(runId).pipe(\n Effect.flatMap(run => run.getReadable<unknown>({ startIndex: -1 })),\n Effect.flatMap(readable =>\n Effect.tryPromise({\n try: () => readable.getTailIndex(),\n catch: cause => workflowsError('tailIndex', cause)\n })\n ),\n Effect.withSpan('VercelWorkflows.tailIndex', {\n attributes: spanAttributes(runId)\n })\n ),\n\n resumeHook: (token: string, payload: unknown): Effect.Effect<void, VercelWorkflowsError> =>\n trySdkPromise(() => sdk.resumeHook(token, payload)).pipe(\n mapSdkError('resumeHook'),\n Effect.withSpan('VercelWorkflows.resumeHook')\n ),\n\n cancel: (runId: string): Effect.Effect<void, VercelWorkflowsError> =>\n getRun<unknown>(runId).pipe(\n Effect.flatMap(run => run.cancel),\n Effect.withSpan('VercelWorkflows.cancel', {\n attributes: spanAttributes(runId)\n })\n )\n }\n })\n }\n) {\n static layer = Layer.effect(this, this.make).pipe(Layer.provide(VercelWorkflowsSdkLive))\n static layerFromSdk = Layer.effect(this, this.make)\n}\n"],"mappings":"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"}
@@ -1,3 +1,5 @@
1
+ import { Effect } from "effect";
2
+
1
3
  //#region src/workflow-events.d.ts
2
4
  type DurableAgentEventSequencerState = {
3
5
  readonly eventSequence: number;
@@ -13,6 +15,13 @@ type DurableAgentEventIdInput = {
13
15
  };
14
16
  type SequenceDurableAgentEventInput<Event extends object = object> = {
15
17
  readonly state: DurableAgentEventSequencerState;
18
+ /**
19
+ * Stable id namespace for one independent durable stream.
20
+ *
21
+ * Include the workflow/session/run id when multiple logical runs can be
22
+ * projected in the same client. Replay-safe clients de-dupe by `eventId`, so
23
+ * reusing a stream id across runs can drop legitimate follow-up events.
24
+ */
16
25
  readonly streamId: string;
17
26
  readonly turn: number;
18
27
  readonly event: Event;
@@ -33,12 +42,12 @@ type TerminalEventCloseResult = {
33
42
  readonly _tag: 'CloseFailed';
34
43
  readonly error: unknown;
35
44
  };
36
- type CommitThenWriteTerminalEventInput<TerminalEvent extends object, TerminalWriteResult, CommitErrorWriteResult> = {
37
- readonly commit: () => Promise<void>;
45
+ type CommitThenWriteTerminalEventInput<TerminalEvent extends object, TerminalWriteResult, CommitErrorWriteResult, CommitError, TerminalWriteError, CommitErrorWriteError, CloseError> = {
46
+ readonly commit: Effect.Effect<void, CommitError>;
38
47
  readonly terminal: TerminalEvent;
39
- readonly write: (event: TerminalEvent) => Promise<TerminalWriteResult>;
40
- readonly writeCommitError: (error: unknown) => Promise<CommitErrorWriteResult>;
41
- readonly close: () => Promise<void>;
48
+ readonly write: (event: TerminalEvent) => Effect.Effect<TerminalWriteResult, TerminalWriteError>;
49
+ readonly writeCommitError: (error: unknown) => Effect.Effect<CommitErrorWriteResult, CommitErrorWriteError>;
50
+ readonly close: Effect.Effect<void, CloseError>;
42
51
  };
43
52
  type CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult> = {
44
53
  readonly _tag: 'Committed';
@@ -62,8 +71,8 @@ type CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteRes
62
71
  declare const makeDurableAgentEventSequencerState: (eventSequence?: number) => DurableAgentEventSequencerState;
63
72
  declare const durableAgentEventId: (input: DurableAgentEventIdInput) => string;
64
73
  declare const sequenceDurableAgentEvent: <Event extends object>(input: SequenceDurableAgentEventInput<Event>) => SequencedDurableAgentEvent<Event>;
65
- declare const writeDurableAgentEvent: <Event extends object>(input: WriteDurableAgentEventInput<Event>) => Promise<SequencedDurableAgentEvent<Event>>;
66
- declare const commitThenWriteTerminalEvent: <TerminalEvent extends object, TerminalWriteResult, CommitErrorWriteResult>(input: CommitThenWriteTerminalEventInput<TerminalEvent, TerminalWriteResult, CommitErrorWriteResult>) => Promise<CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult>>;
74
+ declare const writeDurableAgentEvent: <Event extends object>(input: WriteDurableAgentEventInput<Event>) => Effect.Effect<SequencedDurableAgentEvent<Event>, unknown>;
75
+ declare const commitThenWriteTerminalEvent: <TerminalEvent extends object, TerminalWriteResult, CommitErrorWriteResult, CommitError, TerminalWriteError, CommitErrorWriteError, CloseError>(input: CommitThenWriteTerminalEventInput<TerminalEvent, TerminalWriteResult, CommitErrorWriteResult, CommitError, TerminalWriteError, CommitErrorWriteError, CloseError>) => Effect.Effect<CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult>, never>;
67
76
  //#endregion
68
77
  export { CommitThenWriteTerminalEventInput, CommitThenWriteTerminalEventResult, DurableAgentEvent, DurableAgentEventIdInput, DurableAgentEventSequencerState, SequenceDurableAgentEventInput, SequencedDurableAgentEvent, TerminalEventCloseResult, WriteDurableAgentEventInput, commitThenWriteTerminalEvent, durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent };
69
78
  //# sourceMappingURL=workflow-events.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-events.d.mts","names":[],"sources":["../src/workflow-events.ts"],"mappings":";KAAY,+BAAA;EAAA,SACD,aAAa;AAAA;AAAA,KAGZ,iBAAA,kCAAmD,KAAK;EAAA,SACzD,OAAA;EAAA,SACA,WAAA;AAAA;AAAA,KAGC,wBAAA;EAAA,SACD,QAAA;EAAA,SACA,IAAA;EAAA,SACA,aAAA;AAAA;AAAA,KAGC,8BAAA;EAAA,SACD,KAAA,EAAO,+BAAA;EAAA,SACP,QAAA;EAAA,SACA,IAAA;EAAA,SACA,KAAA,EAAO,KAAK;EAAA,SACZ,WAAA;AAAA;AAAA,KAGC,0BAAA;EAAA,SACD,KAAA,EAAO,iBAAA,CAAkB,KAAA;EAAA,SACzB,aAAA;EAAA,SACA,iBAAA;EAAA,SACA,SAAA,EAAW,+BAAA;AAAA;AAAA,KAGV,2BAAA,kCACV,8BAAA,CAA+B,KAAA;EAAA,SACpB,MAAA,EAAQ,2BAAA,CAA4B,UAAA;AAAA;AAAA,KAGrC,wBAAA;EAAA,SACG,IAAA;AAAA;EAAA,SACA,IAAA;EAAA,SAA8B,KAAA;AAAA;AAAA,KAEjC,iCAAA;EAAA,SAKD,MAAA,QAAc,OAAA;EAAA,SACd,QAAA,EAAU,aAAA;EAAA,SACV,KAAA,GAAQ,KAAA,EAAO,aAAA,KAAkB,OAAA,CAAQ,mBAAA;EAAA,SACzC,gBAAA,GAAmB,KAAA,cAAmB,OAAA,CAAQ,sBAAA;EAAA,SAC9C,KAAA,QAAa,OAAA;AAAA;AAAA,KAGZ,kCAAA;EAAA,SAEG,IAAA;EAAA,SACA,WAAA,EAAa,mBAAA;EAAA,SACb,WAAA,EAAa,wBAAA;AAAA;EAAA,SAGb,IAAA;EAAA,SACA,WAAA;EAAA,SACA,WAAA,EAAa,sBAAA;EAAA,SACb,WAAA,EAAa,wBAAA;AAAA;EAAA,SAGb,IAAA;EAAA,SACA,KAAA;EAAA,SACA,WAAA,EAAa,wBAAA;AAAA;EAAA,SAGb,IAAA;EAAA,SACA,WAAA;EAAA,SACA,KAAA;EAAA,SACA,WAAA,EAAa,wBAAA;AAAA;AAAA,cAKf,mCAAA,GACX,aAAA,cACC,+BAAsD;AAAA,cAE5C,mBAAA,GAAuB,KAA+B,EAAxB,wBAAwB;AAAA,cAGtD,yBAAA,yBACX,KAAA,EAAO,8BAAA,CAA+B,KAAA,MACrC,0BAAA,CAA2B,KAAA;AAAA,cAwBjB,sBAAA,yBACX,KAAA,EAAO,2BAAA,CAA4B,KAAA,MAClC,OAAA,CAAQ,0BAAA,CAA2B,KAAA;AAAA,cAmBzB,4BAAA,8EAKX,KAAA,EAAO,iCAAA,CACL,aAAA,EACA,mBAAA,EACA,sBAAA,MAED,OAAA,CAAQ,kCAAA,CAAmC,mBAAA,EAAqB,sBAAA"}
1
+ {"version":3,"file":"workflow-events.d.mts","names":[],"sources":["../src/workflow-events.ts"],"mappings":";;;KAEY,+BAAA;EAAA,SACD,aAAa;AAAA;AAAA,KAGZ,iBAAA,kCAAmD,KAAK;EAAA,SACzD,OAAA;EAAA,SACA,WAAA;AAAA;AAAA,KAGC,wBAAA;EAAA,SACD,QAAA;EAAA,SACA,IAAA;EAAA,SACA,aAAA;AAAA;AAAA,KAGC,8BAAA;EAAA,SACD,KAAA,EAAO,+BAAA;EAVP;;AAAW;AAGtB;;;;EAHW,SAkBA,QAAA;EAAA,SACA,IAAA;EAAA,SACA,KAAA,EAAO,KAAK;EAAA,SACZ,WAAA;AAAA;AAAA,KAGC,0BAAA;EAAA,SACD,KAAA,EAAO,iBAAA,CAAkB,KAAA;EAAA,SACzB,aAAA;EAAA,SACA,iBAAA;EAAA,SACA,SAAA,EAAW,+BAAA;AAAA;AAAA,KAGV,2BAAA,kCACV,8BAAA,CAA+B,KAAA;EAAA,SACpB,MAAA,EAAQ,2BAAA,CAA4B,UAAA;AAAA;AAAA,KAGrC,wBAAA;EAAA,SACG,IAAA;AAAA;EAAA,SACA,IAAA;EAAA,SAA8B,KAAA;AAAA;AAAA,KAEjC,iCAAA;EAAA,SASD,MAAA,EAAQ,MAAA,CAAO,MAAA,OAAa,WAAA;EAAA,SAC5B,QAAA,EAAU,aAAA;EAAA,SACV,KAAA,GAAQ,KAAA,EAAO,aAAA,KAAkB,MAAA,CAAO,MAAA,CAAO,mBAAA,EAAqB,kBAAA;EAAA,SACpE,gBAAA,GACP,KAAA,cACG,MAAA,CAAO,MAAA,CAAO,sBAAA,EAAwB,qBAAA;EAAA,SAClC,KAAA,EAAO,MAAA,CAAO,MAAA,OAAa,UAAA;AAAA;AAAA,KAG1B,kCAAA;EAAA,SAEG,IAAA;EAAA,SACA,WAAA,EAAa,mBAAA;EAAA,SACb,WAAA,EAAa,wBAAA;AAAA;EAAA,SAGb,IAAA;EAAA,SACA,WAAA;EAAA,SACA,WAAA,EAAa,sBAAA;EAAA,SACb,WAAA,EAAa,wBAAA;AAAA;EAAA,SAGb,IAAA;EAAA,SACA,KAAA;EAAA,SACA,WAAA,EAAa,wBAAA;AAAA;EAAA,SAGb,IAAA;EAAA,SACA,WAAA;EAAA,SACA,KAAA;EAAA,SACA,WAAA,EAAa,wBAAA;AAAA;AAAA,cAKf,mCAAA,GACX,aAAA,cACC,+BAAsD;AAAA,cAE5C,mBAAA,GAAuB,KAA+B,EAAxB,wBAAwB;AAAA,cAGtD,yBAAA,yBACX,KAAA,EAAO,8BAAA,CAA+B,KAAA,MACrC,0BAAA,CAA2B,KAAA;AAAA,cAwBjB,sBAAA,yBACX,KAAA,EAAO,2BAAA,CAA4B,KAAA,MAClC,MAAA,CAAO,MAAA,CAAO,0BAAA,CAA2B,KAAA;AAAA,cAoE/B,4BAAA,kJASX,KAAA,EAAO,iCAAA,CACL,aAAA,EACA,mBAAA,EACA,sBAAA,EACA,WAAA,EACA,kBAAA,EACA,qBAAA,EACA,UAAA,MAED,MAAA,CAAO,MAAA,CACR,kCAAA,CAAmC,mBAAA,EAAqB,sBAAA"}
@@ -1,3 +1,4 @@
1
+ import { Effect } from "effect";
1
2
  //#region src/workflow-events.ts
2
3
  const textEncoder = new TextEncoder();
3
4
  const makeDurableAgentEventSequencerState = (eventSequence = 0) => ({ eventSequence });
@@ -21,56 +22,55 @@ const sequenceDurableAgentEvent = (input) => {
21
22
  };
22
23
  };
23
24
  const encodeDurableAgentEventNdjson = (event) => textEncoder.encode(`${JSON.stringify(event)}\n`);
24
- const writeDurableAgentEvent = async (input) => {
25
+ const writeDurableAgentEvent = (input) => Effect.gen(function* () {
25
26
  const sequenced = sequenceDurableAgentEvent(input);
26
- await input.writer.write(encodeDurableAgentEventNdjson(sequenced.event));
27
+ yield* Effect.tryPromise({
28
+ try: () => input.writer.write(encodeDurableAgentEventNdjson(sequenced.event)),
29
+ catch: (cause) => cause
30
+ });
27
31
  return sequenced;
28
- };
29
- const closeTerminalEventWriter = async (close) => {
30
- try {
31
- await close();
32
- return { _tag: "Closed" };
33
- } catch (error) {
34
- return {
35
- _tag: "CloseFailed",
36
- error
37
- };
38
- }
39
- };
40
- const commitThenWriteTerminalEvent = async (input) => {
41
- try {
42
- await input.commit();
43
- } catch (commitError) {
44
- try {
45
- return {
46
- _tag: "CommitFailed",
47
- commitError,
48
- writeResult: await input.writeCommitError(commitError),
49
- closeResult: await closeTerminalEventWriter(input.close)
50
- };
51
- } catch (error) {
52
- return {
53
- _tag: "CommitErrorWriteFailed",
54
- commitError,
55
- error,
56
- closeResult: await closeTerminalEventWriter(input.close)
57
- };
58
- }
59
- }
60
- try {
61
- return {
62
- _tag: "Committed",
63
- writeResult: await input.write(input.terminal),
64
- closeResult: await closeTerminalEventWriter(input.close)
65
- };
66
- } catch (error) {
67
- return {
68
- _tag: "TerminalWriteFailed",
69
- error,
70
- closeResult: await closeTerminalEventWriter(input.close)
71
- };
72
- }
73
- };
32
+ });
33
+ const closedTerminalEventWriterResult = () => ({ _tag: "Closed" });
34
+ const closeFailedTerminalEventWriterResult = (error) => ({
35
+ _tag: "CloseFailed",
36
+ error
37
+ });
38
+ const committedTerminalResult = (writeResult, closeResult) => ({
39
+ _tag: "Committed",
40
+ writeResult,
41
+ closeResult
42
+ });
43
+ const commitFailedTerminalResult = (commitError, writeResult, closeResult) => ({
44
+ _tag: "CommitFailed",
45
+ commitError,
46
+ writeResult,
47
+ closeResult
48
+ });
49
+ const terminalWriteFailedResult = (error, closeResult) => ({
50
+ _tag: "TerminalWriteFailed",
51
+ error,
52
+ closeResult
53
+ });
54
+ const commitErrorWriteFailedResult = (commitError, error, closeResult) => ({
55
+ _tag: "CommitErrorWriteFailed",
56
+ commitError,
57
+ error,
58
+ closeResult
59
+ });
60
+ const closeTerminalEventWriterEffect = (close) => close.pipe(Effect.match({
61
+ onFailure: closeFailedTerminalEventWriterResult,
62
+ onSuccess: () => closedTerminalEventWriterResult()
63
+ }));
64
+ const commitThenWriteTerminalEvent = (input) => input.commit.pipe(Effect.matchEffect({
65
+ onFailure: (commitError) => input.writeCommitError(commitError).pipe(Effect.matchEffect({
66
+ onFailure: (error) => closeTerminalEventWriterEffect(input.close).pipe(Effect.map((closeResult) => commitErrorWriteFailedResult(commitError, error, closeResult))),
67
+ onSuccess: (writeResult) => closeTerminalEventWriterEffect(input.close).pipe(Effect.map((closeResult) => commitFailedTerminalResult(commitError, writeResult, closeResult)))
68
+ })),
69
+ onSuccess: () => input.write(input.terminal).pipe(Effect.matchEffect({
70
+ onFailure: (error) => closeTerminalEventWriterEffect(input.close).pipe(Effect.map((closeResult) => terminalWriteFailedResult(error, closeResult))),
71
+ onSuccess: (writeResult) => closeTerminalEventWriterEffect(input.close).pipe(Effect.map((closeResult) => committedTerminalResult(writeResult, closeResult)))
72
+ }))
73
+ }));
74
74
  //#endregion
75
75
  export { commitThenWriteTerminalEvent, durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent };
76
76
 
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-events.mjs","names":[],"sources":["../src/workflow-events.ts"],"sourcesContent":["export type DurableAgentEventSequencerState = {\n readonly eventSequence: number\n}\n\nexport type DurableAgentEvent<Event extends object = object> = Event & {\n readonly eventId: string\n readonly createdAtMs?: number\n}\n\nexport type DurableAgentEventIdInput = {\n readonly streamId: string\n readonly turn: number\n readonly eventSequence: number\n}\n\nexport type SequenceDurableAgentEventInput<Event extends object = object> = {\n readonly state: DurableAgentEventSequencerState\n readonly streamId: string\n readonly turn: number\n readonly event: Event\n readonly createdAtMs?: number\n}\n\nexport type SequencedDurableAgentEvent<Event extends object = object> = {\n readonly event: DurableAgentEvent<Event>\n readonly eventSequence: number\n readonly nextEventSequence: number\n readonly nextState: DurableAgentEventSequencerState\n}\n\nexport type WriteDurableAgentEventInput<Event extends object = object> =\n SequenceDurableAgentEventInput<Event> & {\n readonly writer: WritableStreamDefaultWriter<Uint8Array>\n }\n\nexport type TerminalEventCloseResult =\n | { readonly _tag: 'Closed' }\n | { readonly _tag: 'CloseFailed'; readonly error: unknown }\n\nexport type CommitThenWriteTerminalEventInput<\n TerminalEvent extends object,\n TerminalWriteResult,\n CommitErrorWriteResult\n> = {\n readonly commit: () => Promise<void>\n readonly terminal: TerminalEvent\n readonly write: (event: TerminalEvent) => Promise<TerminalWriteResult>\n readonly writeCommitError: (error: unknown) => Promise<CommitErrorWriteResult>\n readonly close: () => Promise<void>\n}\n\nexport type CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult> =\n | {\n readonly _tag: 'Committed'\n readonly writeResult: TerminalWriteResult\n readonly closeResult: TerminalEventCloseResult\n }\n | {\n readonly _tag: 'CommitFailed'\n readonly commitError: unknown\n readonly writeResult: CommitErrorWriteResult\n readonly closeResult: TerminalEventCloseResult\n }\n | {\n readonly _tag: 'TerminalWriteFailed'\n readonly error: unknown\n readonly closeResult: TerminalEventCloseResult\n }\n | {\n readonly _tag: 'CommitErrorWriteFailed'\n readonly commitError: unknown\n readonly error: unknown\n readonly closeResult: TerminalEventCloseResult\n }\n\nconst textEncoder = new TextEncoder()\n\nexport const makeDurableAgentEventSequencerState = (\n eventSequence = 0\n): DurableAgentEventSequencerState => ({ eventSequence })\n\nexport const durableAgentEventId = (input: DurableAgentEventIdInput) =>\n `${input.streamId}:${input.turn}:${input.eventSequence}`\n\nexport const sequenceDurableAgentEvent = <Event extends object>(\n input: SequenceDurableAgentEventInput<Event>\n): SequencedDurableAgentEvent<Event> => {\n const eventSequence = input.state.eventSequence\n const nextEventSequence = eventSequence + 1\n const event = {\n ...input.event,\n eventId: durableAgentEventId({\n streamId: input.streamId,\n turn: input.turn,\n eventSequence\n }),\n ...(input.createdAtMs === undefined ? {} : { createdAtMs: input.createdAtMs })\n }\n\n return {\n event,\n eventSequence,\n nextEventSequence,\n nextState: makeDurableAgentEventSequencerState(nextEventSequence)\n }\n}\n\nconst encodeDurableAgentEventNdjson = <Event extends object>(event: DurableAgentEvent<Event>) =>\n textEncoder.encode(`${JSON.stringify(event)}\\n`)\n\nexport const writeDurableAgentEvent = async <Event extends object>(\n input: WriteDurableAgentEventInput<Event>\n): Promise<SequencedDurableAgentEvent<Event>> => {\n const sequenced = sequenceDurableAgentEvent(input)\n await input.writer.write(encodeDurableAgentEventNdjson(sequenced.event))\n\n return sequenced\n}\n\nconst closeTerminalEventWriter = async (\n close: () => Promise<void>\n): Promise<TerminalEventCloseResult> => {\n try {\n await close()\n\n return { _tag: 'Closed' }\n } catch (error) {\n return { _tag: 'CloseFailed', error }\n }\n}\n\nexport const commitThenWriteTerminalEvent = async <\n TerminalEvent extends object,\n TerminalWriteResult,\n CommitErrorWriteResult\n>(\n input: CommitThenWriteTerminalEventInput<\n TerminalEvent,\n TerminalWriteResult,\n CommitErrorWriteResult\n >\n): Promise<CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult>> => {\n try {\n await input.commit()\n } catch (commitError) {\n try {\n const writeResult = await input.writeCommitError(commitError)\n const closeResult = await closeTerminalEventWriter(input.close)\n\n return { _tag: 'CommitFailed', commitError, writeResult, closeResult }\n } catch (error) {\n const closeResult = await closeTerminalEventWriter(input.close)\n\n return { _tag: 'CommitErrorWriteFailed', commitError, error, closeResult }\n }\n }\n\n try {\n const writeResult = await input.write(input.terminal)\n const closeResult = await closeTerminalEventWriter(input.close)\n\n return { _tag: 'Committed', writeResult, closeResult }\n } catch (error) {\n const closeResult = await closeTerminalEventWriter(input.close)\n\n return { _tag: 'TerminalWriteFailed', error, closeResult }\n }\n}\n"],"mappings":";AA2EA,MAAM,cAAc,IAAI,YAAY;AAEpC,MAAa,uCACX,gBAAgB,OACqB,EAAE,cAAc;AAEvD,MAAa,uBAAuB,UAClC,GAAG,MAAM,SAAS,GAAG,MAAM,KAAK,GAAG,MAAM;AAE3C,MAAa,6BACX,UACsC;CACtC,MAAM,gBAAgB,MAAM,MAAM;CAClC,MAAM,oBAAoB,gBAAgB;CAW1C,OAAO;EACL,OAAA;GAVA,GAAG,MAAM;GACT,SAAS,oBAAoB;IAC3B,UAAU,MAAM;IAChB,MAAM,MAAM;IACZ;GACF,CAAC;GACD,GAAI,MAAM,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,aAAa,MAAM,YAAY;EAIxE;EACJ;EACA;EACA,WAAW,oCAAoC,iBAAiB;CAClE;AACF;AAEA,MAAM,iCAAuD,UAC3D,YAAY,OAAO,GAAG,KAAK,UAAU,KAAK,EAAE,GAAG;AAEjD,MAAa,yBAAyB,OACpC,UAC+C;CAC/C,MAAM,YAAY,0BAA0B,KAAK;CACjD,MAAM,MAAM,OAAO,MAAM,8BAA8B,UAAU,KAAK,CAAC;CAEvE,OAAO;AACT;AAEA,MAAM,2BAA2B,OAC/B,UACsC;CACtC,IAAI;EACF,MAAM,MAAM;EAEZ,OAAO,EAAE,MAAM,SAAS;CAC1B,SAAS,OAAO;EACd,OAAO;GAAE,MAAM;GAAe;EAAM;CACtC;AACF;AAEA,MAAa,+BAA+B,OAK1C,UAK6F;CAC7F,IAAI;EACF,MAAM,MAAM,OAAO;CACrB,SAAS,aAAa;EACpB,IAAI;GAIF,OAAO;IAAE,MAAM;IAAgB;IAAa,aAAA,MAHlB,MAAM,iBAAiB,WAAW;IAGH,aAAA,MAF/B,yBAAyB,MAAM,KAAK;GAEO;EACvE,SAAS,OAAO;GAGd,OAAO;IAAE,MAAM;IAA0B;IAAa;IAAO,aAAA,MAFnC,yBAAyB,MAAM,KAAK;GAEW;EAC3E;CACF;CAEA,IAAI;EAIF,OAAO;GAAE,MAAM;GAAa,aAAA,MAHF,MAAM,MAAM,MAAM,QAAQ;GAGX,aAAA,MAFf,yBAAyB,MAAM,KAAK;EAET;CACvD,SAAS,OAAO;EAGd,OAAO;GAAE,MAAM;GAAuB;GAAO,aAAA,MAFnB,yBAAyB,MAAM,KAAK;EAEL;CAC3D;AACF"}
1
+ {"version":3,"file":"workflow-events.mjs","names":[],"sources":["../src/workflow-events.ts"],"sourcesContent":["import { Effect } from 'effect'\n\nexport type DurableAgentEventSequencerState = {\n readonly eventSequence: number\n}\n\nexport type DurableAgentEvent<Event extends object = object> = Event & {\n readonly eventId: string\n readonly createdAtMs?: number\n}\n\nexport type DurableAgentEventIdInput = {\n readonly streamId: string\n readonly turn: number\n readonly eventSequence: number\n}\n\nexport type SequenceDurableAgentEventInput<Event extends object = object> = {\n readonly state: DurableAgentEventSequencerState\n /**\n * Stable id namespace for one independent durable stream.\n *\n * Include the workflow/session/run id when multiple logical runs can be\n * projected in the same client. Replay-safe clients de-dupe by `eventId`, so\n * reusing a stream id across runs can drop legitimate follow-up events.\n */\n readonly streamId: string\n readonly turn: number\n readonly event: Event\n readonly createdAtMs?: number\n}\n\nexport type SequencedDurableAgentEvent<Event extends object = object> = {\n readonly event: DurableAgentEvent<Event>\n readonly eventSequence: number\n readonly nextEventSequence: number\n readonly nextState: DurableAgentEventSequencerState\n}\n\nexport type WriteDurableAgentEventInput<Event extends object = object> =\n SequenceDurableAgentEventInput<Event> & {\n readonly writer: WritableStreamDefaultWriter<Uint8Array>\n }\n\nexport type TerminalEventCloseResult =\n | { readonly _tag: 'Closed' }\n | { readonly _tag: 'CloseFailed'; readonly error: unknown }\n\nexport type CommitThenWriteTerminalEventInput<\n TerminalEvent extends object,\n TerminalWriteResult,\n CommitErrorWriteResult,\n CommitError,\n TerminalWriteError,\n CommitErrorWriteError,\n CloseError\n> = {\n readonly commit: Effect.Effect<void, CommitError>\n readonly terminal: TerminalEvent\n readonly write: (event: TerminalEvent) => Effect.Effect<TerminalWriteResult, TerminalWriteError>\n readonly writeCommitError: (\n error: unknown\n ) => Effect.Effect<CommitErrorWriteResult, CommitErrorWriteError>\n readonly close: Effect.Effect<void, CloseError>\n}\n\nexport type CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult> =\n | {\n readonly _tag: 'Committed'\n readonly writeResult: TerminalWriteResult\n readonly closeResult: TerminalEventCloseResult\n }\n | {\n readonly _tag: 'CommitFailed'\n readonly commitError: unknown\n readonly writeResult: CommitErrorWriteResult\n readonly closeResult: TerminalEventCloseResult\n }\n | {\n readonly _tag: 'TerminalWriteFailed'\n readonly error: unknown\n readonly closeResult: TerminalEventCloseResult\n }\n | {\n readonly _tag: 'CommitErrorWriteFailed'\n readonly commitError: unknown\n readonly error: unknown\n readonly closeResult: TerminalEventCloseResult\n }\n\nconst textEncoder = new TextEncoder()\n\nexport const makeDurableAgentEventSequencerState = (\n eventSequence = 0\n): DurableAgentEventSequencerState => ({ eventSequence })\n\nexport const durableAgentEventId = (input: DurableAgentEventIdInput) =>\n `${input.streamId}:${input.turn}:${input.eventSequence}`\n\nexport const sequenceDurableAgentEvent = <Event extends object>(\n input: SequenceDurableAgentEventInput<Event>\n): SequencedDurableAgentEvent<Event> => {\n const eventSequence = input.state.eventSequence\n const nextEventSequence = eventSequence + 1\n const event = {\n ...input.event,\n eventId: durableAgentEventId({\n streamId: input.streamId,\n turn: input.turn,\n eventSequence\n }),\n ...(input.createdAtMs === undefined ? {} : { createdAtMs: input.createdAtMs })\n }\n\n return {\n event,\n eventSequence,\n nextEventSequence,\n nextState: makeDurableAgentEventSequencerState(nextEventSequence)\n }\n}\n\nconst encodeDurableAgentEventNdjson = <Event extends object>(event: DurableAgentEvent<Event>) =>\n textEncoder.encode(`${JSON.stringify(event)}\\n`)\n\nexport const writeDurableAgentEvent = <Event extends object>(\n input: WriteDurableAgentEventInput<Event>\n): Effect.Effect<SequencedDurableAgentEvent<Event>, unknown> =>\n Effect.gen(function* () {\n const sequenced = sequenceDurableAgentEvent(input)\n yield* Effect.tryPromise({\n try: () => input.writer.write(encodeDurableAgentEventNdjson(sequenced.event)),\n catch: cause => cause\n })\n\n return sequenced\n })\n\nconst closedTerminalEventWriterResult = (): TerminalEventCloseResult => ({ _tag: 'Closed' })\n\nconst closeFailedTerminalEventWriterResult = (error: unknown): TerminalEventCloseResult => ({\n _tag: 'CloseFailed',\n error\n})\n\nconst committedTerminalResult = <TerminalWriteResult, CommitErrorWriteResult>(\n writeResult: TerminalWriteResult,\n closeResult: TerminalEventCloseResult\n): CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult> => ({\n _tag: 'Committed',\n writeResult,\n closeResult\n})\n\nconst commitFailedTerminalResult = <TerminalWriteResult, CommitErrorWriteResult>(\n commitError: unknown,\n writeResult: CommitErrorWriteResult,\n closeResult: TerminalEventCloseResult\n): CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult> => ({\n _tag: 'CommitFailed',\n commitError,\n writeResult,\n closeResult\n})\n\nconst terminalWriteFailedResult = <TerminalWriteResult, CommitErrorWriteResult>(\n error: unknown,\n closeResult: TerminalEventCloseResult\n): CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult> => ({\n _tag: 'TerminalWriteFailed',\n error,\n closeResult\n})\n\nconst commitErrorWriteFailedResult = <TerminalWriteResult, CommitErrorWriteResult>(\n commitError: unknown,\n error: unknown,\n closeResult: TerminalEventCloseResult\n): CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult> => ({\n _tag: 'CommitErrorWriteFailed',\n commitError,\n error,\n closeResult\n})\n\nconst closeTerminalEventWriterEffect = <CloseError>(\n close: Effect.Effect<void, CloseError>\n): Effect.Effect<TerminalEventCloseResult, never> =>\n close.pipe(\n Effect.match({\n onFailure: closeFailedTerminalEventWriterResult,\n onSuccess: () => closedTerminalEventWriterResult()\n })\n )\n\nexport const commitThenWriteTerminalEvent = <\n TerminalEvent extends object,\n TerminalWriteResult,\n CommitErrorWriteResult,\n CommitError,\n TerminalWriteError,\n CommitErrorWriteError,\n CloseError\n>(\n input: CommitThenWriteTerminalEventInput<\n TerminalEvent,\n TerminalWriteResult,\n CommitErrorWriteResult,\n CommitError,\n TerminalWriteError,\n CommitErrorWriteError,\n CloseError\n >\n): Effect.Effect<\n CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult>,\n never\n> =>\n input.commit.pipe(\n Effect.matchEffect({\n onFailure: commitError =>\n input.writeCommitError(commitError).pipe(\n Effect.matchEffect({\n onFailure: error =>\n closeTerminalEventWriterEffect(input.close).pipe(\n Effect.map(closeResult =>\n commitErrorWriteFailedResult<TerminalWriteResult, CommitErrorWriteResult>(\n commitError,\n error,\n closeResult\n )\n )\n ),\n onSuccess: writeResult =>\n closeTerminalEventWriterEffect(input.close).pipe(\n Effect.map(closeResult =>\n commitFailedTerminalResult<TerminalWriteResult, CommitErrorWriteResult>(\n commitError,\n writeResult,\n closeResult\n )\n )\n )\n })\n ),\n onSuccess: () =>\n input.write(input.terminal).pipe(\n Effect.matchEffect({\n onFailure: error =>\n closeTerminalEventWriterEffect(input.close).pipe(\n Effect.map(closeResult =>\n terminalWriteFailedResult<TerminalWriteResult, CommitErrorWriteResult>(\n error,\n closeResult\n )\n )\n ),\n onSuccess: writeResult =>\n closeTerminalEventWriterEffect(input.close).pipe(\n Effect.map(closeResult =>\n committedTerminalResult<TerminalWriteResult, CommitErrorWriteResult>(\n writeResult,\n closeResult\n )\n )\n )\n })\n )\n })\n )\n"],"mappings":";;AA0FA,MAAM,cAAc,IAAI,YAAY;AAEpC,MAAa,uCACX,gBAAgB,OACqB,EAAE,cAAc;AAEvD,MAAa,uBAAuB,UAClC,GAAG,MAAM,SAAS,GAAG,MAAM,KAAK,GAAG,MAAM;AAE3C,MAAa,6BACX,UACsC;CACtC,MAAM,gBAAgB,MAAM,MAAM;CAClC,MAAM,oBAAoB,gBAAgB;CAW1C,OAAO;EACL,OAAA;GAVA,GAAG,MAAM;GACT,SAAS,oBAAoB;IAC3B,UAAU,MAAM;IAChB,MAAM,MAAM;IACZ;GACF,CAAC;GACD,GAAI,MAAM,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,aAAa,MAAM,YAAY;EAIxE;EACJ;EACA;EACA,WAAW,oCAAoC,iBAAiB;CAClE;AACF;AAEA,MAAM,iCAAuD,UAC3D,YAAY,OAAO,GAAG,KAAK,UAAU,KAAK,EAAE,GAAG;AAEjD,MAAa,0BACX,UAEA,OAAO,IAAI,aAAa;CACtB,MAAM,YAAY,0BAA0B,KAAK;CACjD,OAAO,OAAO,WAAW;EACvB,WAAW,MAAM,OAAO,MAAM,8BAA8B,UAAU,KAAK,CAAC;EAC5E,QAAO,UAAS;CAClB,CAAC;CAED,OAAO;AACT,CAAC;AAEH,MAAM,yCAAmE,EAAE,MAAM,SAAS;AAE1F,MAAM,wCAAwC,WAA8C;CAC1F,MAAM;CACN;AACF;AAEA,MAAM,2BACJ,aACA,iBACqF;CACrF,MAAM;CACN;CACA;AACF;AAEA,MAAM,8BACJ,aACA,aACA,iBACqF;CACrF,MAAM;CACN;CACA;CACA;AACF;AAEA,MAAM,6BACJ,OACA,iBACqF;CACrF,MAAM;CACN;CACA;AACF;AAEA,MAAM,gCACJ,aACA,OACA,iBACqF;CACrF,MAAM;CACN;CACA;CACA;AACF;AAEA,MAAM,kCACJ,UAEA,MAAM,KACJ,OAAO,MAAM;CACX,WAAW;CACX,iBAAiB,gCAAgC;AACnD,CAAC,CACH;AAEF,MAAa,gCASX,UAaA,MAAM,OAAO,KACX,OAAO,YAAY;CACjB,YAAW,gBACT,MAAM,iBAAiB,WAAW,EAAE,KAClC,OAAO,YAAY;EACjB,YAAW,UACT,+BAA+B,MAAM,KAAK,EAAE,KAC1C,OAAO,KAAI,gBACT,6BACE,aACA,OACA,WACF,CACF,CACF;EACF,YAAW,gBACT,+BAA+B,MAAM,KAAK,EAAE,KAC1C,OAAO,KAAI,gBACT,2BACE,aACA,aACA,WACF,CACF,CACF;CACJ,CAAC,CACH;CACF,iBACE,MAAM,MAAM,MAAM,QAAQ,EAAE,KAC1B,OAAO,YAAY;EACjB,YAAW,UACT,+BAA+B,MAAM,KAAK,EAAE,KAC1C,OAAO,KAAI,gBACT,0BACE,OACA,WACF,CACF,CACF;EACF,YAAW,gBACT,+BAA+B,MAAM,KAAK,EAAE,KAC1C,OAAO,KAAI,gBACT,wBACE,aACA,WACF,CACF,CACF;CACJ,CAAC,CACH;AACJ,CAAC,CACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-loop.d.mts","names":[],"sources":["../src/workflow-loop.ts"],"mappings":"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"}
1
+ {"version":3,"file":"workflow-loop.d.mts","names":[],"sources":["../src/workflow-loop.ts"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-loop.mjs","names":[],"sources":["../src/workflow-loop.ts"],"sourcesContent":["export type VercelAgentWorkflowInput = {\n readonly request: unknown\n readonly context: unknown\n}\n\nexport type SerializableWorkflowState = {\n readonly request: unknown\n readonly messages?: ReadonlyArray<unknown>\n readonly createdMessages: ReadonlyArray<unknown>\n readonly usage?: unknown\n readonly turn: number\n readonly eventSequence?: number\n}\n\nexport type VercelAgentWorkflowModelStepInput = {\n readonly context: unknown\n readonly state: SerializableWorkflowState\n}\n\nexport type VercelAgentWorkflowModelStepResult = {\n readonly done: boolean\n readonly messages: ReadonlyArray<unknown>\n readonly createdMessages: ReadonlyArray<unknown>\n readonly toolCalls: ReadonlyArray<unknown>\n readonly usage: unknown\n readonly turn: number\n readonly eventSequence?: number\n}\n\nexport type VercelAgentWorkflowToolBatchStepInput = {\n readonly context: unknown\n readonly request: unknown\n readonly calls: ReadonlyArray<unknown>\n readonly createdMessages: ReadonlyArray<unknown>\n readonly hitlResponses?: ReadonlyArray<unknown>\n readonly usage?: unknown\n readonly turn?: number\n readonly eventSequence?: number\n}\n\nexport type VercelAgentWorkflowAwaitingInput = {\n readonly hookToken: string\n readonly requests: ReadonlyArray<unknown>\n readonly messages: ReadonlyArray<unknown>\n readonly usage: unknown\n readonly turns: number\n readonly eventSequence?: number\n}\n\nexport type VercelAgentWorkflowToolBatchStepResult = {\n readonly messages: ReadonlyArray<unknown>\n readonly createdMessages: ReadonlyArray<unknown>\n readonly awaitingInput?: VercelAgentWorkflowAwaitingInput\n readonly eventSequence?: number\n}\n\nexport type WorkflowStepResult<A> =\n | {\n readonly _tag: 'Success'\n readonly value: A\n }\n | {\n readonly _tag: 'Failure'\n readonly error: unknown\n }\n\nexport type VercelAgentWorkflowStepRetryPolicy = {\n readonly maxAttempts: number\n}\n\nexport type VercelAgentWorkflowRunResult =\n | {\n readonly _tag: 'Completed'\n readonly turns: number\n readonly state: SerializableWorkflowState\n }\n | {\n readonly _tag: 'ModelStepFailed'\n readonly turn: number\n readonly error: unknown\n readonly state: SerializableWorkflowState\n }\n | {\n readonly _tag: 'ToolBatchStepFailed'\n readonly turn: number\n readonly error: unknown\n readonly state: SerializableWorkflowState\n }\n | {\n readonly _tag: 'AwaitInputFailed'\n readonly turn: number\n readonly error: unknown\n readonly awaitingInput: VercelAgentWorkflowAwaitingInput\n readonly state: SerializableWorkflowState\n }\n | {\n readonly _tag: 'CloseStreamFailed'\n readonly turns: number\n readonly error: unknown\n readonly state: SerializableWorkflowState\n }\n | {\n readonly _tag: 'MaxTurnsExceeded'\n readonly maxTurns: number\n readonly error: Error\n readonly state: SerializableWorkflowState\n }\n\nexport type VercelAgentWorkflowLoopConfig = {\n readonly input: VercelAgentWorkflowInput\n readonly maxTurns?: number\n readonly runModelStep: (\n input: VercelAgentWorkflowModelStepInput\n ) => Promise<VercelAgentWorkflowModelStepResult>\n readonly runToolBatchStep: (\n input: VercelAgentWorkflowToolBatchStepInput\n ) => Promise<VercelAgentWorkflowToolBatchStepResult>\n readonly closeStream: () => Promise<void>\n readonly writeError: (error: unknown) => Promise<void>\n readonly awaitInput?: (input: VercelAgentWorkflowAwaitingInput) => Promise<unknown>\n readonly modelStepRetry?: VercelAgentWorkflowStepRetryPolicy\n readonly toolBatchStepRetry?: VercelAgentWorkflowStepRetryPolicy\n readonly awaitInputRetry?: VercelAgentWorkflowStepRetryPolicy\n readonly closeStreamRetry?: VercelAgentWorkflowStepRetryPolicy\n}\n\nexport const defaultMaxWorkflowTurns = 500\nexport const noWorkflowStepRetry: VercelAgentWorkflowStepRetryPolicy = { maxAttempts: 1 }\n\nexport const settleWorkflowStep = <A>(promise: Promise<A>): Promise<WorkflowStepResult<A>> =>\n promise.then(\n value => ({ _tag: 'Success', value }),\n error => ({ _tag: 'Failure', error })\n )\n\nconst workflowMaxTurnsError = (maxTurns: number) =>\n new Error(`Vercel agent workflow exceeded max turns: ${maxTurns}`)\n\nconst writeErrorSafely = (writeError: (error: unknown) => Promise<void>, error: unknown) =>\n writeError(error).catch(() => undefined)\n\nconst missingAwaitInputHandlerError = () =>\n new Error(\n 'Vercel agent workflow awaiting input requested but no awaitInput handler is configured'\n )\n\nconst maxRetryAttempts = (policy: VercelAgentWorkflowStepRetryPolicy | undefined) =>\n Math.max(1, Math.floor(policy?.maxAttempts ?? noWorkflowStepRetry.maxAttempts))\n\nexport async function retryWorkflowStep<A>(\n runStep: () => Promise<A>,\n policy?: VercelAgentWorkflowStepRetryPolicy\n): Promise<A> {\n const maxAttempts = maxRetryAttempts(policy)\n let attempt = 1\n\n for (;;) {\n try {\n return await runStep()\n } catch (error) {\n if (attempt >= maxAttempts) {\n throw error\n }\n\n attempt += 1\n }\n }\n}\n\nexport async function runVercelAgentWorkflow(\n config: VercelAgentWorkflowLoopConfig\n): Promise<VercelAgentWorkflowRunResult> {\n const {\n input,\n maxTurns: configuredMaxTurns,\n runModelStep,\n runToolBatchStep,\n closeStream,\n writeError,\n awaitInput,\n modelStepRetry,\n toolBatchStepRetry,\n awaitInputRetry,\n closeStreamRetry\n } = config\n let state: SerializableWorkflowState = {\n request: input.request,\n createdMessages: [],\n turn: 1,\n eventSequence: 0\n }\n const maxTurns = configuredMaxTurns ?? defaultMaxWorkflowTurns\n\n for (let step = 0; step < maxTurns; step++) {\n const modelResult = await settleWorkflowStep(\n retryWorkflowStep(() => runModelStep({ context: input.context, state }), modelStepRetry)\n )\n\n if (modelResult._tag === 'Failure') {\n await writeErrorSafely(writeError, modelResult.error)\n return {\n _tag: 'ModelStepFailed',\n turn: state.turn,\n error: modelResult.error,\n state\n }\n }\n\n if (modelResult.value.done) {\n const closeResult = await settleWorkflowStep(retryWorkflowStep(closeStream, closeStreamRetry))\n\n if (closeResult._tag === 'Failure') {\n await writeErrorSafely(writeError, closeResult.error)\n\n return {\n _tag: 'CloseStreamFailed',\n turns: modelResult.value.turn,\n error: closeResult.error,\n state\n }\n }\n\n return {\n _tag: 'Completed',\n turns: modelResult.value.turn,\n state\n }\n }\n\n let completedToolsResult: VercelAgentWorkflowToolBatchStepResult | undefined\n let toolHitlResponses: ReadonlyArray<unknown> = []\n let toolEventSequence = modelResult.value.eventSequence ?? state.eventSequence\n\n for (;;) {\n const toolsResult = await settleWorkflowStep(\n retryWorkflowStep(\n () =>\n runToolBatchStep({\n context: input.context,\n request: input.request,\n calls: modelResult.value.toolCalls,\n createdMessages: modelResult.value.createdMessages,\n hitlResponses: toolHitlResponses,\n usage: modelResult.value.usage,\n turn: modelResult.value.turn,\n eventSequence: toolEventSequence\n }),\n toolBatchStepRetry\n )\n )\n\n if (toolsResult._tag === 'Failure') {\n await writeErrorSafely(writeError, toolsResult.error)\n\n return {\n _tag: 'ToolBatchStepFailed',\n turn: modelResult.value.turn,\n error: toolsResult.error,\n state\n }\n }\n\n if (toolsResult.value.awaitingInput === undefined) {\n completedToolsResult = toolsResult.value\n break\n }\n\n const awaitingInput = toolsResult.value.awaitingInput\n toolEventSequence =\n awaitingInput.eventSequence ?? toolsResult.value.eventSequence ?? toolEventSequence\n\n const hitlResponse = await settleWorkflowStep(\n retryWorkflowStep(() => {\n if (awaitInput === undefined) {\n return Promise.reject(missingAwaitInputHandlerError())\n }\n\n return awaitInput(awaitingInput)\n }, awaitInputRetry)\n )\n\n if (hitlResponse._tag === 'Failure') {\n await writeErrorSafely(writeError, hitlResponse.error)\n\n return {\n _tag: 'AwaitInputFailed',\n turn: modelResult.value.turn,\n error: hitlResponse.error,\n awaitingInput,\n state\n }\n }\n\n toolHitlResponses = [...toolHitlResponses, hitlResponse.value]\n }\n\n if (completedToolsResult === undefined) {\n const error = new Error('Vercel agent workflow tool batch did not complete')\n await writeErrorSafely(writeError, error)\n\n return {\n _tag: 'ToolBatchStepFailed',\n turn: modelResult.value.turn,\n error,\n state\n }\n }\n\n state = {\n request: input.request,\n messages: [...modelResult.value.messages, ...completedToolsResult.messages],\n createdMessages: completedToolsResult.createdMessages,\n usage: modelResult.value.usage,\n turn: modelResult.value.turn + 1,\n eventSequence: completedToolsResult.eventSequence ?? toolEventSequence\n }\n }\n\n const error = workflowMaxTurnsError(maxTurns)\n await writeErrorSafely(writeError, error)\n\n return {\n _tag: 'MaxTurnsExceeded',\n maxTurns,\n error,\n state\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"workflow-loop.mjs","names":[],"sources":["../src/workflow-loop.ts"],"sourcesContent":["export type VercelAgentWorkflowInput = {\n readonly request: unknown\n readonly context: unknown\n}\n\nexport type SerializableWorkflowState = {\n readonly request: unknown\n readonly messages?: ReadonlyArray<unknown>\n readonly createdMessages: ReadonlyArray<unknown>\n readonly usage?: unknown\n readonly turn: number\n readonly eventSequence?: number\n}\n\nexport type VercelAgentWorkflowModelStepInput = {\n readonly context: unknown\n readonly state: SerializableWorkflowState\n}\n\nexport type VercelAgentWorkflowModelStepResult = {\n readonly done: boolean\n readonly messages: ReadonlyArray<unknown>\n readonly createdMessages: ReadonlyArray<unknown>\n readonly toolCalls: ReadonlyArray<unknown>\n readonly usage: unknown\n readonly turn: number\n readonly eventSequence?: number\n}\n\nexport type VercelAgentWorkflowToolBatchStepInput = {\n readonly context: unknown\n readonly request: unknown\n readonly calls: ReadonlyArray<unknown>\n readonly createdMessages: ReadonlyArray<unknown>\n readonly hitlResponses?: ReadonlyArray<unknown>\n readonly usage?: unknown\n readonly turn?: number\n readonly eventSequence?: number\n}\n\nexport type VercelAgentWorkflowAwaitingInput = {\n readonly hookToken: string\n readonly requests: ReadonlyArray<unknown>\n readonly messages: ReadonlyArray<unknown>\n readonly usage: unknown\n readonly turns: number\n readonly eventSequence?: number\n}\n\nexport type VercelAgentWorkflowToolBatchStepResult = {\n readonly messages: ReadonlyArray<unknown>\n readonly createdMessages: ReadonlyArray<unknown>\n readonly awaitingInput?: VercelAgentWorkflowAwaitingInput\n readonly eventSequence?: number\n}\n\nexport type WorkflowStepResult<A> =\n | {\n readonly _tag: 'Success'\n readonly value: A\n }\n | {\n readonly _tag: 'Failure'\n readonly error: unknown\n }\n\nexport type VercelAgentWorkflowStepRetryPolicy = {\n readonly maxAttempts: number\n}\n\nexport type VercelAgentWorkflowRunResult =\n | {\n readonly _tag: 'Completed'\n readonly turns: number\n readonly state: SerializableWorkflowState\n }\n | {\n readonly _tag: 'ModelStepFailed'\n readonly turn: number\n readonly error: unknown\n readonly state: SerializableWorkflowState\n }\n | {\n readonly _tag: 'ToolBatchStepFailed'\n readonly turn: number\n readonly error: unknown\n readonly state: SerializableWorkflowState\n }\n | {\n readonly _tag: 'AwaitInputFailed'\n readonly turn: number\n readonly error: unknown\n readonly awaitingInput: VercelAgentWorkflowAwaitingInput\n readonly state: SerializableWorkflowState\n }\n | {\n readonly _tag: 'CloseStreamFailed'\n readonly turns: number\n readonly error: unknown\n readonly state: SerializableWorkflowState\n }\n | {\n readonly _tag: 'MaxTurnsExceeded'\n readonly maxTurns: number\n readonly error: Error\n readonly state: SerializableWorkflowState\n }\n\nexport type VercelAgentWorkflowLoopConfig = {\n readonly input: VercelAgentWorkflowInput\n readonly maxTurns?: number\n readonly runModelStep: (\n input: VercelAgentWorkflowModelStepInput\n ) => Promise<VercelAgentWorkflowModelStepResult>\n readonly runToolBatchStep: (\n input: VercelAgentWorkflowToolBatchStepInput\n ) => Promise<VercelAgentWorkflowToolBatchStepResult>\n readonly closeStream: () => Promise<void>\n readonly writeError: (error: unknown) => Promise<void>\n readonly awaitInput?: (input: VercelAgentWorkflowAwaitingInput) => Promise<unknown>\n readonly modelStepRetry?: VercelAgentWorkflowStepRetryPolicy\n readonly toolBatchStepRetry?: VercelAgentWorkflowStepRetryPolicy\n readonly awaitInputRetry?: VercelAgentWorkflowStepRetryPolicy\n readonly closeStreamRetry?: VercelAgentWorkflowStepRetryPolicy\n}\n\nexport const defaultMaxWorkflowTurns = 500\nexport const noWorkflowStepRetry: VercelAgentWorkflowStepRetryPolicy = { maxAttempts: 1 }\n\nexport const settleWorkflowStep = <A>(promise: Promise<A>): Promise<WorkflowStepResult<A>> =>\n promise.then(\n value => ({ _tag: 'Success', value }),\n error => ({ _tag: 'Failure', error })\n )\n\nconst workflowMaxTurnsError = (maxTurns: number) =>\n new Error(`Vercel agent workflow exceeded max turns: ${maxTurns}`)\n\nconst writeErrorSafely = (writeError: (error: unknown) => Promise<void>, error: unknown) =>\n writeError(error).catch(() => undefined)\n\nconst missingAwaitInputHandlerError = () =>\n new Error(\n 'Vercel agent workflow awaiting input requested but no awaitInput handler is configured'\n )\n\nconst maxRetryAttempts = (policy: VercelAgentWorkflowStepRetryPolicy | undefined) =>\n Math.max(1, Math.floor(policy?.maxAttempts ?? noWorkflowStepRetry.maxAttempts))\n\nexport async function retryWorkflowStep<A>(\n runStep: () => Promise<A>,\n policy?: VercelAgentWorkflowStepRetryPolicy\n): Promise<A> {\n const maxAttempts = maxRetryAttempts(policy)\n\n let attempt = 1\n\n for (;;) {\n try {\n return await runStep()\n } catch (error) {\n if (attempt >= maxAttempts) {\n throw error\n }\n\n attempt += 1\n }\n }\n}\n\nexport async function runVercelAgentWorkflow(\n config: VercelAgentWorkflowLoopConfig\n): Promise<VercelAgentWorkflowRunResult> {\n const {\n input,\n maxTurns: configuredMaxTurns,\n runModelStep,\n runToolBatchStep,\n closeStream,\n writeError,\n awaitInput,\n modelStepRetry,\n toolBatchStepRetry,\n awaitInputRetry,\n closeStreamRetry\n } = config\n let state: SerializableWorkflowState = {\n request: input.request,\n createdMessages: [],\n turn: 1,\n eventSequence: 0\n }\n const maxTurns = configuredMaxTurns ?? defaultMaxWorkflowTurns\n\n for (let step = 0; step < maxTurns; step++) {\n const modelResult = await settleWorkflowStep(\n retryWorkflowStep(() => runModelStep({ context: input.context, state }), modelStepRetry)\n )\n\n if (modelResult._tag === 'Failure') {\n await writeErrorSafely(writeError, modelResult.error)\n return {\n _tag: 'ModelStepFailed',\n turn: state.turn,\n error: modelResult.error,\n state\n }\n }\n\n if (modelResult.value.done) {\n const closeResult = await settleWorkflowStep(retryWorkflowStep(closeStream, closeStreamRetry))\n\n if (closeResult._tag === 'Failure') {\n await writeErrorSafely(writeError, closeResult.error)\n\n return {\n _tag: 'CloseStreamFailed',\n turns: modelResult.value.turn,\n error: closeResult.error,\n state\n }\n }\n\n return {\n _tag: 'Completed',\n turns: modelResult.value.turn,\n state\n }\n }\n\n let completedToolsResult: VercelAgentWorkflowToolBatchStepResult | undefined\n let toolHitlResponses: ReadonlyArray<unknown> = []\n let toolEventSequence = modelResult.value.eventSequence ?? state.eventSequence\n\n for (;;) {\n const toolsResult = await settleWorkflowStep(\n retryWorkflowStep(\n () =>\n runToolBatchStep({\n context: input.context,\n request: input.request,\n calls: modelResult.value.toolCalls,\n createdMessages: modelResult.value.createdMessages,\n hitlResponses: toolHitlResponses,\n usage: modelResult.value.usage,\n turn: modelResult.value.turn,\n eventSequence: toolEventSequence\n }),\n toolBatchStepRetry\n )\n )\n\n if (toolsResult._tag === 'Failure') {\n await writeErrorSafely(writeError, toolsResult.error)\n\n return {\n _tag: 'ToolBatchStepFailed',\n turn: modelResult.value.turn,\n error: toolsResult.error,\n state\n }\n }\n\n if (toolsResult.value.awaitingInput === undefined) {\n completedToolsResult = toolsResult.value\n break\n }\n\n const awaitingInput = toolsResult.value.awaitingInput\n toolEventSequence =\n awaitingInput.eventSequence ?? toolsResult.value.eventSequence ?? toolEventSequence\n\n const hitlResponse = await settleWorkflowStep(\n retryWorkflowStep(() => {\n if (awaitInput === undefined) {\n return Promise.reject(missingAwaitInputHandlerError())\n }\n\n return awaitInput(awaitingInput)\n }, awaitInputRetry)\n )\n\n if (hitlResponse._tag === 'Failure') {\n await writeErrorSafely(writeError, hitlResponse.error)\n\n return {\n _tag: 'AwaitInputFailed',\n turn: modelResult.value.turn,\n error: hitlResponse.error,\n awaitingInput,\n state\n }\n }\n\n toolHitlResponses = [...toolHitlResponses, hitlResponse.value]\n }\n\n if (completedToolsResult === undefined) {\n const error = new Error('Vercel agent workflow tool batch did not complete')\n await writeErrorSafely(writeError, error)\n\n return {\n _tag: 'ToolBatchStepFailed',\n turn: modelResult.value.turn,\n error,\n state\n }\n }\n\n state = {\n request: input.request,\n messages: [...modelResult.value.messages, ...completedToolsResult.messages],\n createdMessages: completedToolsResult.createdMessages,\n usage: modelResult.value.usage,\n turn: modelResult.value.turn + 1,\n eventSequence: completedToolsResult.eventSequence ?? toolEventSequence\n }\n }\n\n const error = workflowMaxTurnsError(maxTurns)\n await writeErrorSafely(writeError, error)\n\n return {\n _tag: 'MaxTurnsExceeded',\n maxTurns,\n error,\n state\n }\n}\n"],"mappings":";AA8HA,MAAa,0BAA0B;AACvC,MAAa,sBAA0D,EAAE,aAAa,EAAE;AAExF,MAAa,sBAAyB,YACpC,QAAQ,MACN,WAAU;CAAE,MAAM;CAAW;AAAM,KACnC,WAAU;CAAE,MAAM;CAAW;AAAM,EACrC;AAEF,MAAM,yBAAyB,6BAC7B,IAAI,MAAM,6CAA6C,UAAU;AAEnE,MAAM,oBAAoB,YAA+C,UACvE,WAAW,KAAK,EAAE,YAAY,KAAA,CAAS;AAEzC,MAAM,sDACJ,IAAI,MACF,wFACF;AAEF,MAAM,oBAAoB,WACxB,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,eAAe,oBAAoB,WAAW,CAAC;AAEhF,eAAsB,kBACpB,SACA,QACY;CACZ,MAAM,cAAc,iBAAiB,MAAM;CAE3C,IAAI,UAAU;CAEd,SACE,IAAI;EACF,OAAO,MAAM,QAAQ;CACvB,SAAS,OAAO;EACd,IAAI,WAAW,aACb,MAAM;EAGR,WAAW;CACb;AAEJ;AAEA,eAAsB,uBACpB,QACuC;CACvC,MAAM,EACJ,OACA,UAAU,oBACV,cACA,kBACA,aACA,YACA,YACA,gBACA,oBACA,iBACA,qBACE;CACJ,IAAI,QAAmC;EACrC,SAAS,MAAM;EACf,iBAAiB,CAAC;EAClB,MAAM;EACN,eAAe;CACjB;CACA,MAAM,WAAW,sBAAA;CAEjB,KAAK,IAAI,OAAO,GAAG,OAAO,UAAU,QAAQ;EAC1C,MAAM,cAAc,MAAM,mBACxB,wBAAwB,aAAa;GAAE,SAAS,MAAM;GAAS;EAAM,CAAC,GAAG,cAAc,CACzF;EAEA,IAAI,YAAY,SAAS,WAAW;GAClC,MAAM,iBAAiB,YAAY,YAAY,KAAK;GACpD,OAAO;IACL,MAAM;IACN,MAAM,MAAM;IACZ,OAAO,YAAY;IACnB;GACF;EACF;EAEA,IAAI,YAAY,MAAM,MAAM;GAC1B,MAAM,cAAc,MAAM,mBAAmB,kBAAkB,aAAa,gBAAgB,CAAC;GAE7F,IAAI,YAAY,SAAS,WAAW;IAClC,MAAM,iBAAiB,YAAY,YAAY,KAAK;IAEpD,OAAO;KACL,MAAM;KACN,OAAO,YAAY,MAAM;KACzB,OAAO,YAAY;KACnB;IACF;GACF;GAEA,OAAO;IACL,MAAM;IACN,OAAO,YAAY,MAAM;IACzB;GACF;EACF;EAEA,IAAI;EACJ,IAAI,oBAA4C,CAAC;EACjD,IAAI,oBAAoB,YAAY,MAAM,iBAAiB,MAAM;EAEjE,SAAS;GACP,MAAM,cAAc,MAAM,mBACxB,wBAEI,iBAAiB;IACf,SAAS,MAAM;IACf,SAAS,MAAM;IACf,OAAO,YAAY,MAAM;IACzB,iBAAiB,YAAY,MAAM;IACnC,eAAe;IACf,OAAO,YAAY,MAAM;IACzB,MAAM,YAAY,MAAM;IACxB,eAAe;GACjB,CAAC,GACH,kBACF,CACF;GAEA,IAAI,YAAY,SAAS,WAAW;IAClC,MAAM,iBAAiB,YAAY,YAAY,KAAK;IAEpD,OAAO;KACL,MAAM;KACN,MAAM,YAAY,MAAM;KACxB,OAAO,YAAY;KACnB;IACF;GACF;GAEA,IAAI,YAAY,MAAM,kBAAkB,KAAA,GAAW;IACjD,uBAAuB,YAAY;IACnC;GACF;GAEA,MAAM,gBAAgB,YAAY,MAAM;GACxC,oBACE,cAAc,iBAAiB,YAAY,MAAM,iBAAiB;GAEpE,MAAM,eAAe,MAAM,mBACzB,wBAAwB;IACtB,IAAI,eAAe,KAAA,GACjB,OAAO,QAAQ,OAAO,8BAA8B,CAAC;IAGvD,OAAO,WAAW,aAAa;GACjC,GAAG,eAAe,CACpB;GAEA,IAAI,aAAa,SAAS,WAAW;IACnC,MAAM,iBAAiB,YAAY,aAAa,KAAK;IAErD,OAAO;KACL,MAAM;KACN,MAAM,YAAY,MAAM;KACxB,OAAO,aAAa;KACpB;KACA;IACF;GACF;GAEA,oBAAoB,CAAC,GAAG,mBAAmB,aAAa,KAAK;EAC/D;EAEA,IAAI,yBAAyB,KAAA,GAAW;GACtC,MAAM,wBAAQ,IAAI,MAAM,mDAAmD;GAC3E,MAAM,iBAAiB,YAAY,KAAK;GAExC,OAAO;IACL,MAAM;IACN,MAAM,YAAY,MAAM;IACxB;IACA;GACF;EACF;EAEA,QAAQ;GACN,SAAS,MAAM;GACf,UAAU,CAAC,GAAG,YAAY,MAAM,UAAU,GAAG,qBAAqB,QAAQ;GAC1E,iBAAiB,qBAAqB;GACtC,OAAO,YAAY,MAAM;GACzB,MAAM,YAAY,MAAM,OAAO;GAC/B,eAAe,qBAAqB,iBAAiB;EACvD;CACF;CAEA,MAAM,QAAQ,sBAAsB,QAAQ;CAC5C,MAAM,iBAAiB,YAAY,KAAK;CAExC,OAAO;EACL,MAAM;EACN;EACA;EACA;CACF;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yolk-sdk/vercel-workflows",
3
- "version": "0.1.0-canary.38",
3
+ "version": "0.1.0-canary.40",
4
4
  "description": "Vercel Workflow orchestration primitives for Yolk agent loops.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/effect.ts CHANGED
@@ -48,7 +48,7 @@ export type VercelWorkflowsSdkClient = {
48
48
  args: TArgs
49
49
  ) => Promise<VercelWorkflowsSdkRun<TResult>>
50
50
  readonly getRun: <TResult>(runId: string) => VercelWorkflowsSdkRun<TResult>
51
- readonly resumeHook: (token: string, payload: unknown) => Promise<unknown>
51
+ readonly resumeHook: (token: string, payload: unknown) => Promise<void>
52
52
  }
53
53
 
54
54
  export type VercelWorkflowRun<TResult> = {
@@ -95,6 +95,16 @@ const workflowsError = (operation: VercelWorkflowsOperation, cause: unknown) =>
95
95
 
96
96
  const spanAttributes = (runId: string) => ({ 'workflow.run.id': runId })
97
97
 
98
+ const trySdkPromise = <A>(body: () => Promise<A>) =>
99
+ Effect.tryPromise({
100
+ try: body,
101
+ catch: error => error
102
+ })
103
+
104
+ const mapSdkError = (operation: VercelWorkflowsOperation) =>
105
+ <A>(effect: Effect.Effect<A, unknown>) =>
106
+ effect.pipe(Effect.mapError(cause => workflowsError(operation, cause)))
107
+
98
108
  const makeWorkflowRun = <TResult>(
99
109
  run: VercelWorkflowsSdkRun<TResult>
100
110
  ): VercelWorkflowRun<TResult> => ({
@@ -108,26 +118,20 @@ const makeWorkflowRun = <TResult>(
108
118
  attributes: spanAttributes(run.runId)
109
119
  })
110
120
  ),
111
- cancel: Effect.tryPromise({
112
- try: () => run.cancel(),
113
- catch: cause => workflowsError('cancel', cause)
114
- }).pipe(
121
+ cancel: trySdkPromise(() => run.cancel()).pipe(
122
+ mapSdkError('cancel'),
115
123
  Effect.withSpan('VercelWorkflows.run.cancel', {
116
124
  attributes: spanAttributes(run.runId)
117
125
  })
118
126
  ),
119
- status: Effect.tryPromise({
120
- try: () => run.status,
121
- catch: cause => workflowsError('status', cause)
122
- }).pipe(
127
+ status: trySdkPromise(() => run.status).pipe(
128
+ mapSdkError('status'),
123
129
  Effect.withSpan('VercelWorkflows.run.status', {
124
130
  attributes: spanAttributes(run.runId)
125
131
  })
126
132
  ),
127
- returnValue: Effect.tryPromise({
128
- try: () => run.returnValue,
129
- catch: cause => workflowsError('returnValue', cause)
130
- }).pipe(
133
+ returnValue: trySdkPromise(() => run.returnValue).pipe(
134
+ mapSdkError('returnValue'),
131
135
  Effect.withSpan('VercelWorkflows.run.returnValue', {
132
136
  attributes: spanAttributes(run.runId)
133
137
  })
@@ -140,7 +144,9 @@ const VercelWorkflowsSdkLive = Layer.succeed(VercelWorkflowsSdk, {
140
144
  args: TArgs
141
145
  ) => workflowStart(workflow, args),
142
146
  getRun: <TResult>(runId: string) => workflowGetRun<TResult>(runId),
143
- resumeHook: (token: string, payload: unknown) => workflowResumeHook<unknown>(token, payload)
147
+ resumeHook: async (token: string, payload: unknown) => {
148
+ await workflowResumeHook<unknown>(token, payload)
149
+ }
144
150
  })
145
151
 
146
152
  export class VercelWorkflows extends Context.Service<VercelWorkflows, VercelWorkflowsClient>()(
@@ -153,9 +159,11 @@ export class VercelWorkflows extends Context.Service<VercelWorkflows, VercelWork
153
159
  runId: string
154
160
  ): Effect.Effect<VercelWorkflowRun<TResult>, VercelWorkflowsError> =>
155
161
  Effect.try({
156
- try: () => makeWorkflowRun(sdk.getRun<TResult>(runId)),
157
- catch: cause => workflowsError('getRun', cause)
162
+ try: () => sdk.getRun<TResult>(runId),
163
+ catch: error => error
158
164
  }).pipe(
165
+ mapSdkError('getRun'),
166
+ Effect.map(makeWorkflowRun),
159
167
  Effect.withSpan('VercelWorkflows.getRun', {
160
168
  attributes: spanAttributes(runId)
161
169
  })
@@ -166,10 +174,11 @@ export class VercelWorkflows extends Context.Service<VercelWorkflows, VercelWork
166
174
  workflow: VercelWorkflowFunction<TArgs, TResult>,
167
175
  args: TArgs
168
176
  ): Effect.Effect<VercelWorkflowRun<TResult>, VercelWorkflowsError> =>
169
- Effect.tryPromise({
170
- try: () => sdk.start(workflow, args),
171
- catch: cause => workflowsError('start', cause)
172
- }).pipe(Effect.map(makeWorkflowRun), Effect.withSpan('VercelWorkflows.start')),
177
+ trySdkPromise(() => sdk.start(workflow, args)).pipe(
178
+ mapSdkError('start'),
179
+ Effect.map(makeWorkflowRun),
180
+ Effect.withSpan('VercelWorkflows.start')
181
+ ),
173
182
 
174
183
  getRun,
175
184
 
@@ -199,10 +208,10 @@ export class VercelWorkflows extends Context.Service<VercelWorkflows, VercelWork
199
208
  ),
200
209
 
201
210
  resumeHook: (token: string, payload: unknown): Effect.Effect<void, VercelWorkflowsError> =>
202
- Effect.tryPromise({
203
- try: () => sdk.resumeHook(token, payload).then(() => undefined),
204
- catch: cause => workflowsError('resumeHook', cause)
205
- }).pipe(Effect.withSpan('VercelWorkflows.resumeHook')),
211
+ trySdkPromise(() => sdk.resumeHook(token, payload)).pipe(
212
+ mapSdkError('resumeHook'),
213
+ Effect.withSpan('VercelWorkflows.resumeHook')
214
+ ),
206
215
 
207
216
  cancel: (runId: string): Effect.Effect<void, VercelWorkflowsError> =>
208
217
  getRun<unknown>(runId).pipe(
@@ -1,3 +1,5 @@
1
+ import { Effect } from 'effect'
2
+
1
3
  export type DurableAgentEventSequencerState = {
2
4
  readonly eventSequence: number
3
5
  }
@@ -15,6 +17,13 @@ export type DurableAgentEventIdInput = {
15
17
 
16
18
  export type SequenceDurableAgentEventInput<Event extends object = object> = {
17
19
  readonly state: DurableAgentEventSequencerState
20
+ /**
21
+ * Stable id namespace for one independent durable stream.
22
+ *
23
+ * Include the workflow/session/run id when multiple logical runs can be
24
+ * projected in the same client. Replay-safe clients de-dupe by `eventId`, so
25
+ * reusing a stream id across runs can drop legitimate follow-up events.
26
+ */
18
27
  readonly streamId: string
19
28
  readonly turn: number
20
29
  readonly event: Event
@@ -40,13 +49,19 @@ export type TerminalEventCloseResult =
40
49
  export type CommitThenWriteTerminalEventInput<
41
50
  TerminalEvent extends object,
42
51
  TerminalWriteResult,
43
- CommitErrorWriteResult
52
+ CommitErrorWriteResult,
53
+ CommitError,
54
+ TerminalWriteError,
55
+ CommitErrorWriteError,
56
+ CloseError
44
57
  > = {
45
- readonly commit: () => Promise<void>
58
+ readonly commit: Effect.Effect<void, CommitError>
46
59
  readonly terminal: TerminalEvent
47
- readonly write: (event: TerminalEvent) => Promise<TerminalWriteResult>
48
- readonly writeCommitError: (error: unknown) => Promise<CommitErrorWriteResult>
49
- readonly close: () => Promise<void>
60
+ readonly write: (event: TerminalEvent) => Effect.Effect<TerminalWriteResult, TerminalWriteError>
61
+ readonly writeCommitError: (
62
+ error: unknown
63
+ ) => Effect.Effect<CommitErrorWriteResult, CommitErrorWriteError>
64
+ readonly close: Effect.Effect<void, CloseError>
50
65
  }
51
66
 
52
67
  export type CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult> =
@@ -108,61 +123,147 @@ export const sequenceDurableAgentEvent = <Event extends object>(
108
123
  const encodeDurableAgentEventNdjson = <Event extends object>(event: DurableAgentEvent<Event>) =>
109
124
  textEncoder.encode(`${JSON.stringify(event)}\n`)
110
125
 
111
- export const writeDurableAgentEvent = async <Event extends object>(
126
+ export const writeDurableAgentEvent = <Event extends object>(
112
127
  input: WriteDurableAgentEventInput<Event>
113
- ): Promise<SequencedDurableAgentEvent<Event>> => {
114
- const sequenced = sequenceDurableAgentEvent(input)
115
- await input.writer.write(encodeDurableAgentEventNdjson(sequenced.event))
128
+ ): Effect.Effect<SequencedDurableAgentEvent<Event>, unknown> =>
129
+ Effect.gen(function* () {
130
+ const sequenced = sequenceDurableAgentEvent(input)
131
+ yield* Effect.tryPromise({
132
+ try: () => input.writer.write(encodeDurableAgentEventNdjson(sequenced.event)),
133
+ catch: cause => cause
134
+ })
116
135
 
117
- return sequenced
118
- }
136
+ return sequenced
137
+ })
119
138
 
120
- const closeTerminalEventWriter = async (
121
- close: () => Promise<void>
122
- ): Promise<TerminalEventCloseResult> => {
123
- try {
124
- await close()
139
+ const closedTerminalEventWriterResult = (): TerminalEventCloseResult => ({ _tag: 'Closed' })
125
140
 
126
- return { _tag: 'Closed' }
127
- } catch (error) {
128
- return { _tag: 'CloseFailed', error }
129
- }
130
- }
141
+ const closeFailedTerminalEventWriterResult = (error: unknown): TerminalEventCloseResult => ({
142
+ _tag: 'CloseFailed',
143
+ error
144
+ })
145
+
146
+ const committedTerminalResult = <TerminalWriteResult, CommitErrorWriteResult>(
147
+ writeResult: TerminalWriteResult,
148
+ closeResult: TerminalEventCloseResult
149
+ ): CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult> => ({
150
+ _tag: 'Committed',
151
+ writeResult,
152
+ closeResult
153
+ })
154
+
155
+ const commitFailedTerminalResult = <TerminalWriteResult, CommitErrorWriteResult>(
156
+ commitError: unknown,
157
+ writeResult: CommitErrorWriteResult,
158
+ closeResult: TerminalEventCloseResult
159
+ ): CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult> => ({
160
+ _tag: 'CommitFailed',
161
+ commitError,
162
+ writeResult,
163
+ closeResult
164
+ })
165
+
166
+ const terminalWriteFailedResult = <TerminalWriteResult, CommitErrorWriteResult>(
167
+ error: unknown,
168
+ closeResult: TerminalEventCloseResult
169
+ ): CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult> => ({
170
+ _tag: 'TerminalWriteFailed',
171
+ error,
172
+ closeResult
173
+ })
174
+
175
+ const commitErrorWriteFailedResult = <TerminalWriteResult, CommitErrorWriteResult>(
176
+ commitError: unknown,
177
+ error: unknown,
178
+ closeResult: TerminalEventCloseResult
179
+ ): CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult> => ({
180
+ _tag: 'CommitErrorWriteFailed',
181
+ commitError,
182
+ error,
183
+ closeResult
184
+ })
131
185
 
132
- export const commitThenWriteTerminalEvent = async <
186
+ const closeTerminalEventWriterEffect = <CloseError>(
187
+ close: Effect.Effect<void, CloseError>
188
+ ): Effect.Effect<TerminalEventCloseResult, never> =>
189
+ close.pipe(
190
+ Effect.match({
191
+ onFailure: closeFailedTerminalEventWriterResult,
192
+ onSuccess: () => closedTerminalEventWriterResult()
193
+ })
194
+ )
195
+
196
+ export const commitThenWriteTerminalEvent = <
133
197
  TerminalEvent extends object,
134
198
  TerminalWriteResult,
135
- CommitErrorWriteResult
199
+ CommitErrorWriteResult,
200
+ CommitError,
201
+ TerminalWriteError,
202
+ CommitErrorWriteError,
203
+ CloseError
136
204
  >(
137
205
  input: CommitThenWriteTerminalEventInput<
138
206
  TerminalEvent,
139
207
  TerminalWriteResult,
140
- CommitErrorWriteResult
208
+ CommitErrorWriteResult,
209
+ CommitError,
210
+ TerminalWriteError,
211
+ CommitErrorWriteError,
212
+ CloseError
141
213
  >
142
- ): Promise<CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult>> => {
143
- try {
144
- await input.commit()
145
- } catch (commitError) {
146
- try {
147
- const writeResult = await input.writeCommitError(commitError)
148
- const closeResult = await closeTerminalEventWriter(input.close)
149
-
150
- return { _tag: 'CommitFailed', commitError, writeResult, closeResult }
151
- } catch (error) {
152
- const closeResult = await closeTerminalEventWriter(input.close)
153
-
154
- return { _tag: 'CommitErrorWriteFailed', commitError, error, closeResult }
155
- }
156
- }
157
-
158
- try {
159
- const writeResult = await input.write(input.terminal)
160
- const closeResult = await closeTerminalEventWriter(input.close)
161
-
162
- return { _tag: 'Committed', writeResult, closeResult }
163
- } catch (error) {
164
- const closeResult = await closeTerminalEventWriter(input.close)
165
-
166
- return { _tag: 'TerminalWriteFailed', error, closeResult }
167
- }
168
- }
214
+ ): Effect.Effect<
215
+ CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult>,
216
+ never
217
+ > =>
218
+ input.commit.pipe(
219
+ Effect.matchEffect({
220
+ onFailure: commitError =>
221
+ input.writeCommitError(commitError).pipe(
222
+ Effect.matchEffect({
223
+ onFailure: error =>
224
+ closeTerminalEventWriterEffect(input.close).pipe(
225
+ Effect.map(closeResult =>
226
+ commitErrorWriteFailedResult<TerminalWriteResult, CommitErrorWriteResult>(
227
+ commitError,
228
+ error,
229
+ closeResult
230
+ )
231
+ )
232
+ ),
233
+ onSuccess: writeResult =>
234
+ closeTerminalEventWriterEffect(input.close).pipe(
235
+ Effect.map(closeResult =>
236
+ commitFailedTerminalResult<TerminalWriteResult, CommitErrorWriteResult>(
237
+ commitError,
238
+ writeResult,
239
+ closeResult
240
+ )
241
+ )
242
+ )
243
+ })
244
+ ),
245
+ onSuccess: () =>
246
+ input.write(input.terminal).pipe(
247
+ Effect.matchEffect({
248
+ onFailure: error =>
249
+ closeTerminalEventWriterEffect(input.close).pipe(
250
+ Effect.map(closeResult =>
251
+ terminalWriteFailedResult<TerminalWriteResult, CommitErrorWriteResult>(
252
+ error,
253
+ closeResult
254
+ )
255
+ )
256
+ ),
257
+ onSuccess: writeResult =>
258
+ closeTerminalEventWriterEffect(input.close).pipe(
259
+ Effect.map(closeResult =>
260
+ committedTerminalResult<TerminalWriteResult, CommitErrorWriteResult>(
261
+ writeResult,
262
+ closeResult
263
+ )
264
+ )
265
+ )
266
+ })
267
+ )
268
+ })
269
+ )
@@ -152,6 +152,7 @@ export async function retryWorkflowStep<A>(
152
152
  policy?: VercelAgentWorkflowStepRetryPolicy
153
153
  ): Promise<A> {
154
154
  const maxAttempts = maxRetryAttempts(policy)
155
+
155
156
  let attempt = 1
156
157
 
157
158
  for (;;) {