@yolk-sdk/vercel-workflows 0.1.0-canary.100
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +340 -0
- package/dist/effect.d.mts +56 -0
- package/dist/effect.d.mts.map +1 -0
- package/dist/effect.mjs +58 -0
- package/dist/effect.mjs.map +1 -0
- package/dist/index.d.mts +4 -0
- package/dist/index.mjs +4 -0
- package/dist/testing/index.d.mts +97 -0
- package/dist/testing/index.d.mts.map +1 -0
- package/dist/testing/index.mjs +285 -0
- package/dist/testing/index.mjs.map +1 -0
- package/dist/workflow-children.d.mts +42 -0
- package/dist/workflow-children.d.mts.map +1 -0
- package/dist/workflow-children.mjs +54 -0
- package/dist/workflow-children.mjs.map +1 -0
- package/dist/workflow-events.d.mts +210 -0
- package/dist/workflow-events.d.mts.map +1 -0
- package/dist/workflow-events.mjs +54 -0
- package/dist/workflow-events.mjs.map +1 -0
- package/dist/workflow-loop.d.mts +416 -0
- package/dist/workflow-loop.d.mts.map +1 -0
- package/dist/workflow-loop.mjs +177 -0
- package/dist/workflow-loop.mjs.map +1 -0
- package/dist/workflow.d.mts +4 -0
- package/dist/workflow.mjs +4 -0
- package/package.json +77 -0
- package/src/effect.ts +232 -0
- package/src/index.ts +36 -0
- package/src/testing/index.ts +503 -0
- package/src/workflow-children.ts +81 -0
- package/src/workflow-events.ts +202 -0
- package/src/workflow-loop.ts +404 -0
- package/src/workflow.ts +42 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-loop.mjs","names":[],"sources":["../src/workflow-loop.ts"],"sourcesContent":["import { Data, Predicate } from 'effect'\n\nexport 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 /** Updated cumulative usage when tools run nested model work such as subagents. */\n readonly usage?: unknown\n readonly awaitingInput?: VercelAgentWorkflowAwaitingInput\n readonly eventSequence?: number\n /**\n * A plain wire-safe failure captured after partial progress. Returning it instead of rejecting\n * lets orchestration retain usage and event sequencing from completed sibling tools.\n */\n readonly failure?: unknown\n}\n\nexport type WorkflowStepResult<A> = Data.TaggedEnum<{\n Success: {\n readonly value: A\n }\n Failure: {\n readonly error: unknown\n }\n}>\n\ninterface WorkflowStepResultDefinition extends Data.TaggedEnum.WithGenerics<1> {\n readonly taggedEnum: WorkflowStepResult<this['A']>\n}\n\nexport const WorkflowStepResult = Data.taggedEnum<WorkflowStepResultDefinition>()\n\nexport type VercelAgentWorkflowStepRetryPolicy = {\n readonly maxAttempts: number\n}\n\nexport type VercelAgentWorkflowRunResult = Data.TaggedEnum<{\n Completed: {\n readonly turns: number\n readonly state: SerializableWorkflowState\n }\n ModelStepFailed: {\n readonly turn: number\n readonly error: unknown\n readonly state: SerializableWorkflowState\n }\n ToolBatchStepFailed: {\n readonly turn: number\n readonly error: unknown\n readonly state: SerializableWorkflowState\n }\n AwaitInputFailed: {\n readonly turn: number\n readonly error: unknown\n readonly awaitingInput: VercelAgentWorkflowAwaitingInput\n readonly state: SerializableWorkflowState\n }\n CloseStreamFailed: {\n readonly turns: number\n readonly error: unknown\n readonly state: SerializableWorkflowState\n }\n MaxTurnsExceeded: {\n readonly maxTurns: number\n readonly error: Error\n readonly state: SerializableWorkflowState\n }\n}>\n\nexport const VercelAgentWorkflowRunResult = Data.taggedEnum<VercelAgentWorkflowRunResult>()\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 /** Called only after a model step returns `done: true`. */\n readonly closeStream: () => Promise<void>\n /**\n * Best-effort final failure handler. It must write a safe final error and\n * close the failure stream; rejection is suppressed in favor of the\n * original structured run result.\n */\n readonly writeError: (error: unknown) => Promise<void>\n /** A successful await suspends/resumes without invoking either finalizer. */\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\n\nexport const noWorkflowStepRetry: VercelAgentWorkflowStepRetryPolicy = { maxAttempts: 1 }\n\nexport const settleWorkflowStep = <A>(promise: Promise<A>): Promise<WorkflowStepResult<A>> =>\n promise.then(\n value => WorkflowStepResult.Success<A>({ value }),\n error => WorkflowStepResult.Failure<A>({ 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 const configured = policy?.maxAttempts ?? noWorkflowStepRetry.maxAttempts\n\n return Number.isFinite(configured) ? Math.max(1, Math.floor(configured)) : 1\n}\n\nconst maxWorkflowTurns = (configured: number | undefined) => {\n if (configured === undefined || !Number.isFinite(configured)) {\n return defaultMaxWorkflowTurns\n }\n\n return Math.max(1, Math.floor(configured))\n}\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\n let state: SerializableWorkflowState = {\n request: input.request,\n createdMessages: [],\n turn: 1,\n eventSequence: 0\n }\n\n const maxTurns = maxWorkflowTurns(configuredMaxTurns)\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 (Predicate.isTagged(modelResult, 'Failure')) {\n await writeErrorSafely(writeError, modelResult.error)\n\n return VercelAgentWorkflowRunResult.ModelStepFailed({\n turn: state.turn,\n error: modelResult.error,\n state\n })\n }\n\n if (modelResult.value.done) {\n const terminalState: SerializableWorkflowState = {\n request: input.request,\n messages: modelResult.value.messages,\n createdMessages: modelResult.value.createdMessages,\n usage: modelResult.value.usage,\n turn: modelResult.value.turn,\n eventSequence: modelResult.value.eventSequence ?? state.eventSequence\n }\n\n const closeResult = await settleWorkflowStep(retryWorkflowStep(closeStream, closeStreamRetry))\n\n if (Predicate.isTagged(closeResult, 'Failure')) {\n await writeErrorSafely(writeError, closeResult.error)\n\n return VercelAgentWorkflowRunResult.CloseStreamFailed({\n turns: modelResult.value.turn,\n error: closeResult.error,\n state: terminalState\n })\n }\n\n return VercelAgentWorkflowRunResult.Completed({\n turns: modelResult.value.turn,\n state: terminalState\n })\n }\n\n if (modelResult.value.toolCalls.length === 0) {\n state = {\n request: input.request,\n messages: modelResult.value.messages,\n createdMessages: modelResult.value.createdMessages,\n usage: modelResult.value.usage,\n turn: modelResult.value.turn + 1,\n eventSequence: modelResult.value.eventSequence ?? state.eventSequence\n }\n continue\n }\n\n let completedToolsResult: VercelAgentWorkflowToolBatchStepResult | undefined\n const toolHitlResponses: Array<unknown> = []\n let cumulativeUsage = modelResult.value.usage\n let toolEventSequence = modelResult.value.eventSequence ?? state.eventSequence\n\n const currentTurnState = (\n toolResult?: VercelAgentWorkflowToolBatchStepResult\n ): SerializableWorkflowState => ({\n request: input.request,\n messages:\n toolResult === undefined\n ? modelResult.value.messages\n : [...modelResult.value.messages, ...toolResult.messages],\n createdMessages: toolResult?.createdMessages ?? modelResult.value.createdMessages,\n usage: cumulativeUsage,\n turn: modelResult.value.turn,\n eventSequence: toolEventSequence\n })\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.slice(),\n usage: cumulativeUsage,\n turn: modelResult.value.turn,\n eventSequence: toolEventSequence\n }),\n toolBatchStepRetry\n )\n )\n\n if (Predicate.isTagged(toolsResult, 'Failure')) {\n await writeErrorSafely(writeError, toolsResult.error)\n\n return VercelAgentWorkflowRunResult.ToolBatchStepFailed({\n turn: modelResult.value.turn,\n error: toolsResult.error,\n state: currentTurnState()\n })\n }\n\n cumulativeUsage = toolsResult.value.usage ?? cumulativeUsage\n toolEventSequence = toolsResult.value.eventSequence ?? toolEventSequence\n\n if (toolsResult.value.failure !== undefined) {\n await writeErrorSafely(writeError, toolsResult.value.failure)\n\n return VercelAgentWorkflowRunResult.ToolBatchStepFailed({\n turn: modelResult.value.turn,\n error: toolsResult.value.failure,\n state: currentTurnState(toolsResult.value)\n })\n }\n\n if (toolsResult.value.awaitingInput === undefined) {\n completedToolsResult = toolsResult.value\n break\n }\n\n const awaitingInput = toolsResult.value.awaitingInput\n cumulativeUsage = toolsResult.value.usage ?? awaitingInput.usage ?? cumulativeUsage\n toolEventSequence = awaitingInput.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 (Predicate.isTagged(hitlResponse, 'Failure')) {\n await writeErrorSafely(writeError, hitlResponse.error)\n\n return VercelAgentWorkflowRunResult.AwaitInputFailed({\n turn: modelResult.value.turn,\n error: hitlResponse.error,\n awaitingInput,\n state: currentTurnState(toolsResult.value)\n })\n }\n\n toolHitlResponses.push(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 VercelAgentWorkflowRunResult.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: completedToolsResult.usage ?? cumulativeUsage,\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 VercelAgentWorkflowRunResult.MaxTurnsExceeded({\n maxTurns,\n error,\n state\n })\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { SerializableWorkflowState, VercelAgentWorkflowAwaitingInput, VercelAgentWorkflowInput, VercelAgentWorkflowLoopConfig, VercelAgentWorkflowModelStepInput, VercelAgentWorkflowModelStepResult, VercelAgentWorkflowRunResult, VercelAgentWorkflowStepRetryPolicy, VercelAgentWorkflowToolBatchStepInput, VercelAgentWorkflowToolBatchStepResult, WorkflowStepResult, defaultMaxWorkflowTurns, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, settleWorkflowStep } from "./workflow-loop.mjs";
|
|
2
|
+
import { CommitThenWriteTerminalEventInput, CommitThenWriteTerminalEventResult, DurableAgentEvent, DurableAgentEventIdInput, DurableAgentEventSequencerState, SequenceDurableAgentEventInput, SequencedDurableAgentEvent, WriteDurableAgentEventInput, commitThenWriteTerminalEvent, durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent } from "./workflow-events.mjs";
|
|
3
|
+
import { awaitWorkflowChild, orchestrateWorkflowToolBatch } from "./workflow-children.mjs";
|
|
4
|
+
export { type CommitThenWriteTerminalEventInput, type CommitThenWriteTerminalEventResult, type DurableAgentEvent, type DurableAgentEventIdInput, type DurableAgentEventSequencerState, type SequenceDurableAgentEventInput, type SequencedDurableAgentEvent, type SerializableWorkflowState, type VercelAgentWorkflowAwaitingInput, type VercelAgentWorkflowInput, type VercelAgentWorkflowLoopConfig, type VercelAgentWorkflowModelStepInput, type VercelAgentWorkflowModelStepResult, VercelAgentWorkflowRunResult, type VercelAgentWorkflowStepRetryPolicy, type VercelAgentWorkflowToolBatchStepInput, type VercelAgentWorkflowToolBatchStepResult, WorkflowStepResult, type WriteDurableAgentEventInput, awaitWorkflowChild, commitThenWriteTerminalEvent, defaultMaxWorkflowTurns, durableAgentEventId, makeDurableAgentEventSequencerState, noWorkflowStepRetry, orchestrateWorkflowToolBatch, retryWorkflowStep, runVercelAgentWorkflow, sequenceDurableAgentEvent, settleWorkflowStep, writeDurableAgentEvent };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { VercelAgentWorkflowRunResult, WorkflowStepResult, defaultMaxWorkflowTurns, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, settleWorkflowStep } from "./workflow-loop.mjs";
|
|
2
|
+
import { commitThenWriteTerminalEvent, durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent } from "./workflow-events.mjs";
|
|
3
|
+
import { awaitWorkflowChild, orchestrateWorkflowToolBatch } from "./workflow-children.mjs";
|
|
4
|
+
export { VercelAgentWorkflowRunResult, WorkflowStepResult, awaitWorkflowChild, commitThenWriteTerminalEvent, defaultMaxWorkflowTurns, durableAgentEventId, makeDurableAgentEventSequencerState, noWorkflowStepRetry, orchestrateWorkflowToolBatch, retryWorkflowStep, runVercelAgentWorkflow, sequenceDurableAgentEvent, settleWorkflowStep, writeDurableAgentEvent };
|
package/package.json
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@yolk-sdk/vercel-workflows",
|
|
3
|
+
"version": "0.1.0-canary.100",
|
|
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"
|
|
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
|
+
"./effect": {
|
|
40
|
+
"types": "./dist/effect.d.mts",
|
|
41
|
+
"import": "./dist/effect.mjs",
|
|
42
|
+
"default": "./dist/effect.mjs"
|
|
43
|
+
},
|
|
44
|
+
"./testing": {
|
|
45
|
+
"types": "./dist/testing/index.d.mts",
|
|
46
|
+
"import": "./dist/testing/index.mjs",
|
|
47
|
+
"default": "./dist/testing/index.mjs"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"files": [
|
|
51
|
+
"src/**/*.ts",
|
|
52
|
+
"!src/**/*.test.ts",
|
|
53
|
+
"!src/**/*.test.tsx",
|
|
54
|
+
"dist/**/*",
|
|
55
|
+
"README.md"
|
|
56
|
+
],
|
|
57
|
+
"publishConfig": {
|
|
58
|
+
"access": "public",
|
|
59
|
+
"provenance": true
|
|
60
|
+
},
|
|
61
|
+
"dependencies": {
|
|
62
|
+
"effect": "4.0.0",
|
|
63
|
+
"workflow": "^5.0.0-beta.42"
|
|
64
|
+
},
|
|
65
|
+
"devDependencies": {
|
|
66
|
+
"@effect/vitest": "4.0.0",
|
|
67
|
+
"@workflow/vitest": "^5.0.0-beta.42",
|
|
68
|
+
"vitest": "^5.0.1"
|
|
69
|
+
},
|
|
70
|
+
"scripts": {
|
|
71
|
+
"build": "tsdown",
|
|
72
|
+
"check": "tsc -p tsconfig.json --noEmit",
|
|
73
|
+
"test": "vitest run --passWithNoTests",
|
|
74
|
+
"test:workflow": "vitest run --config vitest.workflow.config.ts",
|
|
75
|
+
"test:run": "vitest run --passWithNoTests"
|
|
76
|
+
}
|
|
77
|
+
}
|
package/src/effect.ts
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { Context, Data, Effect, Layer } from 'effect'
|
|
2
|
+
import {
|
|
3
|
+
getRun as workflowGetRun,
|
|
4
|
+
resumeHook as workflowResumeHook,
|
|
5
|
+
start as workflowStart,
|
|
6
|
+
type WorkflowReadableStream,
|
|
7
|
+
type WorkflowReadableStreamOptions,
|
|
8
|
+
type WorkflowRun
|
|
9
|
+
} from 'workflow/api'
|
|
10
|
+
|
|
11
|
+
export type VercelWorkflowsOperation =
|
|
12
|
+
| 'start'
|
|
13
|
+
| 'getRun'
|
|
14
|
+
| 'getReadable'
|
|
15
|
+
| 'tailIndex'
|
|
16
|
+
| 'resumeHook'
|
|
17
|
+
| 'cancel'
|
|
18
|
+
| 'status'
|
|
19
|
+
| 'returnValue'
|
|
20
|
+
|
|
21
|
+
export class VercelWorkflowsError extends Data.TaggedError('VercelWorkflowsError')<{
|
|
22
|
+
readonly operation: VercelWorkflowsOperation
|
|
23
|
+
readonly message: string
|
|
24
|
+
readonly cause: unknown
|
|
25
|
+
}> {}
|
|
26
|
+
|
|
27
|
+
export type VercelWorkflowFunction<TArgs extends unknown[], TResult> = (
|
|
28
|
+
...args: TArgs
|
|
29
|
+
) => Promise<TResult>
|
|
30
|
+
|
|
31
|
+
export type VercelWorkflowReadableOptions = WorkflowReadableStreamOptions
|
|
32
|
+
|
|
33
|
+
export type VercelWorkflowReadableStream<Chunk> = WorkflowReadableStream<Chunk>
|
|
34
|
+
|
|
35
|
+
export type VercelWorkflowRunStatus = WorkflowRun['status']
|
|
36
|
+
|
|
37
|
+
export type VercelWorkflowsSdkRun<TResult> = {
|
|
38
|
+
readonly runId: string
|
|
39
|
+
readonly getReadable: <Chunk>(
|
|
40
|
+
options?: VercelWorkflowReadableOptions
|
|
41
|
+
) => VercelWorkflowReadableStream<Chunk>
|
|
42
|
+
readonly cancel: () => Promise<void>
|
|
43
|
+
readonly status: Promise<VercelWorkflowRunStatus>
|
|
44
|
+
readonly returnValue: Promise<TResult>
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export type VercelWorkflowsSdkClient = {
|
|
48
|
+
readonly start: <TArgs extends unknown[], TResult>(
|
|
49
|
+
workflow: VercelWorkflowFunction<TArgs, TResult>,
|
|
50
|
+
args: TArgs
|
|
51
|
+
) => Promise<VercelWorkflowsSdkRun<TResult>>
|
|
52
|
+
readonly getRun: <TResult>(runId: string) => VercelWorkflowsSdkRun<TResult>
|
|
53
|
+
readonly resumeHook: (token: string, payload: unknown) => Promise<void>
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export type VercelWorkflowRun<TResult> = {
|
|
57
|
+
readonly runId: string
|
|
58
|
+
readonly getReadable: <Chunk>(
|
|
59
|
+
options?: VercelWorkflowReadableOptions
|
|
60
|
+
) => Effect.Effect<VercelWorkflowReadableStream<Chunk>, VercelWorkflowsError>
|
|
61
|
+
readonly cancel: Effect.Effect<void, VercelWorkflowsError>
|
|
62
|
+
readonly status: Effect.Effect<VercelWorkflowRunStatus, VercelWorkflowsError>
|
|
63
|
+
readonly returnValue: Effect.Effect<TResult, VercelWorkflowsError>
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export type VercelWorkflowsClient = {
|
|
67
|
+
readonly start: <TArgs extends unknown[], TResult>(
|
|
68
|
+
workflow: VercelWorkflowFunction<TArgs, TResult>,
|
|
69
|
+
args: TArgs
|
|
70
|
+
) => Effect.Effect<VercelWorkflowRun<TResult>, VercelWorkflowsError>
|
|
71
|
+
readonly getRun: <TResult>(
|
|
72
|
+
runId: string
|
|
73
|
+
) => Effect.Effect<VercelWorkflowRun<TResult>, VercelWorkflowsError>
|
|
74
|
+
readonly getReadable: <Chunk>(
|
|
75
|
+
runId: string,
|
|
76
|
+
options?: VercelWorkflowReadableOptions
|
|
77
|
+
) => Effect.Effect<VercelWorkflowReadableStream<Chunk>, VercelWorkflowsError>
|
|
78
|
+
readonly tailIndex: (runId: string) => Effect.Effect<number, VercelWorkflowsError>
|
|
79
|
+
readonly resumeHook: (
|
|
80
|
+
token: string,
|
|
81
|
+
payload: unknown
|
|
82
|
+
) => Effect.Effect<void, VercelWorkflowsError>
|
|
83
|
+
readonly cancel: (runId: string) => Effect.Effect<void, VercelWorkflowsError>
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export class VercelWorkflowsSdk extends Context.Service<
|
|
87
|
+
VercelWorkflowsSdk,
|
|
88
|
+
VercelWorkflowsSdkClient
|
|
89
|
+
>()('@yolk-sdk/vercel-workflows/VercelWorkflowsSdk') {}
|
|
90
|
+
|
|
91
|
+
const workflowsError = (operation: VercelWorkflowsOperation, cause: unknown) =>
|
|
92
|
+
new VercelWorkflowsError({
|
|
93
|
+
operation,
|
|
94
|
+
message: `Vercel Workflow ${operation} failed`,
|
|
95
|
+
cause
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
const spanAttributes = (runId: string) => ({ 'workflow.run.id': runId })
|
|
99
|
+
|
|
100
|
+
const trySdkPromise = <A>(body: () => Promise<A>) =>
|
|
101
|
+
Effect.tryPromise({
|
|
102
|
+
try: body,
|
|
103
|
+
catch: error => error
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
const mapSdkError =
|
|
107
|
+
(operation: VercelWorkflowsOperation) =>
|
|
108
|
+
<A>(effect: Effect.Effect<A, unknown>) =>
|
|
109
|
+
effect.pipe(Effect.mapError(cause => workflowsError(operation, cause)))
|
|
110
|
+
|
|
111
|
+
const makeWorkflowRun = <TResult>(
|
|
112
|
+
run: VercelWorkflowsSdkRun<TResult>
|
|
113
|
+
): VercelWorkflowRun<TResult> => ({
|
|
114
|
+
runId: run.runId,
|
|
115
|
+
getReadable: <Chunk>(options?: VercelWorkflowReadableOptions) =>
|
|
116
|
+
Effect.try({
|
|
117
|
+
try: () => run.getReadable<Chunk>(options),
|
|
118
|
+
catch: cause => workflowsError('getReadable', cause)
|
|
119
|
+
}).pipe(
|
|
120
|
+
Effect.withSpan('VercelWorkflows.run.getReadable', {
|
|
121
|
+
attributes: spanAttributes(run.runId)
|
|
122
|
+
})
|
|
123
|
+
),
|
|
124
|
+
cancel: trySdkPromise(() => run.cancel()).pipe(
|
|
125
|
+
mapSdkError('cancel'),
|
|
126
|
+
Effect.withSpan('VercelWorkflows.run.cancel', {
|
|
127
|
+
attributes: spanAttributes(run.runId)
|
|
128
|
+
})
|
|
129
|
+
),
|
|
130
|
+
status: trySdkPromise(() => run.status).pipe(
|
|
131
|
+
mapSdkError('status'),
|
|
132
|
+
Effect.withSpan('VercelWorkflows.run.status', {
|
|
133
|
+
attributes: spanAttributes(run.runId)
|
|
134
|
+
})
|
|
135
|
+
),
|
|
136
|
+
returnValue: trySdkPromise(() => run.returnValue).pipe(
|
|
137
|
+
mapSdkError('returnValue'),
|
|
138
|
+
Effect.withSpan('VercelWorkflows.run.returnValue', {
|
|
139
|
+
attributes: spanAttributes(run.runId)
|
|
140
|
+
})
|
|
141
|
+
)
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
const VercelWorkflowsSdkLive = Layer.succeed(VercelWorkflowsSdk, {
|
|
145
|
+
start: <TArgs extends unknown[], TResult>(
|
|
146
|
+
workflow: VercelWorkflowFunction<TArgs, TResult>,
|
|
147
|
+
args: TArgs
|
|
148
|
+
) => workflowStart(workflow, args),
|
|
149
|
+
getRun: <TResult>(runId: string) => workflowGetRun<TResult>(runId),
|
|
150
|
+
resumeHook: async (token: string, payload: unknown) => {
|
|
151
|
+
await workflowResumeHook<unknown>(token, payload)
|
|
152
|
+
}
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
export class VercelWorkflows extends Context.Service<VercelWorkflows, VercelWorkflowsClient>()(
|
|
156
|
+
'@yolk-sdk/vercel-workflows/VercelWorkflows',
|
|
157
|
+
{
|
|
158
|
+
make: Effect.gen(function* () {
|
|
159
|
+
const sdk = yield* VercelWorkflowsSdk
|
|
160
|
+
|
|
161
|
+
const getRun = <TResult>(
|
|
162
|
+
runId: string
|
|
163
|
+
): Effect.Effect<VercelWorkflowRun<TResult>, VercelWorkflowsError> =>
|
|
164
|
+
Effect.try({
|
|
165
|
+
try: () => sdk.getRun<TResult>(runId),
|
|
166
|
+
catch: error => error
|
|
167
|
+
}).pipe(
|
|
168
|
+
mapSdkError('getRun'),
|
|
169
|
+
Effect.map(makeWorkflowRun),
|
|
170
|
+
Effect.withSpan('VercelWorkflows.getRun', {
|
|
171
|
+
attributes: spanAttributes(runId)
|
|
172
|
+
})
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
return {
|
|
176
|
+
start: <TArgs extends unknown[], TResult>(
|
|
177
|
+
workflow: VercelWorkflowFunction<TArgs, TResult>,
|
|
178
|
+
args: TArgs
|
|
179
|
+
): Effect.Effect<VercelWorkflowRun<TResult>, VercelWorkflowsError> =>
|
|
180
|
+
trySdkPromise(() => sdk.start(workflow, args)).pipe(
|
|
181
|
+
mapSdkError('start'),
|
|
182
|
+
Effect.map(makeWorkflowRun),
|
|
183
|
+
Effect.withSpan('VercelWorkflows.start')
|
|
184
|
+
),
|
|
185
|
+
|
|
186
|
+
getRun,
|
|
187
|
+
|
|
188
|
+
getReadable: <Chunk>(
|
|
189
|
+
runId: string,
|
|
190
|
+
options?: VercelWorkflowReadableOptions
|
|
191
|
+
): Effect.Effect<VercelWorkflowReadableStream<Chunk>, VercelWorkflowsError> =>
|
|
192
|
+
getRun<unknown>(runId).pipe(
|
|
193
|
+
Effect.flatMap(run => run.getReadable<Chunk>(options)),
|
|
194
|
+
Effect.withSpan('VercelWorkflows.getReadable', {
|
|
195
|
+
attributes: spanAttributes(runId)
|
|
196
|
+
})
|
|
197
|
+
),
|
|
198
|
+
|
|
199
|
+
tailIndex: (runId: string): Effect.Effect<number, VercelWorkflowsError> =>
|
|
200
|
+
getRun<unknown>(runId).pipe(
|
|
201
|
+
Effect.flatMap(run => run.getReadable<unknown>({ startIndex: -1 })),
|
|
202
|
+
Effect.flatMap(readable =>
|
|
203
|
+
Effect.tryPromise({
|
|
204
|
+
try: () => readable.getTailIndex(),
|
|
205
|
+
catch: cause => workflowsError('tailIndex', cause)
|
|
206
|
+
})
|
|
207
|
+
),
|
|
208
|
+
Effect.withSpan('VercelWorkflows.tailIndex', {
|
|
209
|
+
attributes: spanAttributes(runId)
|
|
210
|
+
})
|
|
211
|
+
),
|
|
212
|
+
|
|
213
|
+
resumeHook: (token: string, payload: unknown): Effect.Effect<void, VercelWorkflowsError> =>
|
|
214
|
+
trySdkPromise(() => sdk.resumeHook(token, payload)).pipe(
|
|
215
|
+
mapSdkError('resumeHook'),
|
|
216
|
+
Effect.withSpan('VercelWorkflows.resumeHook')
|
|
217
|
+
),
|
|
218
|
+
|
|
219
|
+
cancel: (runId: string): Effect.Effect<void, VercelWorkflowsError> =>
|
|
220
|
+
getRun<unknown>(runId).pipe(
|
|
221
|
+
Effect.flatMap(run => run.cancel),
|
|
222
|
+
Effect.withSpan('VercelWorkflows.cancel', {
|
|
223
|
+
attributes: spanAttributes(runId)
|
|
224
|
+
})
|
|
225
|
+
)
|
|
226
|
+
}
|
|
227
|
+
})
|
|
228
|
+
}
|
|
229
|
+
) {
|
|
230
|
+
static layer = Layer.effect(this, this.make).pipe(Layer.provide(VercelWorkflowsSdkLive))
|
|
231
|
+
static layerFromSdk = Layer.effect(this, this.make)
|
|
232
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export {
|
|
2
|
+
commitThenWriteTerminalEvent,
|
|
3
|
+
durableAgentEventId,
|
|
4
|
+
defaultMaxWorkflowTurns,
|
|
5
|
+
makeDurableAgentEventSequencerState,
|
|
6
|
+
noWorkflowStepRetry,
|
|
7
|
+
retryWorkflowStep,
|
|
8
|
+
runVercelAgentWorkflow,
|
|
9
|
+
sequenceDurableAgentEvent,
|
|
10
|
+
settleWorkflowStep,
|
|
11
|
+
VercelAgentWorkflowRunResult,
|
|
12
|
+
WorkflowStepResult,
|
|
13
|
+
writeDurableAgentEvent
|
|
14
|
+
} from './workflow.ts'
|
|
15
|
+
|
|
16
|
+
export type {
|
|
17
|
+
CommitThenWriteTerminalEventInput,
|
|
18
|
+
CommitThenWriteTerminalEventResult,
|
|
19
|
+
DurableAgentEvent,
|
|
20
|
+
DurableAgentEventIdInput,
|
|
21
|
+
DurableAgentEventSequencerState,
|
|
22
|
+
SequenceDurableAgentEventInput,
|
|
23
|
+
SequencedDurableAgentEvent,
|
|
24
|
+
SerializableWorkflowState,
|
|
25
|
+
VercelAgentWorkflowAwaitingInput,
|
|
26
|
+
VercelAgentWorkflowInput,
|
|
27
|
+
VercelAgentWorkflowLoopConfig,
|
|
28
|
+
VercelAgentWorkflowModelStepInput,
|
|
29
|
+
VercelAgentWorkflowModelStepResult,
|
|
30
|
+
VercelAgentWorkflowStepRetryPolicy,
|
|
31
|
+
VercelAgentWorkflowToolBatchStepInput,
|
|
32
|
+
VercelAgentWorkflowToolBatchStepResult,
|
|
33
|
+
WriteDurableAgentEventInput
|
|
34
|
+
} from './workflow.ts'
|
|
35
|
+
|
|
36
|
+
export { awaitWorkflowChild, orchestrateWorkflowToolBatch } from './workflow-children.ts'
|