@yolk-sdk/vercel-workflows-runtime 0.0.1-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Yolk SDK contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # @yolk-sdk/vercel-workflows-runtime
2
+
3
+ Vercel Workflow-specific contracts for durable agent model/tool step loops.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pnpm add @yolk-sdk/vercel-workflows-runtime@canary @yolk-sdk/agent@canary effect workflow
9
+ ```
10
+
11
+ Canary APIs are unstable. Keep all `@yolk-sdk/*` packages on the same version.
12
+
13
+ ## Subpaths
14
+
15
+ | Subpath | Purpose |
16
+ | --- | --- |
17
+ | `@yolk-sdk/vercel-workflows-runtime` | Empty root export; reserved package entry |
18
+ | `@yolk-sdk/vercel-workflows-runtime/workflow` | Workflow-safe agent loop orchestration APIs |
19
+
20
+ ## Imports
21
+
22
+ The root export is intentionally empty. Import Workflow APIs from `./workflow`:
23
+
24
+ ```ts
25
+ import {
26
+ noWorkflowStepRetry,
27
+ runVercelAgentWorkflow
28
+ } from '@yolk-sdk/vercel-workflows-runtime/workflow'
29
+ ```
30
+
31
+ ## Runtime model
32
+
33
+ `runVercelAgentWorkflow` coordinates host-provided callbacks:
34
+
35
+ - model step: produce model events/tool calls
36
+ - tool batch step: execute requested tools
37
+ - awaiting-input state: carry pending HITL hook data between steps
38
+ - close step: flush/close output stream
39
+ - terminal status: completed, step failure, close failure, or max turns exceeded
40
+
41
+ Continuation state stays plain serializable data for Workflow persistence.
42
+
43
+ ## Retry policy
44
+
45
+ Default retry policy is `noWorkflowStepRetry` (`maxAttempts: 1`). Retries are opt-in because streamed retries can duplicate chunks unless host/client de-dupe is ready.
46
+
47
+ ## Host responsibilities
48
+
49
+ - Own Next/Vercel routes, auth, providers, tools, persistence, and telemetry.
50
+ - Encode/decode app transcript/session state into serializable Workflow inputs.
51
+ - Decide cancellation/resume/conflict UX.
52
+ - Own hook tokens and response validation for HITL resume.
53
+ - Test directive behavior with `@workflow/vitest` when changing package-owned Workflow files.
54
+
55
+ ## Boundaries
56
+
57
+ - No Next routes, server actions, auth, app tools, DB, UI, or provider SDKs.
58
+ - Effect may run inside host/package step callbacks; workflow orchestration keeps plain data contracts.
@@ -0,0 +1 @@
1
+ export { };
package/dist/index.mjs ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,104 @@
1
+ //#region src/workflow-loop.d.ts
2
+ type VercelAgentWorkflowInput = {
3
+ readonly request: unknown;
4
+ readonly context: unknown;
5
+ };
6
+ type SerializableWorkflowState = {
7
+ readonly request: unknown;
8
+ readonly messages?: ReadonlyArray<unknown>;
9
+ readonly createdMessages: ReadonlyArray<unknown>;
10
+ readonly usage?: unknown;
11
+ readonly turn: number;
12
+ readonly eventSequence?: number;
13
+ };
14
+ type VercelAgentWorkflowModelStepInput = {
15
+ readonly context: unknown;
16
+ readonly state: SerializableWorkflowState;
17
+ };
18
+ type VercelAgentWorkflowModelStepResult = {
19
+ readonly done: boolean;
20
+ readonly messages: ReadonlyArray<unknown>;
21
+ readonly createdMessages: ReadonlyArray<unknown>;
22
+ readonly toolCalls: ReadonlyArray<unknown>;
23
+ readonly usage: unknown;
24
+ readonly turn: number;
25
+ readonly eventSequence?: number;
26
+ };
27
+ type VercelAgentWorkflowToolBatchStepInput = {
28
+ readonly context: unknown;
29
+ readonly request: unknown;
30
+ readonly calls: ReadonlyArray<unknown>;
31
+ readonly createdMessages: ReadonlyArray<unknown>;
32
+ readonly hitlResponses?: ReadonlyArray<unknown>;
33
+ readonly usage?: unknown;
34
+ readonly turn?: number;
35
+ readonly eventSequence?: number;
36
+ };
37
+ type VercelAgentWorkflowAwaitingInput = {
38
+ readonly hookToken: string;
39
+ readonly requests: ReadonlyArray<unknown>;
40
+ readonly messages: ReadonlyArray<unknown>;
41
+ readonly usage: unknown;
42
+ readonly turns: number;
43
+ readonly eventSequence?: number;
44
+ };
45
+ type VercelAgentWorkflowToolBatchStepResult = {
46
+ readonly messages: ReadonlyArray<unknown>;
47
+ readonly createdMessages: ReadonlyArray<unknown>;
48
+ readonly awaitingInput?: VercelAgentWorkflowAwaitingInput;
49
+ readonly eventSequence?: number;
50
+ };
51
+ type WorkflowStepResult<A> = {
52
+ readonly _tag: 'Success';
53
+ readonly value: A;
54
+ } | {
55
+ readonly _tag: 'Failure';
56
+ readonly error: unknown;
57
+ };
58
+ type VercelAgentWorkflowStepRetryPolicy = {
59
+ readonly maxAttempts: number;
60
+ };
61
+ type VercelAgentWorkflowRunResult = {
62
+ readonly _tag: 'Completed';
63
+ readonly turns: number;
64
+ readonly state: SerializableWorkflowState;
65
+ } | {
66
+ readonly _tag: 'ModelStepFailed';
67
+ readonly turn: number;
68
+ readonly error: unknown;
69
+ readonly state: SerializableWorkflowState;
70
+ } | {
71
+ readonly _tag: 'ToolBatchStepFailed';
72
+ readonly turn: number;
73
+ readonly error: unknown;
74
+ readonly state: SerializableWorkflowState;
75
+ } | {
76
+ readonly _tag: 'CloseStreamFailed';
77
+ readonly turns: number;
78
+ readonly error: unknown;
79
+ readonly state: SerializableWorkflowState;
80
+ } | {
81
+ readonly _tag: 'MaxTurnsExceeded';
82
+ readonly maxTurns: number;
83
+ readonly error: Error;
84
+ readonly state: SerializableWorkflowState;
85
+ };
86
+ type VercelAgentWorkflowLoopConfig = {
87
+ readonly input: VercelAgentWorkflowInput;
88
+ readonly maxTurns?: number;
89
+ readonly runModelStep: (input: VercelAgentWorkflowModelStepInput) => Promise<VercelAgentWorkflowModelStepResult>;
90
+ readonly runToolBatchStep: (input: VercelAgentWorkflowToolBatchStepInput) => Promise<VercelAgentWorkflowToolBatchStepResult>;
91
+ readonly closeStream: () => Promise<void>;
92
+ readonly writeError: (error: unknown) => Promise<void>;
93
+ readonly modelStepRetry?: VercelAgentWorkflowStepRetryPolicy;
94
+ readonly toolBatchStepRetry?: VercelAgentWorkflowStepRetryPolicy;
95
+ readonly closeStreamRetry?: VercelAgentWorkflowStepRetryPolicy;
96
+ };
97
+ declare const defaultMaxWorkflowTurns = 500;
98
+ declare const noWorkflowStepRetry: VercelAgentWorkflowStepRetryPolicy;
99
+ declare const settleWorkflowStep: <A>(promise: Promise<A>) => Promise<WorkflowStepResult<A>>;
100
+ declare function retryWorkflowStep<A>(runStep: () => Promise<A>, policy?: VercelAgentWorkflowStepRetryPolicy): Promise<A>;
101
+ declare function runVercelAgentWorkflow(config: VercelAgentWorkflowLoopConfig): Promise<VercelAgentWorkflowRunResult>;
102
+ //#endregion
103
+ export { SerializableWorkflowState, VercelAgentWorkflowAwaitingInput, VercelAgentWorkflowInput, VercelAgentWorkflowLoopConfig, VercelAgentWorkflowModelStepInput, VercelAgentWorkflowModelStepResult, VercelAgentWorkflowRunResult, VercelAgentWorkflowStepRetryPolicy, VercelAgentWorkflowToolBatchStepInput, VercelAgentWorkflowToolBatchStepResult, WorkflowStepResult, defaultMaxWorkflowTurns, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, settleWorkflowStep };
104
+ //# sourceMappingURL=workflow-loop.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-loop.d.mts","names":[],"sources":["../src/workflow-loop.ts"],"mappings":";KAAY,wBAAA;EAAA,SACD,OAAA;EAAA,SACA,OAAO;AAAA;AAAA,KAGN,yBAAA;EAAA,SACD,OAAA;EAAA,SACA,QAAA,GAAW,aAAA;EAAA,SACX,eAAA,EAAiB,aAAa;EAAA,SAC9B,KAAA;EAAA,SACA,IAAA;EAAA,SACA,aAAA;AAAA;AAAA,KAGC,iCAAA;EAAA,SACD,OAAA;EAAA,SACA,KAAA,EAAO,yBAAyB;AAAA;AAAA,KAG/B,kCAAA;EAAA,SACD,IAAA;EAAA,SACA,QAAA,EAAU,aAAA;EAAA,SACV,eAAA,EAAiB,aAAA;EAAA,SACjB,SAAA,EAAW,aAAA;EAAA,SACX,KAAA;EAAA,SACA,IAAA;EAAA,SACA,aAAA;AAAA;AAAA,KAGC,qCAAA;EAAA,SACD,OAAA;EAAA,SACA,OAAA;EAAA,SACA,KAAA,EAAO,aAAA;EAAA,SACP,eAAA,EAAiB,aAAA;EAAA,SACjB,aAAA,GAAgB,aAAA;EAAA,SAChB,KAAA;EAAA,SACA,IAAA;EAAA,SACA,aAAA;AAAA;AAAA,KAGC,gCAAA;EAAA,SACD,SAAA;EAAA,SACA,QAAA,EAAU,aAAA;EAAA,SACV,QAAA,EAAU,aAAa;EAAA,SACvB,KAAA;EAAA,SACA,KAAA;EAAA,SACA,aAAA;AAAA;AAAA,KAGC,sCAAA;EAAA,SACD,QAAA,EAAU,aAAA;EAAA,SACV,eAAA,EAAiB,aAAA;EAAA,SACjB,aAAA,GAAgB,gCAAA;EAAA,SAChB,aAAA;AAAA;AAAA,KAGC,kBAAA;EAAA,SAEG,IAAA;EAAA,SACA,KAAA,EAAO,CAAC;AAAA;EAAA,SAGR,IAAA;EAAA,SACA,KAAA;AAAA;AAAA,KAGH,kCAAA;EAAA,SACD,WAAW;AAAA;AAAA,KAGV,4BAAA;EAAA,SAEG,IAAA;EAAA,SACA,KAAA;EAAA,SACA,KAAA,EAAO,yBAAA;AAAA;EAAA,SAGP,IAAA;EAAA,SACA,IAAA;EAAA,SACA,KAAA;EAAA,SACA,KAAA,EAAO,yBAAA;AAAA;EAAA,SAGP,IAAA;EAAA,SACA,IAAA;EAAA,SACA,KAAA;EAAA,SACA,KAAA,EAAO,yBAAA;AAAA;EAAA,SAGP,IAAA;EAAA,SACA,KAAA;EAAA,SACA,KAAA;EAAA,SACA,KAAA,EAAO,yBAAA;AAAA;EAAA,SAGP,IAAA;EAAA,SACA,QAAA;EAAA,SACA,KAAA,EAAO,KAAA;EAAA,SACP,KAAA,EAAO,yBAAA;AAAA;AAAA,KAGV,6BAAA;EAAA,SACD,KAAA,EAAO,wBAAA;EAAA,SACP,QAAA;EAAA,SACA,YAAA,GACP,KAAA,EAAO,iCAAA,KACJ,OAAA,CAAQ,kCAAA;EAAA,SACJ,gBAAA,GACP,KAAA,EAAO,qCAAA,KACJ,OAAA,CAAQ,sCAAA;EAAA,SACJ,WAAA,QAAmB,OAAA;EAAA,SACnB,UAAA,GAAa,KAAA,cAAmB,OAAA;EAAA,SAChC,cAAA,GAAiB,kCAAA;EAAA,SACjB,kBAAA,GAAqB,kCAAA;EAAA,SACrB,gBAAA,GAAmB,kCAAA;AAAA;AAAA,cAGjB,uBAAA;AAAA,cACA,mBAAA,EAAqB,kCAAuD;AAAA,cAE5E,kBAAA,MAAyB,OAAA,EAAS,OAAA,CAAQ,CAAA,MAAK,OAAA,CAAQ,kBAAA,CAAmB,CAAA;AAAA,iBAejE,iBAAA,GAAA,CACpB,OAAA,QAAe,OAAA,CAAQ,CAAA,GACvB,MAAA,GAAS,kCAAA,GACR,OAAA,CAAQ,CAAA;AAAA,iBAiBW,sBAAA,CACpB,MAAA,EAAQ,6BAAA,GACP,OAAA,CAAQ,4BAAA"}
@@ -0,0 +1,101 @@
1
+ //#region src/workflow-loop.ts
2
+ const defaultMaxWorkflowTurns = 500;
3
+ const noWorkflowStepRetry = { maxAttempts: 1 };
4
+ const settleWorkflowStep = (promise) => promise.then((value) => ({
5
+ _tag: "Success",
6
+ value
7
+ }), (error) => ({
8
+ _tag: "Failure",
9
+ error
10
+ }));
11
+ const workflowMaxTurnsError = (maxTurns) => /* @__PURE__ */ new Error(`Vercel agent workflow exceeded max turns: ${maxTurns}`);
12
+ const writeErrorSafely = (writeError, error) => writeError(error).catch(() => void 0);
13
+ const maxRetryAttempts = (policy) => Math.max(1, Math.floor(policy?.maxAttempts ?? noWorkflowStepRetry.maxAttempts));
14
+ async function retryWorkflowStep(runStep, policy) {
15
+ const maxAttempts = maxRetryAttempts(policy);
16
+ let attempt = 1;
17
+ for (;;) try {
18
+ return await runStep();
19
+ } catch (error) {
20
+ if (attempt >= maxAttempts) throw error;
21
+ attempt += 1;
22
+ }
23
+ }
24
+ async function runVercelAgentWorkflow(config) {
25
+ let state = {
26
+ request: config.input.request,
27
+ createdMessages: [],
28
+ turn: 1,
29
+ eventSequence: 0
30
+ };
31
+ const maxTurns = config.maxTurns ?? 500;
32
+ for (let step = 0; step < maxTurns; step++) {
33
+ const modelResult = await settleWorkflowStep(retryWorkflowStep(() => config.runModelStep({
34
+ context: config.input.context,
35
+ state
36
+ }), config.modelStepRetry));
37
+ if (modelResult._tag === "Failure") {
38
+ await writeErrorSafely(config.writeError, modelResult.error);
39
+ return {
40
+ _tag: "ModelStepFailed",
41
+ turn: state.turn,
42
+ error: modelResult.error,
43
+ state
44
+ };
45
+ }
46
+ if (modelResult.value.done) {
47
+ const closeResult = await settleWorkflowStep(retryWorkflowStep(config.closeStream, config.closeStreamRetry));
48
+ if (closeResult._tag === "Failure") {
49
+ await writeErrorSafely(config.writeError, closeResult.error);
50
+ return {
51
+ _tag: "CloseStreamFailed",
52
+ turns: modelResult.value.turn,
53
+ error: closeResult.error,
54
+ state
55
+ };
56
+ }
57
+ return {
58
+ _tag: "Completed",
59
+ turns: modelResult.value.turn,
60
+ state
61
+ };
62
+ }
63
+ const toolsResult = await settleWorkflowStep(retryWorkflowStep(() => config.runToolBatchStep({
64
+ context: config.input.context,
65
+ request: config.input.request,
66
+ calls: modelResult.value.toolCalls,
67
+ createdMessages: modelResult.value.createdMessages,
68
+ turn: modelResult.value.turn,
69
+ eventSequence: modelResult.value.eventSequence ?? state.eventSequence
70
+ }), config.toolBatchStepRetry));
71
+ if (toolsResult._tag === "Failure") {
72
+ await writeErrorSafely(config.writeError, toolsResult.error);
73
+ return {
74
+ _tag: "ToolBatchStepFailed",
75
+ turn: modelResult.value.turn,
76
+ error: toolsResult.error,
77
+ state
78
+ };
79
+ }
80
+ state = {
81
+ request: config.input.request,
82
+ messages: [...modelResult.value.messages, ...toolsResult.value.messages],
83
+ createdMessages: toolsResult.value.createdMessages,
84
+ usage: modelResult.value.usage,
85
+ turn: modelResult.value.turn + 1,
86
+ eventSequence: toolsResult.value.eventSequence ?? modelResult.value.eventSequence ?? state.eventSequence
87
+ };
88
+ }
89
+ const error = workflowMaxTurnsError(maxTurns);
90
+ await writeErrorSafely(config.writeError, error);
91
+ return {
92
+ _tag: "MaxTurnsExceeded",
93
+ maxTurns,
94
+ error,
95
+ state
96
+ };
97
+ }
98
+ //#endregion
99
+ export { defaultMaxWorkflowTurns, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, settleWorkflowStep };
100
+
101
+ //# sourceMappingURL=workflow-loop.mjs.map
@@ -0,0 +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: '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 modelStepRetry?: VercelAgentWorkflowStepRetryPolicy\n readonly toolBatchStepRetry?: 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 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 let state: SerializableWorkflowState = {\n request: config.input.request,\n createdMessages: [],\n turn: 1,\n eventSequence: 0\n }\n const maxTurns = config.maxTurns ?? defaultMaxWorkflowTurns\n\n for (let step = 0; step < maxTurns; step++) {\n const modelResult = await settleWorkflowStep(\n retryWorkflowStep(\n () => config.runModelStep({ context: config.input.context, state }),\n config.modelStepRetry\n )\n )\n\n if (modelResult._tag === 'Failure') {\n await writeErrorSafely(config.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(\n retryWorkflowStep(config.closeStream, config.closeStreamRetry)\n )\n\n if (closeResult._tag === 'Failure') {\n await writeErrorSafely(config.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 const toolsResult = await settleWorkflowStep(\n retryWorkflowStep(\n () =>\n config.runToolBatchStep({\n context: config.input.context,\n request: config.input.request,\n calls: modelResult.value.toolCalls,\n createdMessages: modelResult.value.createdMessages,\n turn: modelResult.value.turn,\n eventSequence: modelResult.value.eventSequence ?? state.eventSequence\n }),\n config.toolBatchStepRetry\n )\n )\n\n if (toolsResult._tag === 'Failure') {\n await writeErrorSafely(config.writeError, toolsResult.error)\n return {\n _tag: 'ToolBatchStepFailed',\n turn: modelResult.value.turn,\n error: toolsResult.error,\n state\n }\n }\n\n state = {\n request: config.input.request,\n messages: [...modelResult.value.messages, ...toolsResult.value.messages],\n createdMessages: toolsResult.value.createdMessages,\n usage: modelResult.value.usage,\n turn: modelResult.value.turn + 1,\n eventSequence: toolsResult.value.eventSequence ?? modelResult.value.eventSequence ?? state.eventSequence\n }\n }\n\n const error = workflowMaxTurnsError(maxTurns)\n await writeErrorSafely(config.writeError, error)\n\n return {\n _tag: 'MaxTurnsExceeded',\n maxTurns,\n error,\n state\n }\n}\n"],"mappings":";AAqHA,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,oBAAoB,WACxB,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,eAAe,oBAAoB,WAAW,CAAC;AAEhF,eAAsB,kBACpB,SACA,QACY;CACZ,MAAM,cAAc,iBAAiB,MAAM;CAC3C,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,IAAI,QAAmC;EACrC,SAAS,OAAO,MAAM;EACtB,iBAAiB,CAAC;EAClB,MAAM;EACN,eAAe;CACjB;CACA,MAAM,WAAW,OAAO,YAAA;CAExB,KAAK,IAAI,OAAO,GAAG,OAAO,UAAU,QAAQ;EAC1C,MAAM,cAAc,MAAM,mBACxB,wBACQ,OAAO,aAAa;GAAE,SAAS,OAAO,MAAM;GAAS;EAAM,CAAC,GAClE,OAAO,cACT,CACF;EAEA,IAAI,YAAY,SAAS,WAAW;GAClC,MAAM,iBAAiB,OAAO,YAAY,YAAY,KAAK;GAC3D,OAAO;IACL,MAAM;IACN,MAAM,MAAM;IACZ,OAAO,YAAY;IACnB;GACF;EACF;EAEA,IAAI,YAAY,MAAM,MAAM;GAC1B,MAAM,cAAc,MAAM,mBACxB,kBAAkB,OAAO,aAAa,OAAO,gBAAgB,CAC/D;GAEA,IAAI,YAAY,SAAS,WAAW;IAClC,MAAM,iBAAiB,OAAO,YAAY,YAAY,KAAK;IAE3D,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,MAAM,cAAc,MAAM,mBACxB,wBAEI,OAAO,iBAAiB;GACtB,SAAS,OAAO,MAAM;GACtB,SAAS,OAAO,MAAM;GACtB,OAAO,YAAY,MAAM;GACzB,iBAAiB,YAAY,MAAM;GACnC,MAAM,YAAY,MAAM;GACxB,eAAe,YAAY,MAAM,iBAAiB,MAAM;EAC1D,CAAC,GACH,OAAO,kBACT,CACF;EAEA,IAAI,YAAY,SAAS,WAAW;GAClC,MAAM,iBAAiB,OAAO,YAAY,YAAY,KAAK;GAC3D,OAAO;IACL,MAAM;IACN,MAAM,YAAY,MAAM;IACxB,OAAO,YAAY;IACnB;GACF;EACF;EAEA,QAAQ;GACN,SAAS,OAAO,MAAM;GACtB,UAAU,CAAC,GAAG,YAAY,MAAM,UAAU,GAAG,YAAY,MAAM,QAAQ;GACvE,iBAAiB,YAAY,MAAM;GACnC,OAAO,YAAY,MAAM;GACzB,MAAM,YAAY,MAAM,OAAO;GAC/B,eAAe,YAAY,MAAM,iBAAiB,YAAY,MAAM,iBAAiB,MAAM;EAC7F;CACF;CAEA,MAAM,QAAQ,sBAAsB,QAAQ;CAC5C,MAAM,iBAAiB,OAAO,YAAY,KAAK;CAE/C,OAAO;EACL,MAAM;EACN;EACA;EACA;CACF;AACF"}
@@ -0,0 +1,2 @@
1
+ import { SerializableWorkflowState, VercelAgentWorkflowAwaitingInput, VercelAgentWorkflowInput, VercelAgentWorkflowLoopConfig, VercelAgentWorkflowModelStepInput, VercelAgentWorkflowModelStepResult, VercelAgentWorkflowRunResult, VercelAgentWorkflowStepRetryPolicy, VercelAgentWorkflowToolBatchStepInput, VercelAgentWorkflowToolBatchStepResult, WorkflowStepResult, defaultMaxWorkflowTurns, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, settleWorkflowStep } from "./workflow-loop.mjs";
2
+ export { type SerializableWorkflowState, type VercelAgentWorkflowAwaitingInput, type VercelAgentWorkflowInput, type VercelAgentWorkflowLoopConfig, type VercelAgentWorkflowModelStepInput, type VercelAgentWorkflowModelStepResult, type VercelAgentWorkflowRunResult, type VercelAgentWorkflowStepRetryPolicy, type VercelAgentWorkflowToolBatchStepInput, type VercelAgentWorkflowToolBatchStepResult, type WorkflowStepResult, defaultMaxWorkflowTurns, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, settleWorkflowStep };
@@ -0,0 +1,2 @@
1
+ import { defaultMaxWorkflowTurns, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, settleWorkflowStep } from "./workflow-loop.mjs";
2
+ export { defaultMaxWorkflowTurns, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, settleWorkflowStep };
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@yolk-sdk/vercel-workflows-runtime",
3
+ "version": "0.0.1-canary.0",
4
+ "description": "Vercel Workflow orchestration primitives for Yolk agent loops.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "sideEffects": false,
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/magoz/yolk-sdk.git",
11
+ "directory": "packages/vercel-workflows-runtime"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/magoz/yolk-sdk/issues"
15
+ },
16
+ "homepage": "https://github.com/magoz/yolk-sdk#readme",
17
+ "keywords": [
18
+ "vercel",
19
+ "workflow",
20
+ "agents",
21
+ "runtime",
22
+ "effect"
23
+ ],
24
+ "engines": {
25
+ "node": ">=22"
26
+ },
27
+ "exports": {
28
+ "./package.json": "./package.json",
29
+ ".": {
30
+ "types": "./dist/index.d.mts",
31
+ "import": "./dist/index.mjs",
32
+ "default": "./dist/index.mjs"
33
+ },
34
+ "./workflow": {
35
+ "types": "./dist/workflow.d.mts",
36
+ "import": "./dist/workflow.mjs",
37
+ "default": "./dist/workflow.mjs"
38
+ }
39
+ },
40
+ "files": [
41
+ "src/**/*.ts",
42
+ "!src/**/*.test.ts",
43
+ "!src/**/*.test.tsx",
44
+ "dist/**/*",
45
+ "README.md"
46
+ ],
47
+ "publishConfig": {
48
+ "access": "public",
49
+ "provenance": true
50
+ },
51
+ "dependencies": {
52
+ "effect": "4.0.0-beta.65",
53
+ "workflow": "^4.2.4"
54
+ },
55
+ "devDependencies": {
56
+ "@effect/vitest": "4.0.0-beta.65",
57
+ "@workflow/vitest": "^4.0.5",
58
+ "vitest": "^4.0.17"
59
+ },
60
+ "scripts": {
61
+ "build": "tsdown",
62
+ "check": "tsc -p tsconfig.json --noEmit",
63
+ "test": "vitest run --passWithNoTests",
64
+ "test:workflow": "vitest run --config vitest.workflow.config.ts",
65
+ "test:run": "vitest run --passWithNoTests"
66
+ }
67
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,252 @@
1
+ export type VercelAgentWorkflowInput = {
2
+ readonly request: unknown
3
+ readonly context: unknown
4
+ }
5
+
6
+ export type SerializableWorkflowState = {
7
+ readonly request: unknown
8
+ readonly messages?: ReadonlyArray<unknown>
9
+ readonly createdMessages: ReadonlyArray<unknown>
10
+ readonly usage?: unknown
11
+ readonly turn: number
12
+ readonly eventSequence?: number
13
+ }
14
+
15
+ export type VercelAgentWorkflowModelStepInput = {
16
+ readonly context: unknown
17
+ readonly state: SerializableWorkflowState
18
+ }
19
+
20
+ export type VercelAgentWorkflowModelStepResult = {
21
+ readonly done: boolean
22
+ readonly messages: ReadonlyArray<unknown>
23
+ readonly createdMessages: ReadonlyArray<unknown>
24
+ readonly toolCalls: ReadonlyArray<unknown>
25
+ readonly usage: unknown
26
+ readonly turn: number
27
+ readonly eventSequence?: number
28
+ }
29
+
30
+ export type VercelAgentWorkflowToolBatchStepInput = {
31
+ readonly context: unknown
32
+ readonly request: unknown
33
+ readonly calls: ReadonlyArray<unknown>
34
+ readonly createdMessages: ReadonlyArray<unknown>
35
+ readonly hitlResponses?: ReadonlyArray<unknown>
36
+ readonly usage?: unknown
37
+ readonly turn?: number
38
+ readonly eventSequence?: number
39
+ }
40
+
41
+ export type VercelAgentWorkflowAwaitingInput = {
42
+ readonly hookToken: string
43
+ readonly requests: ReadonlyArray<unknown>
44
+ readonly messages: ReadonlyArray<unknown>
45
+ readonly usage: unknown
46
+ readonly turns: number
47
+ readonly eventSequence?: number
48
+ }
49
+
50
+ export type VercelAgentWorkflowToolBatchStepResult = {
51
+ readonly messages: ReadonlyArray<unknown>
52
+ readonly createdMessages: ReadonlyArray<unknown>
53
+ readonly awaitingInput?: VercelAgentWorkflowAwaitingInput
54
+ readonly eventSequence?: number
55
+ }
56
+
57
+ export type WorkflowStepResult<A> =
58
+ | {
59
+ readonly _tag: 'Success'
60
+ readonly value: A
61
+ }
62
+ | {
63
+ readonly _tag: 'Failure'
64
+ readonly error: unknown
65
+ }
66
+
67
+ export type VercelAgentWorkflowStepRetryPolicy = {
68
+ readonly maxAttempts: number
69
+ }
70
+
71
+ export type VercelAgentWorkflowRunResult =
72
+ | {
73
+ readonly _tag: 'Completed'
74
+ readonly turns: number
75
+ readonly state: SerializableWorkflowState
76
+ }
77
+ | {
78
+ readonly _tag: 'ModelStepFailed'
79
+ readonly turn: number
80
+ readonly error: unknown
81
+ readonly state: SerializableWorkflowState
82
+ }
83
+ | {
84
+ readonly _tag: 'ToolBatchStepFailed'
85
+ readonly turn: number
86
+ readonly error: unknown
87
+ readonly state: SerializableWorkflowState
88
+ }
89
+ | {
90
+ readonly _tag: 'CloseStreamFailed'
91
+ readonly turns: number
92
+ readonly error: unknown
93
+ readonly state: SerializableWorkflowState
94
+ }
95
+ | {
96
+ readonly _tag: 'MaxTurnsExceeded'
97
+ readonly maxTurns: number
98
+ readonly error: Error
99
+ readonly state: SerializableWorkflowState
100
+ }
101
+
102
+ export type VercelAgentWorkflowLoopConfig = {
103
+ readonly input: VercelAgentWorkflowInput
104
+ readonly maxTurns?: number
105
+ readonly runModelStep: (
106
+ input: VercelAgentWorkflowModelStepInput
107
+ ) => Promise<VercelAgentWorkflowModelStepResult>
108
+ readonly runToolBatchStep: (
109
+ input: VercelAgentWorkflowToolBatchStepInput
110
+ ) => Promise<VercelAgentWorkflowToolBatchStepResult>
111
+ readonly closeStream: () => Promise<void>
112
+ readonly writeError: (error: unknown) => Promise<void>
113
+ readonly modelStepRetry?: VercelAgentWorkflowStepRetryPolicy
114
+ readonly toolBatchStepRetry?: VercelAgentWorkflowStepRetryPolicy
115
+ readonly closeStreamRetry?: VercelAgentWorkflowStepRetryPolicy
116
+ }
117
+
118
+ export const defaultMaxWorkflowTurns = 500
119
+ export const noWorkflowStepRetry: VercelAgentWorkflowStepRetryPolicy = { maxAttempts: 1 }
120
+
121
+ export const settleWorkflowStep = <A>(promise: Promise<A>): Promise<WorkflowStepResult<A>> =>
122
+ promise.then(
123
+ value => ({ _tag: 'Success', value }),
124
+ error => ({ _tag: 'Failure', error })
125
+ )
126
+
127
+ const workflowMaxTurnsError = (maxTurns: number) =>
128
+ new Error(`Vercel agent workflow exceeded max turns: ${maxTurns}`)
129
+
130
+ const writeErrorSafely = (writeError: (error: unknown) => Promise<void>, error: unknown) =>
131
+ writeError(error).catch(() => undefined)
132
+
133
+ const maxRetryAttempts = (policy: VercelAgentWorkflowStepRetryPolicy | undefined) =>
134
+ Math.max(1, Math.floor(policy?.maxAttempts ?? noWorkflowStepRetry.maxAttempts))
135
+
136
+ export async function retryWorkflowStep<A>(
137
+ runStep: () => Promise<A>,
138
+ policy?: VercelAgentWorkflowStepRetryPolicy
139
+ ): Promise<A> {
140
+ const maxAttempts = maxRetryAttempts(policy)
141
+ let attempt = 1
142
+
143
+ for (;;) {
144
+ try {
145
+ return await runStep()
146
+ } catch (error) {
147
+ if (attempt >= maxAttempts) {
148
+ throw error
149
+ }
150
+
151
+ attempt += 1
152
+ }
153
+ }
154
+ }
155
+
156
+ export async function runVercelAgentWorkflow(
157
+ config: VercelAgentWorkflowLoopConfig
158
+ ): Promise<VercelAgentWorkflowRunResult> {
159
+ let state: SerializableWorkflowState = {
160
+ request: config.input.request,
161
+ createdMessages: [],
162
+ turn: 1,
163
+ eventSequence: 0
164
+ }
165
+ const maxTurns = config.maxTurns ?? defaultMaxWorkflowTurns
166
+
167
+ for (let step = 0; step < maxTurns; step++) {
168
+ const modelResult = await settleWorkflowStep(
169
+ retryWorkflowStep(
170
+ () => config.runModelStep({ context: config.input.context, state }),
171
+ config.modelStepRetry
172
+ )
173
+ )
174
+
175
+ if (modelResult._tag === 'Failure') {
176
+ await writeErrorSafely(config.writeError, modelResult.error)
177
+ return {
178
+ _tag: 'ModelStepFailed',
179
+ turn: state.turn,
180
+ error: modelResult.error,
181
+ state
182
+ }
183
+ }
184
+
185
+ if (modelResult.value.done) {
186
+ const closeResult = await settleWorkflowStep(
187
+ retryWorkflowStep(config.closeStream, config.closeStreamRetry)
188
+ )
189
+
190
+ if (closeResult._tag === 'Failure') {
191
+ await writeErrorSafely(config.writeError, closeResult.error)
192
+
193
+ return {
194
+ _tag: 'CloseStreamFailed',
195
+ turns: modelResult.value.turn,
196
+ error: closeResult.error,
197
+ state
198
+ }
199
+ }
200
+
201
+ return {
202
+ _tag: 'Completed',
203
+ turns: modelResult.value.turn,
204
+ state
205
+ }
206
+ }
207
+
208
+ const toolsResult = await settleWorkflowStep(
209
+ retryWorkflowStep(
210
+ () =>
211
+ config.runToolBatchStep({
212
+ context: config.input.context,
213
+ request: config.input.request,
214
+ calls: modelResult.value.toolCalls,
215
+ createdMessages: modelResult.value.createdMessages,
216
+ turn: modelResult.value.turn,
217
+ eventSequence: modelResult.value.eventSequence ?? state.eventSequence
218
+ }),
219
+ config.toolBatchStepRetry
220
+ )
221
+ )
222
+
223
+ if (toolsResult._tag === 'Failure') {
224
+ await writeErrorSafely(config.writeError, toolsResult.error)
225
+ return {
226
+ _tag: 'ToolBatchStepFailed',
227
+ turn: modelResult.value.turn,
228
+ error: toolsResult.error,
229
+ state
230
+ }
231
+ }
232
+
233
+ state = {
234
+ request: config.input.request,
235
+ messages: [...modelResult.value.messages, ...toolsResult.value.messages],
236
+ createdMessages: toolsResult.value.createdMessages,
237
+ usage: modelResult.value.usage,
238
+ turn: modelResult.value.turn + 1,
239
+ eventSequence: toolsResult.value.eventSequence ?? modelResult.value.eventSequence ?? state.eventSequence
240
+ }
241
+ }
242
+
243
+ const error = workflowMaxTurnsError(maxTurns)
244
+ await writeErrorSafely(config.writeError, error)
245
+
246
+ return {
247
+ _tag: 'MaxTurnsExceeded',
248
+ maxTurns,
249
+ error,
250
+ state
251
+ }
252
+ }
@@ -0,0 +1,20 @@
1
+ export {
2
+ defaultMaxWorkflowTurns,
3
+ noWorkflowStepRetry,
4
+ retryWorkflowStep,
5
+ runVercelAgentWorkflow,
6
+ settleWorkflowStep
7
+ } from './workflow-loop.ts'
8
+ export type {
9
+ SerializableWorkflowState,
10
+ VercelAgentWorkflowAwaitingInput,
11
+ VercelAgentWorkflowInput,
12
+ VercelAgentWorkflowLoopConfig,
13
+ VercelAgentWorkflowModelStepInput,
14
+ VercelAgentWorkflowModelStepResult,
15
+ VercelAgentWorkflowRunResult,
16
+ VercelAgentWorkflowStepRetryPolicy,
17
+ VercelAgentWorkflowToolBatchStepInput,
18
+ VercelAgentWorkflowToolBatchStepResult,
19
+ WorkflowStepResult
20
+ } from './workflow-loop.ts'