@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 +32 -21
- package/dist/effect.d.mts +1 -1
- package/dist/effect.d.mts.map +1 -1
- package/dist/effect.mjs +16 -24
- package/dist/effect.mjs.map +1 -1
- package/dist/workflow-events.d.mts +16 -7
- package/dist/workflow-events.d.mts.map +1 -1
- package/dist/workflow-events.mjs +48 -48
- package/dist/workflow-events.mjs.map +1 -1
- package/dist/workflow-loop.d.mts.map +1 -1
- package/dist/workflow-loop.mjs.map +1 -1
- package/package.json +1 -1
- package/src/effect.ts +33 -24
- package/src/workflow-events.ts +152 -51
- package/src/workflow-loop.ts +1 -0
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
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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 =
|
|
132
|
+
const sequenced = yield* writeDurableAgentEvent({
|
|
126
133
|
writer,
|
|
127
134
|
event,
|
|
128
|
-
streamId:
|
|
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}`.
|
|
137
|
-
|
|
138
|
-
|
|
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 =
|
|
167
|
+
const result = yield* commitThenWriteTerminalEvent({
|
|
158
168
|
terminal,
|
|
159
|
-
commit:
|
|
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
|
|
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<
|
|
28
|
+
readonly resumeHook: (token: string, payload: unknown) => Promise<void>;
|
|
29
29
|
};
|
|
30
30
|
type VercelWorkflowRun<TResult> = {
|
|
31
31
|
readonly runId: string;
|
package/dist/effect.d.mts.map
CHANGED
|
@@ -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;;;
|
|
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.
|
|
19
|
-
|
|
20
|
-
|
|
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) =>
|
|
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: () =>
|
|
40
|
-
catch: (
|
|
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.
|
|
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.
|
|
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
|
}) }) {
|
package/dist/effect.mjs.map
CHANGED
|
@@ -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":";;;AAoBA,IAAa,uBAAb,cAA0C,KAAK,YAAY,sBAAsB,EAI9E,CAAC;AA2DJ,IAAa,qBAAb,cAAwC,QAAQ,QAG9C,EAAE,+CAA+C,EAAE,CAAC;AAEtD,MAAM,kBAAkB,WAAqC,UAC3D,IAAI,qBAAqB;CACvB;CACA,SAAS,mBAAmB,UAAU;CACtC;AACF,CAAC;AAEH,MAAM,kBAAkB,WAAmB,EAAE,mBAAmB,MAAM;AAEtE,MAAM,iBAAoB,SACxB,OAAO,WAAW;CAChB,KAAK;CACL,QAAO,UAAS;AAClB,CAAC;AAEH,MAAM,eAAe,eACf,WACF,OAAO,KAAK,OAAO,UAAS,UAAS,eAAe,WAAW,KAAK,CAAC,CAAC;AAE1E,MAAM,mBACJ,SACgC;CAChC,OAAO,IAAI;CACX,cAAqB,YACnB,OAAO,IAAI;EACT,WAAW,IAAI,YAAmB,OAAO;EACzC,QAAO,UAAS,eAAe,eAAe,KAAK;CACrD,CAAC,EAAE,KACD,OAAO,SAAS,mCAAmC,EACjD,YAAY,eAAe,IAAI,KAAK,EACtC,CAAC,CACH;CACF,QAAQ,oBAAoB,IAAI,OAAO,CAAC,EAAE,KACxC,YAAY,QAAQ,GACpB,OAAO,SAAS,8BAA8B,EAC5C,YAAY,eAAe,IAAI,KAAK,EACtC,CAAC,CACH;CACA,QAAQ,oBAAoB,IAAI,MAAM,EAAE,KACtC,YAAY,QAAQ,GACpB,OAAO,SAAS,8BAA8B,EAC5C,YAAY,eAAe,IAAI,KAAK,EACtC,CAAC,CACH;CACA,aAAa,oBAAoB,IAAI,WAAW,EAAE,KAChD,YAAY,aAAa,GACzB,OAAO,SAAS,mCAAmC,EACjD,YAAY,eAAe,IAAI,KAAK,EACtC,CAAC,CACH;AACF;AAEA,MAAM,yBAAyB,MAAM,QAAQ,oBAAoB;CAC/D,QACE,UACA,SACGA,MAAc,UAAU,IAAI;CACjC,SAAkB,UAAkBC,OAAwB,KAAK;CACjE,YAAY,OAAO,OAAe,YAAqB;EACrD,MAAMC,WAA4B,OAAO,OAAO;CAClD;AACF,CAAC;AAED,IAAa,kBAAb,cAAqC,QAAQ,QAAgD,EAC3F,8CACA,EACE,MAAM,OAAO,IAAI,aAAa;CAC5B,MAAM,MAAM,OAAO;CAEnB,MAAM,UACJ,UAEA,OAAO,IAAI;EACT,WAAW,IAAI,OAAgB,KAAK;EACpC,QAAO,UAAS;CAClB,CAAC,EAAE,KACD,YAAY,QAAQ,GACpB,OAAO,IAAI,eAAe,GAC1B,OAAO,SAAS,0BAA0B,EACxC,YAAY,eAAe,KAAK,EAClC,CAAC,CACH;CAEF,OAAO;EACL,QACE,UACA,SAEA,oBAAoB,IAAI,MAAM,UAAU,IAAI,CAAC,EAAE,KAC7C,YAAY,OAAO,GACnB,OAAO,IAAI,eAAe,GAC1B,OAAO,SAAS,uBAAuB,CACzC;EAEF;EAEA,cACE,OACA,YAEA,OAAgB,KAAK,EAAE,KACrB,OAAO,SAAQ,QAAO,IAAI,YAAmB,OAAO,CAAC,GACrD,OAAO,SAAS,+BAA+B,EAC7C,YAAY,eAAe,KAAK,EAClC,CAAC,CACH;EAEF,YAAY,UACV,OAAgB,KAAK,EAAE,KACrB,OAAO,SAAQ,QAAO,IAAI,YAAqB,EAAE,YAAY,GAAG,CAAC,CAAC,GAClE,OAAO,SAAQ,aACb,OAAO,WAAW;GAChB,WAAW,SAAS,aAAa;GACjC,QAAO,UAAS,eAAe,aAAa,KAAK;EACnD,CAAC,CACH,GACA,OAAO,SAAS,6BAA6B,EAC3C,YAAY,eAAe,KAAK,EAClC,CAAC,CACH;EAEF,aAAa,OAAe,YAC1B,oBAAoB,IAAI,WAAW,OAAO,OAAO,CAAC,EAAE,KAClD,YAAY,YAAY,GACxB,OAAO,SAAS,4BAA4B,CAC9C;EAEF,SAAS,UACP,OAAgB,KAAK,EAAE,KACrB,OAAO,SAAQ,QAAO,IAAI,MAAM,GAChC,OAAO,SAAS,0BAA0B,EACxC,YAAY,eAAe,KAAK,EAClC,CAAC,CACH;CACJ;AACF,CAAC,EACH,CACF,EAAE;CACA,OAAO,QAAQ,MAAM,OAAO,MAAM,KAAK,IAAI,EAAE,KAAK,MAAM,QAAQ,sBAAsB,CAAC;CACvF,OAAO,eAAe,MAAM,OAAO,MAAM,KAAK,IAAI;AACpD"}
|
|
@@ -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:
|
|
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) =>
|
|
40
|
-
readonly writeCommitError: (error: unknown) =>
|
|
41
|
-
readonly close:
|
|
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>) =>
|
|
66
|
-
declare const commitThenWriteTerminalEvent: <TerminalEvent extends object, TerminalWriteResult, CommitErrorWriteResult>(input: CommitThenWriteTerminalEventInput<TerminalEvent, 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":"
|
|
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"}
|
package/dist/workflow-events.mjs
CHANGED
|
@@ -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 =
|
|
25
|
+
const writeDurableAgentEvent = (input) => Effect.gen(function* () {
|
|
25
26
|
const sequenced = sequenceDurableAgentEvent(input);
|
|
26
|
-
|
|
27
|
+
yield* Effect.tryPromise({
|
|
28
|
+
try: () => input.writer.write(encodeDurableAgentEventNdjson(sequenced.event)),
|
|
29
|
+
catch: (cause) => cause
|
|
30
|
+
});
|
|
27
31
|
return sequenced;
|
|
28
|
-
};
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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":"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"}
|
package/package.json
CHANGED
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<
|
|
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:
|
|
112
|
-
|
|
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:
|
|
120
|
-
|
|
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:
|
|
128
|
-
|
|
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) =>
|
|
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: () =>
|
|
157
|
-
catch:
|
|
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
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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(
|
package/src/workflow-events.ts
CHANGED
|
@@ -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:
|
|
58
|
+
readonly commit: Effect.Effect<void, CommitError>
|
|
46
59
|
readonly terminal: TerminalEvent
|
|
47
|
-
readonly write: (event: TerminalEvent) =>
|
|
48
|
-
readonly writeCommitError: (
|
|
49
|
-
|
|
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 =
|
|
126
|
+
export const writeDurableAgentEvent = <Event extends object>(
|
|
112
127
|
input: WriteDurableAgentEventInput<Event>
|
|
113
|
-
):
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
|
|
118
|
-
}
|
|
136
|
+
return sequenced
|
|
137
|
+
})
|
|
119
138
|
|
|
120
|
-
const
|
|
121
|
-
close: () => Promise<void>
|
|
122
|
-
): Promise<TerminalEventCloseResult> => {
|
|
123
|
-
try {
|
|
124
|
-
await close()
|
|
139
|
+
const closedTerminalEventWriterResult = (): TerminalEventCloseResult => ({ _tag: 'Closed' })
|
|
125
140
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
-
|
|
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
|
-
):
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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
|
+
)
|