@yolk-sdk/vercel-workflows 0.1.0-canary.27 → 0.1.0-canary.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -23,6 +23,7 @@ Import Workflow APIs from the package root:
23
23
 
24
24
  ```ts
25
25
  import {
26
+ commitThenWriteTerminalEvent,
26
27
  makeDurableAgentEventSequencerState,
27
28
  noWorkflowStepRetry,
28
29
  runVercelAgentWorkflow,
@@ -118,6 +119,37 @@ The id format is `${streamId}:${turn}:${eventSequence}`. Keep `eventSequence` in
118
119
  Resume route reads should use `startIndex` when available. Host apps still own active-run locking,
119
120
  stale-run guards, and cancellation behavior.
120
121
 
122
+ ## Terminal barriers
123
+
124
+ For durable host streams, terminal events are commit barriers. Emit live/progress events first,
125
+ commit canonical host state, then write the terminal event, then close the writer:
126
+
127
+ ```txt
128
+ live events -> host durable commit -> terminal event -> close
129
+ ```
130
+
131
+ This lets clients stop consuming at a protocol-terminal event and immediately revalidate or reconnect
132
+ from durable state. Hosts that emit terminal events before persistence should not rely on
133
+ `streamAgentEventsUntilTerminal()` as a durable-settled signal.
134
+
135
+ Use `commitThenWriteTerminalEvent` when a step must commit host state before writing its terminal
136
+ event:
137
+
138
+ ```ts
139
+ const result = await commitThenWriteTerminalEvent({
140
+ terminal,
141
+ commit: () => persistState(),
142
+ write: event => writeDurableAgentEvent({ writer, event, streamId, turn, state }),
143
+ writeCommitError: error =>
144
+ writeDurableAgentEvent({ writer, event: commitErrorEvent(error), streamId, turn, state }),
145
+ close: () => writer.close()
146
+ })
147
+ ```
148
+
149
+ The helper never writes the success terminal before `commit` succeeds. If `commit` fails, it writes
150
+ the host-provided terminal error event instead. Terminal write failures still attempt `close`; close
151
+ failures are returned separately and do not turn a successful durable commit into a failed commit.
152
+
121
153
  ## Host responsibilities
122
154
 
123
155
  - Own Next/Vercel routes, auth, providers, tools, persistence, and telemetry.
@@ -126,6 +158,7 @@ stale-run guards, and cancellation behavior.
126
158
  - Decide cancellation/resume/conflict UX.
127
159
  - Own hook tokens and response validation for HITL resume.
128
160
  - Emit replay-safe event ids for durable streams and de-dupe by `eventId` client-side.
161
+ - Write durable terminal events only after host persistence has settled.
129
162
  - Test directive behavior with `@workflow/vitest` when changing package-owned Workflow files.
130
163
 
131
164
  ## Boundaries
package/dist/index.d.mts CHANGED
@@ -1,3 +1,3 @@
1
1
  import { SerializableWorkflowState, VercelAgentWorkflowAwaitingInput, VercelAgentWorkflowInput, VercelAgentWorkflowLoopConfig, VercelAgentWorkflowModelStepInput, VercelAgentWorkflowModelStepResult, VercelAgentWorkflowRunResult, VercelAgentWorkflowStepRetryPolicy, VercelAgentWorkflowToolBatchStepInput, VercelAgentWorkflowToolBatchStepResult, WorkflowStepResult, defaultMaxWorkflowTurns, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, settleWorkflowStep } from "./workflow-loop.mjs";
2
- import { DurableAgentEvent, DurableAgentEventIdInput, DurableAgentEventSequencerState, SequenceDurableAgentEventInput, SequencedDurableAgentEvent, WriteDurableAgentEventInput, durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent } from "./workflow-events.mjs";
3
- export { type DurableAgentEvent, type DurableAgentEventIdInput, type DurableAgentEventSequencerState, type SequenceDurableAgentEventInput, type SequencedDurableAgentEvent, type SerializableWorkflowState, type VercelAgentWorkflowAwaitingInput, type VercelAgentWorkflowInput, type VercelAgentWorkflowLoopConfig, type VercelAgentWorkflowModelStepInput, type VercelAgentWorkflowModelStepResult, type VercelAgentWorkflowRunResult, type VercelAgentWorkflowStepRetryPolicy, type VercelAgentWorkflowToolBatchStepInput, type VercelAgentWorkflowToolBatchStepResult, type WorkflowStepResult, type WriteDurableAgentEventInput, defaultMaxWorkflowTurns, durableAgentEventId, makeDurableAgentEventSequencerState, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, sequenceDurableAgentEvent, settleWorkflowStep, writeDurableAgentEvent };
2
+ import { CommitThenWriteTerminalEventInput, CommitThenWriteTerminalEventResult, DurableAgentEvent, DurableAgentEventIdInput, DurableAgentEventSequencerState, SequenceDurableAgentEventInput, SequencedDurableAgentEvent, TerminalEventCloseResult, WriteDurableAgentEventInput, commitThenWriteTerminalEvent, durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent } from "./workflow-events.mjs";
3
+ export { type CommitThenWriteTerminalEventInput, type CommitThenWriteTerminalEventResult, type DurableAgentEvent, type DurableAgentEventIdInput, type DurableAgentEventSequencerState, type SequenceDurableAgentEventInput, type SequencedDurableAgentEvent, type SerializableWorkflowState, type TerminalEventCloseResult, type VercelAgentWorkflowAwaitingInput, type VercelAgentWorkflowInput, type VercelAgentWorkflowLoopConfig, type VercelAgentWorkflowModelStepInput, type VercelAgentWorkflowModelStepResult, type VercelAgentWorkflowRunResult, type VercelAgentWorkflowStepRetryPolicy, type VercelAgentWorkflowToolBatchStepInput, type VercelAgentWorkflowToolBatchStepResult, type WorkflowStepResult, type WriteDurableAgentEventInput, commitThenWriteTerminalEvent, defaultMaxWorkflowTurns, durableAgentEventId, makeDurableAgentEventSequencerState, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, sequenceDurableAgentEvent, settleWorkflowStep, writeDurableAgentEvent };
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
1
  import { defaultMaxWorkflowTurns, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, settleWorkflowStep } from "./workflow-loop.mjs";
2
- import { durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent } from "./workflow-events.mjs";
3
- export { defaultMaxWorkflowTurns, durableAgentEventId, makeDurableAgentEventSequencerState, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, sequenceDurableAgentEvent, settleWorkflowStep, writeDurableAgentEvent };
2
+ import { commitThenWriteTerminalEvent, durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent } from "./workflow-events.mjs";
3
+ export { commitThenWriteTerminalEvent, defaultMaxWorkflowTurns, durableAgentEventId, makeDurableAgentEventSequencerState, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, sequenceDurableAgentEvent, settleWorkflowStep, writeDurableAgentEvent };
@@ -27,10 +27,43 @@ type SequencedDurableAgentEvent<Event extends object = object> = {
27
27
  type WriteDurableAgentEventInput<Event extends object = object> = SequenceDurableAgentEventInput<Event> & {
28
28
  readonly writer: WritableStreamDefaultWriter<Uint8Array>;
29
29
  };
30
+ type TerminalEventCloseResult = {
31
+ readonly _tag: 'Closed';
32
+ } | {
33
+ readonly _tag: 'CloseFailed';
34
+ readonly error: unknown;
35
+ };
36
+ type CommitThenWriteTerminalEventInput<TerminalEvent extends object, TerminalWriteResult, CommitErrorWriteResult> = {
37
+ readonly commit: () => Promise<void>;
38
+ readonly terminal: TerminalEvent;
39
+ readonly write: (event: TerminalEvent) => Promise<TerminalWriteResult>;
40
+ readonly writeCommitError: (error: unknown) => Promise<CommitErrorWriteResult>;
41
+ readonly close: () => Promise<void>;
42
+ };
43
+ type CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult> = {
44
+ readonly _tag: 'Committed';
45
+ readonly writeResult: TerminalWriteResult;
46
+ readonly closeResult: TerminalEventCloseResult;
47
+ } | {
48
+ readonly _tag: 'CommitFailed';
49
+ readonly commitError: unknown;
50
+ readonly writeResult: CommitErrorWriteResult;
51
+ readonly closeResult: TerminalEventCloseResult;
52
+ } | {
53
+ readonly _tag: 'TerminalWriteFailed';
54
+ readonly error: unknown;
55
+ readonly closeResult: TerminalEventCloseResult;
56
+ } | {
57
+ readonly _tag: 'CommitErrorWriteFailed';
58
+ readonly commitError: unknown;
59
+ readonly error: unknown;
60
+ readonly closeResult: TerminalEventCloseResult;
61
+ };
30
62
  declare const makeDurableAgentEventSequencerState: (eventSequence?: number) => DurableAgentEventSequencerState;
31
63
  declare const durableAgentEventId: (input: DurableAgentEventIdInput) => string;
32
64
  declare const sequenceDurableAgentEvent: <Event extends object>(input: SequenceDurableAgentEventInput<Event>) => SequencedDurableAgentEvent<Event>;
33
65
  declare const writeDurableAgentEvent: <Event extends object>(input: WriteDurableAgentEventInput<Event>) => Promise<SequencedDurableAgentEvent<Event>>;
66
+ declare const commitThenWriteTerminalEvent: <TerminalEvent extends object, TerminalWriteResult, CommitErrorWriteResult>(input: CommitThenWriteTerminalEventInput<TerminalEvent, TerminalWriteResult, CommitErrorWriteResult>) => Promise<CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult>>;
34
67
  //#endregion
35
- export { DurableAgentEvent, DurableAgentEventIdInput, DurableAgentEventSequencerState, SequenceDurableAgentEventInput, SequencedDurableAgentEvent, WriteDurableAgentEventInput, durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent };
68
+ export { CommitThenWriteTerminalEventInput, CommitThenWriteTerminalEventResult, DurableAgentEvent, DurableAgentEventIdInput, DurableAgentEventSequencerState, SequenceDurableAgentEventInput, SequencedDurableAgentEvent, TerminalEventCloseResult, WriteDurableAgentEventInput, commitThenWriteTerminalEvent, durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent };
36
69
  //# sourceMappingURL=workflow-events.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-events.d.mts","names":[],"sources":["../src/workflow-events.ts"],"mappings":";KAAY,+BAAA;EAAA,SACD,aAAa;AAAA;AAAA,KAGZ,iBAAA,kCAAmD,KAAK;EAAA,SACzD,OAAA;EAAA,SACA,WAAA;AAAA;AAAA,KAGC,wBAAA;EAAA,SACD,QAAA;EAAA,SACA,IAAA;EAAA,SACA,aAAA;AAAA;AAAA,KAGC,8BAAA;EAAA,SACD,KAAA,EAAO,+BAAA;EAAA,SACP,QAAA;EAAA,SACA,IAAA;EAAA,SACA,KAAA,EAAO,KAAK;EAAA,SACZ,WAAA;AAAA;AAAA,KAGC,0BAAA;EAAA,SACD,KAAA,EAAO,iBAAA,CAAkB,KAAA;EAAA,SACzB,aAAA;EAAA,SACA,iBAAA;EAAA,SACA,SAAA,EAAW,+BAAA;AAAA;AAAA,KAGV,2BAAA,kCACV,8BAAA,CAA+B,KAAA;EAAA,SACpB,MAAA,EAAQ,2BAAA,CAA4B,UAAA;AAAA;AAAA,cAKpC,mCAAA,GACX,aAAA,cACC,+BAAsD;AAAA,cAE5C,mBAAA,GAAuB,KAA+B,EAAxB,wBAAwB;AAAA,cAGtD,yBAAA,yBACX,KAAA,EAAO,8BAAA,CAA+B,KAAA,MACrC,0BAAA,CAA2B,KAAA;AAAA,cA0BjB,sBAAA,yBACX,KAAA,EAAO,2BAAA,CAA4B,KAAA,MAClC,OAAA,CAAQ,0BAAA,CAA2B,KAAA"}
1
+ {"version":3,"file":"workflow-events.d.mts","names":[],"sources":["../src/workflow-events.ts"],"mappings":";KAAY,+BAAA;EAAA,SACD,aAAa;AAAA;AAAA,KAGZ,iBAAA,kCAAmD,KAAK;EAAA,SACzD,OAAA;EAAA,SACA,WAAA;AAAA;AAAA,KAGC,wBAAA;EAAA,SACD,QAAA;EAAA,SACA,IAAA;EAAA,SACA,aAAA;AAAA;AAAA,KAGC,8BAAA;EAAA,SACD,KAAA,EAAO,+BAAA;EAAA,SACP,QAAA;EAAA,SACA,IAAA;EAAA,SACA,KAAA,EAAO,KAAK;EAAA,SACZ,WAAA;AAAA;AAAA,KAGC,0BAAA;EAAA,SACD,KAAA,EAAO,iBAAA,CAAkB,KAAA;EAAA,SACzB,aAAA;EAAA,SACA,iBAAA;EAAA,SACA,SAAA,EAAW,+BAAA;AAAA;AAAA,KAGV,2BAAA,kCACV,8BAAA,CAA+B,KAAA;EAAA,SACpB,MAAA,EAAQ,2BAAA,CAA4B,UAAA;AAAA;AAAA,KAGrC,wBAAA;EAAA,SACG,IAAA;AAAA;EAAA,SACA,IAAA;EAAA,SAA8B,KAAA;AAAA;AAAA,KAEjC,iCAAA;EAAA,SAKD,MAAA,QAAc,OAAA;EAAA,SACd,QAAA,EAAU,aAAA;EAAA,SACV,KAAA,GAAQ,KAAA,EAAO,aAAA,KAAkB,OAAA,CAAQ,mBAAA;EAAA,SACzC,gBAAA,GAAmB,KAAA,cAAmB,OAAA,CAAQ,sBAAA;EAAA,SAC9C,KAAA,QAAa,OAAA;AAAA;AAAA,KAGZ,kCAAA;EAAA,SAEG,IAAA;EAAA,SACA,WAAA,EAAa,mBAAA;EAAA,SACb,WAAA,EAAa,wBAAA;AAAA;EAAA,SAGb,IAAA;EAAA,SACA,WAAA;EAAA,SACA,WAAA,EAAa,sBAAA;EAAA,SACb,WAAA,EAAa,wBAAA;AAAA;EAAA,SAGb,IAAA;EAAA,SACA,KAAA;EAAA,SACA,WAAA,EAAa,wBAAA;AAAA;EAAA,SAGb,IAAA;EAAA,SACA,WAAA;EAAA,SACA,KAAA;EAAA,SACA,WAAA,EAAa,wBAAA;AAAA;AAAA,cAKf,mCAAA,GACX,aAAA,cACC,+BAAsD;AAAA,cAE5C,mBAAA,GAAuB,KAA+B,EAAxB,wBAAwB;AAAA,cAGtD,yBAAA,yBACX,KAAA,EAAO,8BAAA,CAA+B,KAAA,MACrC,0BAAA,CAA2B,KAAA;AAAA,cA0BjB,sBAAA,yBACX,KAAA,EAAO,2BAAA,CAA4B,KAAA,MAClC,OAAA,CAAQ,0BAAA,CAA2B,KAAA;AAAA,cAmBzB,4BAAA,8EAKX,KAAA,EAAO,iCAAA,CACL,aAAA,EACA,mBAAA,EACA,sBAAA,MAED,OAAA,CAAQ,kCAAA,CAAmC,mBAAA,EAAqB,sBAAA"}
@@ -26,7 +26,52 @@ const writeDurableAgentEvent = async (input) => {
26
26
  await input.writer.write(encodeDurableAgentEventNdjson(sequenced.event));
27
27
  return sequenced;
28
28
  };
29
+ const closeTerminalEventWriter = async (close) => {
30
+ try {
31
+ await close();
32
+ return { _tag: "Closed" };
33
+ } catch (error) {
34
+ return {
35
+ _tag: "CloseFailed",
36
+ error
37
+ };
38
+ }
39
+ };
40
+ const commitThenWriteTerminalEvent = async (input) => {
41
+ try {
42
+ await input.commit();
43
+ } catch (commitError) {
44
+ try {
45
+ return {
46
+ _tag: "CommitFailed",
47
+ commitError,
48
+ writeResult: await input.writeCommitError(commitError),
49
+ closeResult: await closeTerminalEventWriter(input.close)
50
+ };
51
+ } catch (error) {
52
+ return {
53
+ _tag: "CommitErrorWriteFailed",
54
+ commitError,
55
+ error,
56
+ closeResult: await closeTerminalEventWriter(input.close)
57
+ };
58
+ }
59
+ }
60
+ try {
61
+ return {
62
+ _tag: "Committed",
63
+ writeResult: await input.write(input.terminal),
64
+ closeResult: await closeTerminalEventWriter(input.close)
65
+ };
66
+ } catch (error) {
67
+ return {
68
+ _tag: "TerminalWriteFailed",
69
+ error,
70
+ closeResult: await closeTerminalEventWriter(input.close)
71
+ };
72
+ }
73
+ };
29
74
  //#endregion
30
- export { durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent };
75
+ export { commitThenWriteTerminalEvent, durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent };
31
76
 
32
77
  //# sourceMappingURL=workflow-events.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"workflow-events.mjs","names":[],"sources":["../src/workflow-events.ts"],"sourcesContent":["export type DurableAgentEventSequencerState = {\n readonly eventSequence: number\n}\n\nexport type DurableAgentEvent<Event extends object = object> = Event & {\n readonly eventId: string\n readonly createdAtMs?: number\n}\n\nexport type DurableAgentEventIdInput = {\n readonly streamId: string\n readonly turn: number\n readonly eventSequence: number\n}\n\nexport type SequenceDurableAgentEventInput<Event extends object = object> = {\n readonly state: DurableAgentEventSequencerState\n readonly streamId: string\n readonly turn: number\n readonly event: Event\n readonly createdAtMs?: number\n}\n\nexport type SequencedDurableAgentEvent<Event extends object = object> = {\n readonly event: DurableAgentEvent<Event>\n readonly eventSequence: number\n readonly nextEventSequence: number\n readonly nextState: DurableAgentEventSequencerState\n}\n\nexport type WriteDurableAgentEventInput<Event extends object = object> =\n SequenceDurableAgentEventInput<Event> & {\n readonly writer: WritableStreamDefaultWriter<Uint8Array>\n }\n\nconst textEncoder = new TextEncoder()\n\nexport const makeDurableAgentEventSequencerState = (\n eventSequence = 0\n): DurableAgentEventSequencerState => ({ eventSequence })\n\nexport const durableAgentEventId = (input: DurableAgentEventIdInput) =>\n `${input.streamId}:${input.turn}:${input.eventSequence}`\n\nexport const sequenceDurableAgentEvent = <Event extends object>(\n input: SequenceDurableAgentEventInput<Event>\n): SequencedDurableAgentEvent<Event> => {\n const eventSequence = input.state.eventSequence\n const nextEventSequence = eventSequence + 1\n const event = {\n ...input.event,\n eventId: durableAgentEventId({\n streamId: input.streamId,\n turn: input.turn,\n eventSequence\n }),\n ...(input.createdAtMs === undefined ? {} : { createdAtMs: input.createdAtMs })\n }\n\n return {\n event,\n eventSequence,\n nextEventSequence,\n nextState: makeDurableAgentEventSequencerState(nextEventSequence)\n }\n}\n\nconst encodeDurableAgentEventNdjson = <Event extends object>(\n event: DurableAgentEvent<Event>\n) =>\n textEncoder.encode(`${JSON.stringify(event)}\\n`)\n\nexport const writeDurableAgentEvent = async <Event extends object>(\n input: WriteDurableAgentEventInput<Event>\n): Promise<SequencedDurableAgentEvent<Event>> => {\n const sequenced = sequenceDurableAgentEvent(input)\n await input.writer.write(encodeDurableAgentEventNdjson(sequenced.event))\n\n return sequenced\n}\n"],"mappings":";AAmCA,MAAM,cAAc,IAAI,YAAY;AAEpC,MAAa,uCACX,gBAAgB,OACqB,EAAE,cAAc;AAEvD,MAAa,uBAAuB,UAClC,GAAG,MAAM,SAAS,GAAG,MAAM,KAAK,GAAG,MAAM;AAE3C,MAAa,6BACX,UACsC;CACtC,MAAM,gBAAgB,MAAM,MAAM;CAClC,MAAM,oBAAoB,gBAAgB;CAW1C,OAAO;EACL,OAAA;GAVA,GAAG,MAAM;GACT,SAAS,oBAAoB;IAC3B,UAAU,MAAM;IAChB,MAAM,MAAM;IACZ;GACF,CAAC;GACD,GAAI,MAAM,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,aAAa,MAAM,YAAY;EAIxE;EACJ;EACA;EACA,WAAW,oCAAoC,iBAAiB;CAClE;AACF;AAEA,MAAM,iCACJ,UAEA,YAAY,OAAO,GAAG,KAAK,UAAU,KAAK,EAAE,GAAG;AAEjD,MAAa,yBAAyB,OACpC,UAC+C;CAC/C,MAAM,YAAY,0BAA0B,KAAK;CACjD,MAAM,MAAM,OAAO,MAAM,8BAA8B,UAAU,KAAK,CAAC;CAEvE,OAAO;AACT"}
1
+ {"version":3,"file":"workflow-events.mjs","names":[],"sources":["../src/workflow-events.ts"],"sourcesContent":["export type DurableAgentEventSequencerState = {\n readonly eventSequence: number\n}\n\nexport type DurableAgentEvent<Event extends object = object> = Event & {\n readonly eventId: string\n readonly createdAtMs?: number\n}\n\nexport type DurableAgentEventIdInput = {\n readonly streamId: string\n readonly turn: number\n readonly eventSequence: number\n}\n\nexport type SequenceDurableAgentEventInput<Event extends object = object> = {\n readonly state: DurableAgentEventSequencerState\n readonly streamId: string\n readonly turn: number\n readonly event: Event\n readonly createdAtMs?: number\n}\n\nexport type SequencedDurableAgentEvent<Event extends object = object> = {\n readonly event: DurableAgentEvent<Event>\n readonly eventSequence: number\n readonly nextEventSequence: number\n readonly nextState: DurableAgentEventSequencerState\n}\n\nexport type WriteDurableAgentEventInput<Event extends object = object> =\n SequenceDurableAgentEventInput<Event> & {\n readonly writer: WritableStreamDefaultWriter<Uint8Array>\n }\n\nexport type TerminalEventCloseResult =\n | { readonly _tag: 'Closed' }\n | { readonly _tag: 'CloseFailed'; readonly error: unknown }\n\nexport type CommitThenWriteTerminalEventInput<\n TerminalEvent extends object,\n TerminalWriteResult,\n CommitErrorWriteResult\n> = {\n readonly commit: () => Promise<void>\n readonly terminal: TerminalEvent\n readonly write: (event: TerminalEvent) => Promise<TerminalWriteResult>\n readonly writeCommitError: (error: unknown) => Promise<CommitErrorWriteResult>\n readonly close: () => Promise<void>\n}\n\nexport type CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult> =\n | {\n readonly _tag: 'Committed'\n readonly writeResult: TerminalWriteResult\n readonly closeResult: TerminalEventCloseResult\n }\n | {\n readonly _tag: 'CommitFailed'\n readonly commitError: unknown\n readonly writeResult: CommitErrorWriteResult\n readonly closeResult: TerminalEventCloseResult\n }\n | {\n readonly _tag: 'TerminalWriteFailed'\n readonly error: unknown\n readonly closeResult: TerminalEventCloseResult\n }\n | {\n readonly _tag: 'CommitErrorWriteFailed'\n readonly commitError: unknown\n readonly error: unknown\n readonly closeResult: TerminalEventCloseResult\n }\n\nconst textEncoder = new TextEncoder()\n\nexport const makeDurableAgentEventSequencerState = (\n eventSequence = 0\n): DurableAgentEventSequencerState => ({ eventSequence })\n\nexport const durableAgentEventId = (input: DurableAgentEventIdInput) =>\n `${input.streamId}:${input.turn}:${input.eventSequence}`\n\nexport const sequenceDurableAgentEvent = <Event extends object>(\n input: SequenceDurableAgentEventInput<Event>\n): SequencedDurableAgentEvent<Event> => {\n const eventSequence = input.state.eventSequence\n const nextEventSequence = eventSequence + 1\n const event = {\n ...input.event,\n eventId: durableAgentEventId({\n streamId: input.streamId,\n turn: input.turn,\n eventSequence\n }),\n ...(input.createdAtMs === undefined ? {} : { createdAtMs: input.createdAtMs })\n }\n\n return {\n event,\n eventSequence,\n nextEventSequence,\n nextState: makeDurableAgentEventSequencerState(nextEventSequence)\n }\n}\n\nconst encodeDurableAgentEventNdjson = <Event extends object>(\n event: DurableAgentEvent<Event>\n) =>\n textEncoder.encode(`${JSON.stringify(event)}\\n`)\n\nexport const writeDurableAgentEvent = async <Event extends object>(\n input: WriteDurableAgentEventInput<Event>\n): Promise<SequencedDurableAgentEvent<Event>> => {\n const sequenced = sequenceDurableAgentEvent(input)\n await input.writer.write(encodeDurableAgentEventNdjson(sequenced.event))\n\n return sequenced\n}\n\nconst closeTerminalEventWriter = async (\n close: () => Promise<void>\n): Promise<TerminalEventCloseResult> => {\n try {\n await close()\n\n return { _tag: 'Closed' }\n } catch (error) {\n return { _tag: 'CloseFailed', error }\n }\n}\n\nexport const commitThenWriteTerminalEvent = async <\n TerminalEvent extends object,\n TerminalWriteResult,\n CommitErrorWriteResult\n>(\n input: CommitThenWriteTerminalEventInput<\n TerminalEvent,\n TerminalWriteResult,\n CommitErrorWriteResult\n >\n): Promise<CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult>> => {\n try {\n await input.commit()\n } catch (commitError) {\n try {\n const writeResult = await input.writeCommitError(commitError)\n const closeResult = await closeTerminalEventWriter(input.close)\n\n return { _tag: 'CommitFailed', commitError, writeResult, closeResult }\n } catch (error) {\n const closeResult = await closeTerminalEventWriter(input.close)\n\n return { _tag: 'CommitErrorWriteFailed', commitError, error, closeResult }\n }\n }\n\n try {\n const writeResult = await input.write(input.terminal)\n const closeResult = await closeTerminalEventWriter(input.close)\n\n return { _tag: 'Committed', writeResult, closeResult }\n } catch (error) {\n const closeResult = await closeTerminalEventWriter(input.close)\n\n return { _tag: 'TerminalWriteFailed', error, closeResult }\n }\n}\n"],"mappings":";AA2EA,MAAM,cAAc,IAAI,YAAY;AAEpC,MAAa,uCACX,gBAAgB,OACqB,EAAE,cAAc;AAEvD,MAAa,uBAAuB,UAClC,GAAG,MAAM,SAAS,GAAG,MAAM,KAAK,GAAG,MAAM;AAE3C,MAAa,6BACX,UACsC;CACtC,MAAM,gBAAgB,MAAM,MAAM;CAClC,MAAM,oBAAoB,gBAAgB;CAW1C,OAAO;EACL,OAAA;GAVA,GAAG,MAAM;GACT,SAAS,oBAAoB;IAC3B,UAAU,MAAM;IAChB,MAAM,MAAM;IACZ;GACF,CAAC;GACD,GAAI,MAAM,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,aAAa,MAAM,YAAY;EAIxE;EACJ;EACA;EACA,WAAW,oCAAoC,iBAAiB;CAClE;AACF;AAEA,MAAM,iCACJ,UAEA,YAAY,OAAO,GAAG,KAAK,UAAU,KAAK,EAAE,GAAG;AAEjD,MAAa,yBAAyB,OACpC,UAC+C;CAC/C,MAAM,YAAY,0BAA0B,KAAK;CACjD,MAAM,MAAM,OAAO,MAAM,8BAA8B,UAAU,KAAK,CAAC;CAEvE,OAAO;AACT;AAEA,MAAM,2BAA2B,OAC/B,UACsC;CACtC,IAAI;EACF,MAAM,MAAM;EAEZ,OAAO,EAAE,MAAM,SAAS;CAC1B,SAAS,OAAO;EACd,OAAO;GAAE,MAAM;GAAe;EAAM;CACtC;AACF;AAEA,MAAa,+BAA+B,OAK1C,UAK6F;CAC7F,IAAI;EACF,MAAM,MAAM,OAAO;CACrB,SAAS,aAAa;EACpB,IAAI;GAIF,OAAO;IAAE,MAAM;IAAgB;IAAa,aAAA,MAHlB,MAAM,iBAAiB,WAAW;IAGH,aAAA,MAF/B,yBAAyB,MAAM,KAAK;GAEO;EACvE,SAAS,OAAO;GAGd,OAAO;IAAE,MAAM;IAA0B;IAAa;IAAO,aAAA,MAFnC,yBAAyB,MAAM,KAAK;GAEW;EAC3E;CACF;CAEA,IAAI;EAIF,OAAO;GAAE,MAAM;GAAa,aAAA,MAHF,MAAM,MAAM,MAAM,QAAQ;GAGX,aAAA,MAFf,yBAAyB,MAAM,KAAK;EAET;CACvD,SAAS,OAAO;EAGd,OAAO;GAAE,MAAM;GAAuB;GAAO,aAAA,MAFnB,yBAAyB,MAAM,KAAK;EAEL;CAC3D;AACF"}
@@ -1,3 +1,3 @@
1
1
  import { SerializableWorkflowState, VercelAgentWorkflowAwaitingInput, VercelAgentWorkflowInput, VercelAgentWorkflowLoopConfig, VercelAgentWorkflowModelStepInput, VercelAgentWorkflowModelStepResult, VercelAgentWorkflowRunResult, VercelAgentWorkflowStepRetryPolicy, VercelAgentWorkflowToolBatchStepInput, VercelAgentWorkflowToolBatchStepResult, WorkflowStepResult, defaultMaxWorkflowTurns, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, settleWorkflowStep } from "./workflow-loop.mjs";
2
- import { DurableAgentEvent, DurableAgentEventIdInput, DurableAgentEventSequencerState, SequenceDurableAgentEventInput, SequencedDurableAgentEvent, WriteDurableAgentEventInput, durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent } from "./workflow-events.mjs";
3
- export { type DurableAgentEvent, type DurableAgentEventIdInput, type DurableAgentEventSequencerState, type SequenceDurableAgentEventInput, type SequencedDurableAgentEvent, type SerializableWorkflowState, type VercelAgentWorkflowAwaitingInput, type VercelAgentWorkflowInput, type VercelAgentWorkflowLoopConfig, type VercelAgentWorkflowModelStepInput, type VercelAgentWorkflowModelStepResult, type VercelAgentWorkflowRunResult, type VercelAgentWorkflowStepRetryPolicy, type VercelAgentWorkflowToolBatchStepInput, type VercelAgentWorkflowToolBatchStepResult, type WorkflowStepResult, type WriteDurableAgentEventInput, defaultMaxWorkflowTurns, durableAgentEventId, makeDurableAgentEventSequencerState, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, sequenceDurableAgentEvent, settleWorkflowStep, writeDurableAgentEvent };
2
+ import { CommitThenWriteTerminalEventInput, CommitThenWriteTerminalEventResult, DurableAgentEvent, DurableAgentEventIdInput, DurableAgentEventSequencerState, SequenceDurableAgentEventInput, SequencedDurableAgentEvent, TerminalEventCloseResult, WriteDurableAgentEventInput, commitThenWriteTerminalEvent, durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent } from "./workflow-events.mjs";
3
+ export { type CommitThenWriteTerminalEventInput, type CommitThenWriteTerminalEventResult, type DurableAgentEvent, type DurableAgentEventIdInput, type DurableAgentEventSequencerState, type SequenceDurableAgentEventInput, type SequencedDurableAgentEvent, type SerializableWorkflowState, type TerminalEventCloseResult, type VercelAgentWorkflowAwaitingInput, type VercelAgentWorkflowInput, type VercelAgentWorkflowLoopConfig, type VercelAgentWorkflowModelStepInput, type VercelAgentWorkflowModelStepResult, type VercelAgentWorkflowRunResult, type VercelAgentWorkflowStepRetryPolicy, type VercelAgentWorkflowToolBatchStepInput, type VercelAgentWorkflowToolBatchStepResult, type WorkflowStepResult, type WriteDurableAgentEventInput, commitThenWriteTerminalEvent, defaultMaxWorkflowTurns, durableAgentEventId, makeDurableAgentEventSequencerState, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, sequenceDurableAgentEvent, settleWorkflowStep, writeDurableAgentEvent };
package/dist/workflow.mjs CHANGED
@@ -1,3 +1,3 @@
1
1
  import { defaultMaxWorkflowTurns, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, settleWorkflowStep } from "./workflow-loop.mjs";
2
- import { durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent } from "./workflow-events.mjs";
3
- export { defaultMaxWorkflowTurns, durableAgentEventId, makeDurableAgentEventSequencerState, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, sequenceDurableAgentEvent, settleWorkflowStep, writeDurableAgentEvent };
2
+ import { commitThenWriteTerminalEvent, durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent } from "./workflow-events.mjs";
3
+ export { commitThenWriteTerminalEvent, defaultMaxWorkflowTurns, durableAgentEventId, makeDurableAgentEventSequencerState, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, sequenceDurableAgentEvent, settleWorkflowStep, writeDurableAgentEvent };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yolk-sdk/vercel-workflows",
3
- "version": "0.1.0-canary.27",
3
+ "version": "0.1.0-canary.29",
4
4
  "description": "Vercel Workflow orchestration primitives for Yolk agent loops.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export {
2
+ commitThenWriteTerminalEvent,
2
3
  durableAgentEventId,
3
4
  defaultMaxWorkflowTurns,
4
5
  makeDurableAgentEventSequencerState,
@@ -10,6 +11,8 @@ export {
10
11
  writeDurableAgentEvent
11
12
  } from './workflow.ts'
12
13
  export type {
14
+ CommitThenWriteTerminalEventInput,
15
+ CommitThenWriteTerminalEventResult,
13
16
  DurableAgentEvent,
14
17
  DurableAgentEventIdInput,
15
18
  DurableAgentEventSequencerState,
@@ -25,6 +28,7 @@ export type {
25
28
  VercelAgentWorkflowStepRetryPolicy,
26
29
  VercelAgentWorkflowToolBatchStepInput,
27
30
  VercelAgentWorkflowToolBatchStepResult,
31
+ TerminalEventCloseResult,
28
32
  WorkflowStepResult,
29
33
  WriteDurableAgentEventInput
30
34
  } from './workflow.ts'
@@ -33,6 +33,46 @@ export type WriteDurableAgentEventInput<Event extends object = object> =
33
33
  readonly writer: WritableStreamDefaultWriter<Uint8Array>
34
34
  }
35
35
 
36
+ export type TerminalEventCloseResult =
37
+ | { readonly _tag: 'Closed' }
38
+ | { readonly _tag: 'CloseFailed'; readonly error: unknown }
39
+
40
+ export type CommitThenWriteTerminalEventInput<
41
+ TerminalEvent extends object,
42
+ TerminalWriteResult,
43
+ CommitErrorWriteResult
44
+ > = {
45
+ readonly commit: () => Promise<void>
46
+ readonly terminal: TerminalEvent
47
+ readonly write: (event: TerminalEvent) => Promise<TerminalWriteResult>
48
+ readonly writeCommitError: (error: unknown) => Promise<CommitErrorWriteResult>
49
+ readonly close: () => Promise<void>
50
+ }
51
+
52
+ export type CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult> =
53
+ | {
54
+ readonly _tag: 'Committed'
55
+ readonly writeResult: TerminalWriteResult
56
+ readonly closeResult: TerminalEventCloseResult
57
+ }
58
+ | {
59
+ readonly _tag: 'CommitFailed'
60
+ readonly commitError: unknown
61
+ readonly writeResult: CommitErrorWriteResult
62
+ readonly closeResult: TerminalEventCloseResult
63
+ }
64
+ | {
65
+ readonly _tag: 'TerminalWriteFailed'
66
+ readonly error: unknown
67
+ readonly closeResult: TerminalEventCloseResult
68
+ }
69
+ | {
70
+ readonly _tag: 'CommitErrorWriteFailed'
71
+ readonly commitError: unknown
72
+ readonly error: unknown
73
+ readonly closeResult: TerminalEventCloseResult
74
+ }
75
+
36
76
  const textEncoder = new TextEncoder()
37
77
 
38
78
  export const makeDurableAgentEventSequencerState = (
@@ -78,3 +118,53 @@ export const writeDurableAgentEvent = async <Event extends object>(
78
118
 
79
119
  return sequenced
80
120
  }
121
+
122
+ const closeTerminalEventWriter = async (
123
+ close: () => Promise<void>
124
+ ): Promise<TerminalEventCloseResult> => {
125
+ try {
126
+ await close()
127
+
128
+ return { _tag: 'Closed' }
129
+ } catch (error) {
130
+ return { _tag: 'CloseFailed', error }
131
+ }
132
+ }
133
+
134
+ export const commitThenWriteTerminalEvent = async <
135
+ TerminalEvent extends object,
136
+ TerminalWriteResult,
137
+ CommitErrorWriteResult
138
+ >(
139
+ input: CommitThenWriteTerminalEventInput<
140
+ TerminalEvent,
141
+ TerminalWriteResult,
142
+ CommitErrorWriteResult
143
+ >
144
+ ): Promise<CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult>> => {
145
+ try {
146
+ await input.commit()
147
+ } catch (commitError) {
148
+ try {
149
+ const writeResult = await input.writeCommitError(commitError)
150
+ const closeResult = await closeTerminalEventWriter(input.close)
151
+
152
+ return { _tag: 'CommitFailed', commitError, writeResult, closeResult }
153
+ } catch (error) {
154
+ const closeResult = await closeTerminalEventWriter(input.close)
155
+
156
+ return { _tag: 'CommitErrorWriteFailed', commitError, error, closeResult }
157
+ }
158
+ }
159
+
160
+ try {
161
+ const writeResult = await input.write(input.terminal)
162
+ const closeResult = await closeTerminalEventWriter(input.close)
163
+
164
+ return { _tag: 'Committed', writeResult, closeResult }
165
+ } catch (error) {
166
+ const closeResult = await closeTerminalEventWriter(input.close)
167
+
168
+ return { _tag: 'TerminalWriteFailed', error, closeResult }
169
+ }
170
+ }
package/src/workflow.ts CHANGED
@@ -6,6 +6,7 @@ export {
6
6
  settleWorkflowStep
7
7
  } from './workflow-loop.ts'
8
8
  export {
9
+ commitThenWriteTerminalEvent,
9
10
  durableAgentEventId,
10
11
  makeDurableAgentEventSequencerState,
11
12
  sequenceDurableAgentEvent,
@@ -28,7 +29,10 @@ export type {
28
29
  DurableAgentEvent,
29
30
  DurableAgentEventIdInput,
30
31
  DurableAgentEventSequencerState,
32
+ CommitThenWriteTerminalEventInput,
33
+ CommitThenWriteTerminalEventResult,
31
34
  SequenceDurableAgentEventInput,
32
35
  SequencedDurableAgentEvent,
36
+ TerminalEventCloseResult,
33
37
  WriteDurableAgentEventInput
34
38
  } from './workflow-events.ts'