@yolk-sdk/vercel-workflows 0.1.0-canary.104 → 0.1.0-canary.106
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 +5 -1
- package/dist/workflow-loop.d.mts +7 -0
- package/dist/workflow-loop.d.mts.map +1 -1
- package/dist/workflow-loop.mjs +10 -2
- package/dist/workflow-loop.mjs.map +1 -1
- package/package.json +1 -1
- package/src/workflow-loop.ts +31 -14
package/README.md
CHANGED
|
@@ -210,7 +210,11 @@ loop will:
|
|
|
210
210
|
|
|
211
211
|
1. pass that payload to `awaitInput`
|
|
212
212
|
2. wait for the hook/webhook response
|
|
213
|
-
3. rerun the same tool batch with the accumulated responses in a fresh `hitlResponses` array
|
|
213
|
+
3. rerun the same tool batch with the accumulated responses in a fresh `hitlResponses` array and
|
|
214
|
+
the requests of the pause being resumed as `awaitingRequests` (absent on the first attempt)
|
|
215
|
+
|
|
216
|
+
Forward `awaitingRequests` to the agent loop's `prepareToolBatch`/`runToolBatch`: an unanswered
|
|
217
|
+
approval then stays pending even when its tool's policy changed since the pause.
|
|
214
218
|
|
|
215
219
|
The loop owns its accumulator: host mutation of a supplied array cannot affect a later batch.
|
|
216
220
|
Response order and element identity are preserved; response objects are not deep-cloned.
|
package/dist/workflow-loop.d.mts
CHANGED
|
@@ -32,6 +32,13 @@ type VercelAgentWorkflowToolBatchStepInput = {
|
|
|
32
32
|
readonly calls: ReadonlyArray<unknown>;
|
|
33
33
|
readonly createdMessages: ReadonlyArray<unknown>;
|
|
34
34
|
readonly hitlResponses?: ReadonlyArray<unknown>;
|
|
35
|
+
/**
|
|
36
|
+
* On a resume, the requests of the pause being resumed (`awaitingInput.requests` of the
|
|
37
|
+
* previous attempt). Forward them to the agent loop (`prepareToolBatch` / `runToolBatch`
|
|
38
|
+
* `awaitingRequests`) so an unanswered approval stays pending even when its tool's policy
|
|
39
|
+
* changed. Absent on the first attempt of a batch.
|
|
40
|
+
*/
|
|
41
|
+
readonly awaitingRequests?: ReadonlyArray<unknown>;
|
|
35
42
|
readonly usage?: unknown;
|
|
36
43
|
readonly turn?: number;
|
|
37
44
|
readonly eventSequence?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow-loop.d.mts","names":[],"sources":["../src/workflow-loop.ts"],"mappings":";;;KAEY,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,
|
|
1
|
+
{"version":3,"file":"workflow-loop.d.mts","names":[],"sources":["../src/workflow-loop.ts"],"mappings":"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"}
|
package/dist/workflow-loop.mjs
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { Data, Predicate } from "effect";
|
|
2
2
|
//#region src/workflow-loop.ts
|
|
3
|
+
/** A resume carries the pause it resumes; the first attempt of a batch has none. */
|
|
4
|
+
const withAwaitingRequests = (base, awaitingRequests) => awaitingRequests === void 0 ? base : {
|
|
5
|
+
...base,
|
|
6
|
+
awaitingRequests
|
|
7
|
+
};
|
|
3
8
|
const WorkflowStepResult = Data.taggedEnum();
|
|
4
9
|
const VercelAgentWorkflowRunResult = Data.taggedEnum();
|
|
5
10
|
const defaultMaxWorkflowTurns = 500;
|
|
@@ -84,6 +89,7 @@ async function runVercelAgentWorkflow(config) {
|
|
|
84
89
|
}
|
|
85
90
|
let completedToolsResult;
|
|
86
91
|
const toolHitlResponses = [];
|
|
92
|
+
let toolAwaitingRequests;
|
|
87
93
|
let cumulativeUsage = modelResult.value.usage;
|
|
88
94
|
let toolEventSequence = modelResult.value.eventSequence ?? state.eventSequence;
|
|
89
95
|
const currentTurnState = (toolResult) => ({
|
|
@@ -95,7 +101,7 @@ async function runVercelAgentWorkflow(config) {
|
|
|
95
101
|
eventSequence: toolEventSequence
|
|
96
102
|
});
|
|
97
103
|
for (;;) {
|
|
98
|
-
const
|
|
104
|
+
const stepInput = withAwaitingRequests({
|
|
99
105
|
context: input.context,
|
|
100
106
|
request: input.request,
|
|
101
107
|
calls: modelResult.value.toolCalls,
|
|
@@ -104,7 +110,8 @@ async function runVercelAgentWorkflow(config) {
|
|
|
104
110
|
usage: cumulativeUsage,
|
|
105
111
|
turn: modelResult.value.turn,
|
|
106
112
|
eventSequence: toolEventSequence
|
|
107
|
-
}
|
|
113
|
+
}, toolAwaitingRequests);
|
|
114
|
+
const toolsResult = await settleWorkflowStep(retryWorkflowStep(() => runToolBatchStep(stepInput), toolBatchStepRetry));
|
|
108
115
|
if (Predicate.isTagged(toolsResult, "Failure")) {
|
|
109
116
|
await writeErrorSafely(writeError, toolsResult.error);
|
|
110
117
|
return VercelAgentWorkflowRunResult.ToolBatchStepFailed({
|
|
@@ -128,6 +135,7 @@ async function runVercelAgentWorkflow(config) {
|
|
|
128
135
|
break;
|
|
129
136
|
}
|
|
130
137
|
const awaitingInput = toolsResult.value.awaitingInput;
|
|
138
|
+
toolAwaitingRequests = awaitingInput.requests;
|
|
131
139
|
cumulativeUsage = toolsResult.value.usage ?? awaitingInput.usage ?? cumulativeUsage;
|
|
132
140
|
toolEventSequence = awaitingInput.eventSequence ?? toolEventSequence;
|
|
133
141
|
const hitlResponse = await settleWorkflowStep(retryWorkflowStep(() => {
|
|
@@ -1 +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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"}
|
|
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 /**\n * On a resume, the requests of the pause being resumed (`awaitingInput.requests` of the\n * previous attempt). Forward them to the agent loop (`prepareToolBatch` / `runToolBatch`\n * `awaitingRequests`) so an unanswered approval stays pending even when its tool's policy\n * changed. Absent on the first attempt of a batch.\n */\n readonly awaitingRequests?: ReadonlyArray<unknown>\n readonly usage?: unknown\n readonly turn?: number\n readonly eventSequence?: number\n}\n\n/** A resume carries the pause it resumes; the first attempt of a batch has none. */\nconst withAwaitingRequests = (\n base: VercelAgentWorkflowToolBatchStepInput,\n awaitingRequests: ReadonlyArray<unknown> | undefined\n): VercelAgentWorkflowToolBatchStepInput =>\n awaitingRequests === undefined ? base : { ...base, awaitingRequests }\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 toolAwaitingRequests: ReadonlyArray<unknown> | undefined\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 stepInput = withAwaitingRequests(\n {\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 toolAwaitingRequests\n )\n\n const toolsResult = await settleWorkflowStep(\n retryWorkflowStep(() => runToolBatchStep(stepInput), toolBatchStepRetry)\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 toolAwaitingRequests = awaitingInput.requests\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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"}
|
package/package.json
CHANGED
package/src/workflow-loop.ts
CHANGED
|
@@ -35,11 +35,25 @@ export type VercelAgentWorkflowToolBatchStepInput = {
|
|
|
35
35
|
readonly calls: ReadonlyArray<unknown>
|
|
36
36
|
readonly createdMessages: ReadonlyArray<unknown>
|
|
37
37
|
readonly hitlResponses?: ReadonlyArray<unknown>
|
|
38
|
+
/**
|
|
39
|
+
* On a resume, the requests of the pause being resumed (`awaitingInput.requests` of the
|
|
40
|
+
* previous attempt). Forward them to the agent loop (`prepareToolBatch` / `runToolBatch`
|
|
41
|
+
* `awaitingRequests`) so an unanswered approval stays pending even when its tool's policy
|
|
42
|
+
* changed. Absent on the first attempt of a batch.
|
|
43
|
+
*/
|
|
44
|
+
readonly awaitingRequests?: ReadonlyArray<unknown>
|
|
38
45
|
readonly usage?: unknown
|
|
39
46
|
readonly turn?: number
|
|
40
47
|
readonly eventSequence?: number
|
|
41
48
|
}
|
|
42
49
|
|
|
50
|
+
/** A resume carries the pause it resumes; the first attempt of a batch has none. */
|
|
51
|
+
const withAwaitingRequests = (
|
|
52
|
+
base: VercelAgentWorkflowToolBatchStepInput,
|
|
53
|
+
awaitingRequests: ReadonlyArray<unknown> | undefined
|
|
54
|
+
): VercelAgentWorkflowToolBatchStepInput =>
|
|
55
|
+
awaitingRequests === undefined ? base : { ...base, awaitingRequests }
|
|
56
|
+
|
|
43
57
|
export type VercelAgentWorkflowAwaitingInput = {
|
|
44
58
|
readonly hookToken: string
|
|
45
59
|
readonly requests: ReadonlyArray<unknown>
|
|
@@ -281,6 +295,7 @@ export async function runVercelAgentWorkflow(
|
|
|
281
295
|
|
|
282
296
|
let completedToolsResult: VercelAgentWorkflowToolBatchStepResult | undefined
|
|
283
297
|
const toolHitlResponses: Array<unknown> = []
|
|
298
|
+
let toolAwaitingRequests: ReadonlyArray<unknown> | undefined
|
|
284
299
|
let cumulativeUsage = modelResult.value.usage
|
|
285
300
|
let toolEventSequence = modelResult.value.eventSequence ?? state.eventSequence
|
|
286
301
|
|
|
@@ -299,21 +314,22 @@ export async function runVercelAgentWorkflow(
|
|
|
299
314
|
})
|
|
300
315
|
|
|
301
316
|
for (;;) {
|
|
317
|
+
const stepInput = withAwaitingRequests(
|
|
318
|
+
{
|
|
319
|
+
context: input.context,
|
|
320
|
+
request: input.request,
|
|
321
|
+
calls: modelResult.value.toolCalls,
|
|
322
|
+
createdMessages: modelResult.value.createdMessages,
|
|
323
|
+
hitlResponses: toolHitlResponses.slice(),
|
|
324
|
+
usage: cumulativeUsage,
|
|
325
|
+
turn: modelResult.value.turn,
|
|
326
|
+
eventSequence: toolEventSequence
|
|
327
|
+
},
|
|
328
|
+
toolAwaitingRequests
|
|
329
|
+
)
|
|
330
|
+
|
|
302
331
|
const toolsResult = await settleWorkflowStep(
|
|
303
|
-
retryWorkflowStep(
|
|
304
|
-
() =>
|
|
305
|
-
runToolBatchStep({
|
|
306
|
-
context: input.context,
|
|
307
|
-
request: input.request,
|
|
308
|
-
calls: modelResult.value.toolCalls,
|
|
309
|
-
createdMessages: modelResult.value.createdMessages,
|
|
310
|
-
hitlResponses: toolHitlResponses.slice(),
|
|
311
|
-
usage: cumulativeUsage,
|
|
312
|
-
turn: modelResult.value.turn,
|
|
313
|
-
eventSequence: toolEventSequence
|
|
314
|
-
}),
|
|
315
|
-
toolBatchStepRetry
|
|
316
|
-
)
|
|
332
|
+
retryWorkflowStep(() => runToolBatchStep(stepInput), toolBatchStepRetry)
|
|
317
333
|
)
|
|
318
334
|
|
|
319
335
|
if (Predicate.isTagged(toolsResult, 'Failure')) {
|
|
@@ -345,6 +361,7 @@ export async function runVercelAgentWorkflow(
|
|
|
345
361
|
}
|
|
346
362
|
|
|
347
363
|
const awaitingInput = toolsResult.value.awaitingInput
|
|
364
|
+
toolAwaitingRequests = awaitingInput.requests
|
|
348
365
|
cumulativeUsage = toolsResult.value.usage ?? awaitingInput.usage ?? cumulativeUsage
|
|
349
366
|
toolEventSequence = awaitingInput.eventSequence ?? toolEventSequence
|
|
350
367
|
|