@yolk-sdk/vercel-workflows 0.1.0-canary.38 → 0.1.0-canary.39

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
@@ -25,10 +25,12 @@ Import Workflow APIs from the package root:
25
25
  ```ts
26
26
  import {
27
27
  commitThenWriteTerminalEvent,
28
+ commitThenWriteTerminalEventEffect,
28
29
  makeDurableAgentEventSequencerState,
29
30
  noWorkflowStepRetry,
30
31
  runVercelAgentWorkflow,
31
- writeDurableAgentEvent
32
+ writeDurableAgentEvent,
33
+ writeDurableAgentEventEffect
32
34
  } from '@yolk-sdk/vercel-workflows'
33
35
  ```
34
36
 
@@ -125,7 +127,7 @@ const state = makeDurableAgentEventSequencerState(eventSequence)
125
127
  const sequenced = await writeDurableAgentEvent({
126
128
  writer,
127
129
  event,
128
- streamId: 'workflow',
130
+ streamId: `workflow:${runId}`,
129
131
  turn,
130
132
  state
131
133
  })
@@ -133,9 +135,14 @@ const sequenced = await writeDurableAgentEvent({
133
135
  eventSequence = sequenced.nextEventSequence
134
136
  ```
135
137
 
136
- The id format is `${streamId}:${turn}:${eventSequence}`. Keep `eventSequence` in Workflow state.
137
- Resume route reads should use `startIndex` when available. Host apps still own active-run locking,
138
- stale-run guards, and cancellation behavior.
138
+ The id format is `${streamId}:${turn}:${eventSequence}`. Scope `streamId` to one logical durable
139
+ run (for example `workflow:${runId}`), not just one route or feature. Replay-safe clients de-dupe by
140
+ `eventId`; reusing a stream id across independent runs can make a follow-up run's live deltas look
141
+ like old replayed events. Keep `eventSequence` in Workflow state and reset it when starting a fresh
142
+ logical stream. Resume route reads should use `startIndex` when available. Host apps still own
143
+ active-run locking, stale-run guards, and cancellation behavior.
144
+
145
+ Use `writeDurableAgentEventEffect` when the writer path is already Effect-native.
139
146
 
140
147
  ## Terminal barriers
141
148
 
@@ -168,6 +175,8 @@ The helper never writes the success terminal before `commit` succeeds. If `commi
168
175
  the host-provided terminal error event instead. Terminal write failures still attempt `close`; close
169
176
  failures are returned separately and do not turn a successful durable commit into a failed commit.
170
177
 
178
+ Use `commitThenWriteTerminalEventEffect` for the same barrier with Effect callbacks.
179
+
171
180
  ## Host responsibilities
172
181
 
173
182
  - Own Next/Vercel routes, auth, providers, tools, persistence, and telemetry.
@@ -175,7 +184,8 @@ failures are returned separately and do not turn a successful durable commit int
175
184
  - Preserve tool result order and never advance the next model step with dangling host tool calls.
176
185
  - Decide cancellation/resume/conflict UX.
177
186
  - Own hook tokens and response validation for HITL resume.
178
- - Emit replay-safe event ids for durable streams and de-dupe by `eventId` client-side.
187
+ - Emit replay-safe event ids for durable streams; scope stream ids per independent run and de-dupe
188
+ by `eventId` client-side.
179
189
  - Write durable terminal events only after host persistence has settled.
180
190
  - Test directive behavior with `@workflow/vitest` when changing package-owned Workflow files.
181
191
 
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 { 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 };
2
+ import { CommitThenWriteTerminalEventEffectInput, CommitThenWriteTerminalEventInput, CommitThenWriteTerminalEventResult, DurableAgentEvent, DurableAgentEventIdInput, DurableAgentEventSequencerState, SequenceDurableAgentEventInput, SequencedDurableAgentEvent, TerminalEventCloseResult, WriteDurableAgentEventInput, commitThenWriteTerminalEvent, commitThenWriteTerminalEventEffect, durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent, writeDurableAgentEventEffect } from "./workflow-events.mjs";
3
+ export { type CommitThenWriteTerminalEventEffectInput, 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, commitThenWriteTerminalEventEffect, defaultMaxWorkflowTurns, durableAgentEventId, makeDurableAgentEventSequencerState, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, sequenceDurableAgentEvent, settleWorkflowStep, writeDurableAgentEvent, writeDurableAgentEventEffect };
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
1
  import { defaultMaxWorkflowTurns, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, settleWorkflowStep } from "./workflow-loop.mjs";
2
- import { commitThenWriteTerminalEvent, durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent } from "./workflow-events.mjs";
3
- export { commitThenWriteTerminalEvent, defaultMaxWorkflowTurns, durableAgentEventId, makeDurableAgentEventSequencerState, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, sequenceDurableAgentEvent, settleWorkflowStep, writeDurableAgentEvent };
2
+ import { commitThenWriteTerminalEvent, commitThenWriteTerminalEventEffect, durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent, writeDurableAgentEventEffect } from "./workflow-events.mjs";
3
+ export { commitThenWriteTerminalEvent, commitThenWriteTerminalEventEffect, defaultMaxWorkflowTurns, durableAgentEventId, makeDurableAgentEventSequencerState, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, sequenceDurableAgentEvent, settleWorkflowStep, writeDurableAgentEvent, writeDurableAgentEventEffect };
@@ -1,3 +1,5 @@
1
+ import { Effect } from "effect";
2
+
1
3
  //#region src/workflow-events.d.ts
2
4
  type DurableAgentEventSequencerState = {
3
5
  readonly eventSequence: number;
@@ -13,6 +15,13 @@ type DurableAgentEventIdInput = {
13
15
  };
14
16
  type SequenceDurableAgentEventInput<Event extends object = object> = {
15
17
  readonly state: DurableAgentEventSequencerState;
18
+ /**
19
+ * Stable id namespace for one independent durable stream.
20
+ *
21
+ * Include the workflow/session/run id when multiple logical runs can be
22
+ * projected in the same client. Replay-safe clients de-dupe by `eventId`, so
23
+ * reusing a stream id across runs can drop legitimate follow-up events.
24
+ */
16
25
  readonly streamId: string;
17
26
  readonly turn: number;
18
27
  readonly event: Event;
@@ -40,6 +49,13 @@ type CommitThenWriteTerminalEventInput<TerminalEvent extends object, TerminalWri
40
49
  readonly writeCommitError: (error: unknown) => Promise<CommitErrorWriteResult>;
41
50
  readonly close: () => Promise<void>;
42
51
  };
52
+ type CommitThenWriteTerminalEventEffectInput<TerminalEvent extends object, TerminalWriteResult, CommitErrorWriteResult, CommitError, TerminalWriteError, CommitErrorWriteError, CloseError> = {
53
+ readonly commit: Effect.Effect<void, CommitError>;
54
+ readonly terminal: TerminalEvent;
55
+ readonly write: (event: TerminalEvent) => Effect.Effect<TerminalWriteResult, TerminalWriteError>;
56
+ readonly writeCommitError: (error: unknown) => Effect.Effect<CommitErrorWriteResult, CommitErrorWriteError>;
57
+ readonly close: Effect.Effect<void, CloseError>;
58
+ };
43
59
  type CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult> = {
44
60
  readonly _tag: 'Committed';
45
61
  readonly writeResult: TerminalWriteResult;
@@ -62,8 +78,10 @@ type CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteRes
62
78
  declare const makeDurableAgentEventSequencerState: (eventSequence?: number) => DurableAgentEventSequencerState;
63
79
  declare const durableAgentEventId: (input: DurableAgentEventIdInput) => string;
64
80
  declare const sequenceDurableAgentEvent: <Event extends object>(input: SequenceDurableAgentEventInput<Event>) => SequencedDurableAgentEvent<Event>;
81
+ declare const writeDurableAgentEventEffect: <Event extends object>(input: WriteDurableAgentEventInput<Event>) => Effect.Effect<SequencedDurableAgentEvent<Event>, unknown>;
65
82
  declare const writeDurableAgentEvent: <Event extends object>(input: WriteDurableAgentEventInput<Event>) => Promise<SequencedDurableAgentEvent<Event>>;
83
+ declare const commitThenWriteTerminalEventEffect: <TerminalEvent extends object, TerminalWriteResult, CommitErrorWriteResult, CommitError, TerminalWriteError, CommitErrorWriteError, CloseError>(input: CommitThenWriteTerminalEventEffectInput<TerminalEvent, TerminalWriteResult, CommitErrorWriteResult, CommitError, TerminalWriteError, CommitErrorWriteError, CloseError>) => Effect.Effect<CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult>, never>;
66
84
  declare const commitThenWriteTerminalEvent: <TerminalEvent extends object, TerminalWriteResult, CommitErrorWriteResult>(input: CommitThenWriteTerminalEventInput<TerminalEvent, TerminalWriteResult, CommitErrorWriteResult>) => Promise<CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult>>;
67
85
  //#endregion
68
- export { CommitThenWriteTerminalEventInput, CommitThenWriteTerminalEventResult, DurableAgentEvent, DurableAgentEventIdInput, DurableAgentEventSequencerState, SequenceDurableAgentEventInput, SequencedDurableAgentEvent, TerminalEventCloseResult, WriteDurableAgentEventInput, commitThenWriteTerminalEvent, durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent };
86
+ export { CommitThenWriteTerminalEventEffectInput, CommitThenWriteTerminalEventInput, CommitThenWriteTerminalEventResult, DurableAgentEvent, DurableAgentEventIdInput, DurableAgentEventSequencerState, SequenceDurableAgentEventInput, SequencedDurableAgentEvent, TerminalEventCloseResult, WriteDurableAgentEventInput, commitThenWriteTerminalEvent, commitThenWriteTerminalEventEffect, durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent, writeDurableAgentEventEffect };
69
87
  //# 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,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,cAwBjB,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"}
1
+ {"version":3,"file":"workflow-events.d.mts","names":[],"sources":["../src/workflow-events.ts"],"mappings":";;;KAEY,+BAAA;EAAA,SACD,aAAa;AAAA;AAAA,KAGZ,iBAAA,kCAAmD,KAAK;EAAA,SACzD,OAAA;EAAA,SACA,WAAA;AAAA;AAAA,KAGC,wBAAA;EAAA,SACD,QAAA;EAAA,SACA,IAAA;EAAA,SACA,aAAA;AAAA;AAAA,KAGC,8BAAA;EAAA,SACD,KAAA,EAAO,+BAAA;EAVP;;AAAW;AAGtB;;;;EAHW,SAkBA,QAAA;EAAA,SACA,IAAA;EAAA,SACA,KAAA,EAAO,KAAK;EAAA,SACZ,WAAA;AAAA;AAAA,KAGC,0BAAA;EAAA,SACD,KAAA,EAAO,iBAAA,CAAkB,KAAA;EAAA,SACzB,aAAA;EAAA,SACA,iBAAA;EAAA,SACA,SAAA,EAAW,+BAAA;AAAA;AAAA,KAGV,2BAAA,kCACV,8BAAA,CAA+B,KAAA;EAAA,SACpB,MAAA,EAAQ,2BAAA,CAA4B,UAAA;AAAA;AAAA,KAGrC,wBAAA;EAAA,SACG,IAAA;AAAA;EAAA,SACA,IAAA;EAAA,SAA8B,KAAA;AAAA;AAAA,KAEjC,iCAAA;EAAA,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,uCAAA;EAAA,SASD,MAAA,EAAQ,MAAA,CAAO,MAAA,OAAa,WAAA;EAAA,SAC5B,QAAA,EAAU,aAAA;EAAA,SACV,KAAA,GAAQ,KAAA,EAAO,aAAA,KAAkB,MAAA,CAAO,MAAA,CAAO,mBAAA,EAAqB,kBAAA;EAAA,SACpE,gBAAA,GACP,KAAA,cACG,MAAA,CAAO,MAAA,CAAO,sBAAA,EAAwB,qBAAA;EAAA,SAClC,KAAA,EAAO,MAAA,CAAO,MAAA,OAAa,UAAA;AAAA;AAAA,KAG1B,kCAAA;EAAA,SAEG,IAAA;EAAA,SACA,WAAA,EAAa,mBAAA;EAAA,SACb,WAAA,EAAa,wBAAA;AAAA;EAAA,SAGb,IAAA;EAAA,SACA,WAAA;EAAA,SACA,WAAA,EAAa,sBAAA;EAAA,SACb,WAAA,EAAa,wBAAA;AAAA;EAAA,SAGb,IAAA;EAAA,SACA,KAAA;EAAA,SACA,WAAA,EAAa,wBAAA;AAAA;EAAA,SAGb,IAAA;EAAA,SACA,WAAA;EAAA,SACA,KAAA;EAAA,SACA,WAAA,EAAa,wBAAA;AAAA;AAAA,cAKf,mCAAA,GACX,aAAA,cACC,+BAAsD;AAAA,cAE5C,mBAAA,GAAuB,KAA+B,EAAxB,wBAAwB;AAAA,cAGtD,yBAAA,yBACX,KAAA,EAAO,8BAAA,CAA+B,KAAA,MACrC,0BAAA,CAA2B,KAAA;AAAA,cAwBjB,4BAAA,yBACX,KAAA,EAAO,2BAAA,CAA4B,KAAA,MAClC,MAAA,CAAO,MAAA,CAAO,0BAAA,CAA2B,KAAA;AAAA,cAW/B,sBAAA,yBACX,KAAA,EAAO,2BAAA,CAA4B,KAAA,MAClC,OAAA,CAAQ,0BAAA,CAA2B,KAAA;AAAA,cA4DzB,kCAAA,kJASX,KAAA,EAAO,uCAAA,CACL,aAAA,EACA,mBAAA,EACA,sBAAA,EACA,WAAA,EACA,kBAAA,EACA,qBAAA,EACA,UAAA,MAED,MAAA,CAAO,MAAA,CACR,kCAAA,CAAmC,mBAAA,EAAqB,sBAAA;AAAA,cAwD7C,4BAAA,8EAKX,KAAA,EAAO,iCAAA,CACL,aAAA,EACA,mBAAA,EACA,sBAAA,MAED,OAAA,CAAQ,kCAAA,CAAmC,mBAAA,EAAqB,sBAAA"}
@@ -1,3 +1,4 @@
1
+ import { Effect } from "effect";
1
2
  //#region src/workflow-events.ts
2
3
  const textEncoder = new TextEncoder();
3
4
  const makeDurableAgentEventSequencerState = (eventSequence = 0) => ({ eventSequence });
@@ -21,57 +22,76 @@ const sequenceDurableAgentEvent = (input) => {
21
22
  };
22
23
  };
23
24
  const encodeDurableAgentEventNdjson = (event) => textEncoder.encode(`${JSON.stringify(event)}\n`);
24
- const writeDurableAgentEvent = async (input) => {
25
+ const writeDurableAgentEventEffect = (input) => Effect.gen(function* () {
25
26
  const sequenced = sequenceDurableAgentEvent(input);
26
- await input.writer.write(encodeDurableAgentEventNdjson(sequenced.event));
27
+ yield* Effect.tryPromise({
28
+ try: () => input.writer.write(encodeDurableAgentEventNdjson(sequenced.event)),
29
+ catch: (cause) => cause
30
+ });
27
31
  return sequenced;
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
- };
32
+ });
33
+ const writeDurableAgentEvent = async (input) => Effect.runPromise(writeDurableAgentEventEffect(input));
34
+ const closedTerminalEventWriterResult = () => ({ _tag: "Closed" });
35
+ const closeFailedTerminalEventWriterResult = (error) => ({
36
+ _tag: "CloseFailed",
37
+ error
38
+ });
39
+ const committedTerminalResult = (writeResult, closeResult) => ({
40
+ _tag: "Committed",
41
+ writeResult,
42
+ closeResult
43
+ });
44
+ const commitFailedTerminalResult = (commitError, writeResult, closeResult) => ({
45
+ _tag: "CommitFailed",
46
+ commitError,
47
+ writeResult,
48
+ closeResult
49
+ });
50
+ const terminalWriteFailedResult = (error, closeResult) => ({
51
+ _tag: "TerminalWriteFailed",
52
+ error,
53
+ closeResult
54
+ });
55
+ const commitErrorWriteFailedResult = (commitError, error, closeResult) => ({
56
+ _tag: "CommitErrorWriteFailed",
57
+ commitError,
58
+ error,
59
+ closeResult
60
+ });
61
+ const closeTerminalEventWriterEffect = (close) => close.pipe(Effect.match({
62
+ onFailure: closeFailedTerminalEventWriterResult,
63
+ onSuccess: () => closedTerminalEventWriterResult()
64
+ }));
65
+ const commitThenWriteTerminalEventEffect = (input) => input.commit.pipe(Effect.matchEffect({
66
+ onFailure: (commitError) => input.writeCommitError(commitError).pipe(Effect.matchEffect({
67
+ onFailure: (error) => closeTerminalEventWriterEffect(input.close).pipe(Effect.map((closeResult) => commitErrorWriteFailedResult(commitError, error, closeResult))),
68
+ onSuccess: (writeResult) => closeTerminalEventWriterEffect(input.close).pipe(Effect.map((closeResult) => commitFailedTerminalResult(commitError, writeResult, closeResult)))
69
+ })),
70
+ onSuccess: () => input.write(input.terminal).pipe(Effect.matchEffect({
71
+ onFailure: (error) => closeTerminalEventWriterEffect(input.close).pipe(Effect.map((closeResult) => terminalWriteFailedResult(error, closeResult))),
72
+ onSuccess: (writeResult) => closeTerminalEventWriterEffect(input.close).pipe(Effect.map((closeResult) => committedTerminalResult(writeResult, closeResult)))
73
+ }))
74
+ }));
75
+ const commitThenWriteTerminalEvent = async (input) => Effect.runPromise(commitThenWriteTerminalEventEffect({
76
+ terminal: input.terminal,
77
+ commit: Effect.tryPromise({
78
+ try: input.commit,
79
+ catch: (cause) => cause
80
+ }),
81
+ write: (event) => Effect.tryPromise({
82
+ try: () => input.write(event),
83
+ catch: (cause) => cause
84
+ }),
85
+ writeCommitError: (error) => Effect.tryPromise({
86
+ try: () => input.writeCommitError(error),
87
+ catch: (cause) => cause
88
+ }),
89
+ close: Effect.tryPromise({
90
+ try: input.close,
91
+ catch: (cause) => cause
92
+ })
93
+ }));
74
94
  //#endregion
75
- export { commitThenWriteTerminalEvent, durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent };
95
+ export { commitThenWriteTerminalEvent, commitThenWriteTerminalEventEffect, durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent, writeDurableAgentEventEffect };
76
96
 
77
97
  //# 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\nexport type TerminalEventCloseResult =\n | { readonly _tag: 'Closed' }\n | { readonly _tag: 'CloseFailed'; readonly error: unknown }\n\nexport type CommitThenWriteTerminalEventInput<\n TerminalEvent extends object,\n TerminalWriteResult,\n CommitErrorWriteResult\n> = {\n readonly commit: () => Promise<void>\n readonly terminal: TerminalEvent\n readonly write: (event: TerminalEvent) => Promise<TerminalWriteResult>\n readonly writeCommitError: (error: unknown) => Promise<CommitErrorWriteResult>\n readonly close: () => Promise<void>\n}\n\nexport type CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult> =\n | {\n readonly _tag: 'Committed'\n readonly writeResult: TerminalWriteResult\n readonly closeResult: TerminalEventCloseResult\n }\n | {\n readonly _tag: 'CommitFailed'\n readonly commitError: unknown\n readonly writeResult: CommitErrorWriteResult\n readonly closeResult: TerminalEventCloseResult\n }\n | {\n readonly _tag: 'TerminalWriteFailed'\n readonly error: unknown\n readonly closeResult: TerminalEventCloseResult\n }\n | {\n readonly _tag: 'CommitErrorWriteFailed'\n readonly commitError: unknown\n readonly error: unknown\n readonly closeResult: TerminalEventCloseResult\n }\n\nconst textEncoder = new TextEncoder()\n\nexport const makeDurableAgentEventSequencerState = (\n eventSequence = 0\n): DurableAgentEventSequencerState => ({ eventSequence })\n\nexport const durableAgentEventId = (input: DurableAgentEventIdInput) =>\n `${input.streamId}:${input.turn}:${input.eventSequence}`\n\nexport const sequenceDurableAgentEvent = <Event extends object>(\n input: SequenceDurableAgentEventInput<Event>\n): SequencedDurableAgentEvent<Event> => {\n const eventSequence = input.state.eventSequence\n const nextEventSequence = eventSequence + 1\n const event = {\n ...input.event,\n eventId: durableAgentEventId({\n streamId: input.streamId,\n turn: input.turn,\n eventSequence\n }),\n ...(input.createdAtMs === undefined ? {} : { createdAtMs: input.createdAtMs })\n }\n\n return {\n event,\n eventSequence,\n nextEventSequence,\n nextState: makeDurableAgentEventSequencerState(nextEventSequence)\n }\n}\n\nconst encodeDurableAgentEventNdjson = <Event extends object>(event: DurableAgentEvent<Event>) =>\n textEncoder.encode(`${JSON.stringify(event)}\\n`)\n\nexport const writeDurableAgentEvent = async <Event extends object>(\n input: WriteDurableAgentEventInput<Event>\n): Promise<SequencedDurableAgentEvent<Event>> => {\n const sequenced = sequenceDurableAgentEvent(input)\n await input.writer.write(encodeDurableAgentEventNdjson(sequenced.event))\n\n return sequenced\n}\n\nconst closeTerminalEventWriter = async (\n close: () => Promise<void>\n): Promise<TerminalEventCloseResult> => {\n try {\n await close()\n\n return { _tag: 'Closed' }\n } catch (error) {\n return { _tag: 'CloseFailed', error }\n }\n}\n\nexport const commitThenWriteTerminalEvent = async <\n TerminalEvent extends object,\n TerminalWriteResult,\n CommitErrorWriteResult\n>(\n input: CommitThenWriteTerminalEventInput<\n TerminalEvent,\n TerminalWriteResult,\n CommitErrorWriteResult\n >\n): Promise<CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult>> => {\n try {\n await input.commit()\n } catch (commitError) {\n try {\n const writeResult = await input.writeCommitError(commitError)\n const closeResult = await closeTerminalEventWriter(input.close)\n\n return { _tag: 'CommitFailed', commitError, writeResult, closeResult }\n } catch (error) {\n const closeResult = await closeTerminalEventWriter(input.close)\n\n return { _tag: 'CommitErrorWriteFailed', commitError, error, closeResult }\n }\n }\n\n try {\n const writeResult = await input.write(input.terminal)\n const closeResult = await closeTerminalEventWriter(input.close)\n\n return { _tag: 'Committed', writeResult, closeResult }\n } catch (error) {\n const closeResult = await closeTerminalEventWriter(input.close)\n\n return { _tag: 'TerminalWriteFailed', error, closeResult }\n }\n}\n"],"mappings":";AA2EA,MAAM,cAAc,IAAI,YAAY;AAEpC,MAAa,uCACX,gBAAgB,OACqB,EAAE,cAAc;AAEvD,MAAa,uBAAuB,UAClC,GAAG,MAAM,SAAS,GAAG,MAAM,KAAK,GAAG,MAAM;AAE3C,MAAa,6BACX,UACsC;CACtC,MAAM,gBAAgB,MAAM,MAAM;CAClC,MAAM,oBAAoB,gBAAgB;CAW1C,OAAO;EACL,OAAA;GAVA,GAAG,MAAM;GACT,SAAS,oBAAoB;IAC3B,UAAU,MAAM;IAChB,MAAM,MAAM;IACZ;GACF,CAAC;GACD,GAAI,MAAM,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,aAAa,MAAM,YAAY;EAIxE;EACJ;EACA;EACA,WAAW,oCAAoC,iBAAiB;CAClE;AACF;AAEA,MAAM,iCAAuD,UAC3D,YAAY,OAAO,GAAG,KAAK,UAAU,KAAK,EAAE,GAAG;AAEjD,MAAa,yBAAyB,OACpC,UAC+C;CAC/C,MAAM,YAAY,0BAA0B,KAAK;CACjD,MAAM,MAAM,OAAO,MAAM,8BAA8B,UAAU,KAAK,CAAC;CAEvE,OAAO;AACT;AAEA,MAAM,2BAA2B,OAC/B,UACsC;CACtC,IAAI;EACF,MAAM,MAAM;EAEZ,OAAO,EAAE,MAAM,SAAS;CAC1B,SAAS,OAAO;EACd,OAAO;GAAE,MAAM;GAAe;EAAM;CACtC;AACF;AAEA,MAAa,+BAA+B,OAK1C,UAK6F;CAC7F,IAAI;EACF,MAAM,MAAM,OAAO;CACrB,SAAS,aAAa;EACpB,IAAI;GAIF,OAAO;IAAE,MAAM;IAAgB;IAAa,aAAA,MAHlB,MAAM,iBAAiB,WAAW;IAGH,aAAA,MAF/B,yBAAyB,MAAM,KAAK;GAEO;EACvE,SAAS,OAAO;GAGd,OAAO;IAAE,MAAM;IAA0B;IAAa;IAAO,aAAA,MAFnC,yBAAyB,MAAM,KAAK;GAEW;EAC3E;CACF;CAEA,IAAI;EAIF,OAAO;GAAE,MAAM;GAAa,aAAA,MAHF,MAAM,MAAM,MAAM,QAAQ;GAGX,aAAA,MAFf,yBAAyB,MAAM,KAAK;EAET;CACvD,SAAS,OAAO;EAGd,OAAO;GAAE,MAAM;GAAuB;GAAO,aAAA,MAFnB,yBAAyB,MAAM,KAAK;EAEL;CAC3D;AACF"}
1
+ {"version":3,"file":"workflow-events.mjs","names":[],"sources":["../src/workflow-events.ts"],"sourcesContent":["import { Effect } from 'effect'\n\nexport type DurableAgentEventSequencerState = {\n readonly eventSequence: number\n}\n\nexport type DurableAgentEvent<Event extends object = object> = Event & {\n readonly eventId: string\n readonly createdAtMs?: number\n}\n\nexport type DurableAgentEventIdInput = {\n readonly streamId: string\n readonly turn: number\n readonly eventSequence: number\n}\n\nexport type SequenceDurableAgentEventInput<Event extends object = object> = {\n readonly state: DurableAgentEventSequencerState\n /**\n * Stable id namespace for one independent durable stream.\n *\n * Include the workflow/session/run id when multiple logical runs can be\n * projected in the same client. Replay-safe clients de-dupe by `eventId`, so\n * reusing a stream id across runs can drop legitimate follow-up events.\n */\n readonly streamId: string\n readonly turn: number\n readonly event: Event\n readonly createdAtMs?: number\n}\n\nexport type SequencedDurableAgentEvent<Event extends object = object> = {\n readonly event: DurableAgentEvent<Event>\n readonly eventSequence: number\n readonly nextEventSequence: number\n readonly nextState: DurableAgentEventSequencerState\n}\n\nexport type WriteDurableAgentEventInput<Event extends object = object> =\n SequenceDurableAgentEventInput<Event> & {\n readonly writer: WritableStreamDefaultWriter<Uint8Array>\n }\n\nexport type TerminalEventCloseResult =\n | { readonly _tag: 'Closed' }\n | { readonly _tag: 'CloseFailed'; readonly error: unknown }\n\nexport type CommitThenWriteTerminalEventInput<\n TerminalEvent extends object,\n TerminalWriteResult,\n CommitErrorWriteResult\n> = {\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 CommitThenWriteTerminalEventEffectInput<\n TerminalEvent extends object,\n TerminalWriteResult,\n CommitErrorWriteResult,\n CommitError,\n TerminalWriteError,\n CommitErrorWriteError,\n CloseError\n> = {\n readonly commit: Effect.Effect<void, CommitError>\n readonly terminal: TerminalEvent\n readonly write: (event: TerminalEvent) => Effect.Effect<TerminalWriteResult, TerminalWriteError>\n readonly writeCommitError: (\n error: unknown\n ) => Effect.Effect<CommitErrorWriteResult, CommitErrorWriteError>\n readonly close: Effect.Effect<void, CloseError>\n}\n\nexport type CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult> =\n | {\n readonly _tag: 'Committed'\n readonly writeResult: TerminalWriteResult\n readonly closeResult: TerminalEventCloseResult\n }\n | {\n readonly _tag: 'CommitFailed'\n readonly commitError: unknown\n readonly writeResult: CommitErrorWriteResult\n readonly closeResult: TerminalEventCloseResult\n }\n | {\n readonly _tag: 'TerminalWriteFailed'\n readonly error: unknown\n readonly closeResult: TerminalEventCloseResult\n }\n | {\n readonly _tag: 'CommitErrorWriteFailed'\n readonly commitError: unknown\n readonly error: unknown\n readonly closeResult: TerminalEventCloseResult\n }\n\nconst textEncoder = new TextEncoder()\n\nexport const makeDurableAgentEventSequencerState = (\n eventSequence = 0\n): DurableAgentEventSequencerState => ({ eventSequence })\n\nexport const durableAgentEventId = (input: DurableAgentEventIdInput) =>\n `${input.streamId}:${input.turn}:${input.eventSequence}`\n\nexport const sequenceDurableAgentEvent = <Event extends object>(\n input: SequenceDurableAgentEventInput<Event>\n): SequencedDurableAgentEvent<Event> => {\n const eventSequence = input.state.eventSequence\n const nextEventSequence = eventSequence + 1\n const event = {\n ...input.event,\n eventId: durableAgentEventId({\n streamId: input.streamId,\n turn: input.turn,\n eventSequence\n }),\n ...(input.createdAtMs === undefined ? {} : { createdAtMs: input.createdAtMs })\n }\n\n return {\n event,\n eventSequence,\n nextEventSequence,\n nextState: makeDurableAgentEventSequencerState(nextEventSequence)\n }\n}\n\nconst encodeDurableAgentEventNdjson = <Event extends object>(event: DurableAgentEvent<Event>) =>\n textEncoder.encode(`${JSON.stringify(event)}\\n`)\n\nexport const writeDurableAgentEventEffect = <Event extends object>(\n input: WriteDurableAgentEventInput<Event>\n): Effect.Effect<SequencedDurableAgentEvent<Event>, unknown> =>\n Effect.gen(function* () {\n const sequenced = sequenceDurableAgentEvent(input)\n yield* Effect.tryPromise({\n try: () => input.writer.write(encodeDurableAgentEventNdjson(sequenced.event)),\n catch: cause => cause\n })\n\n return sequenced\n })\n\nexport const writeDurableAgentEvent = async <Event extends object>(\n input: WriteDurableAgentEventInput<Event>\n): Promise<SequencedDurableAgentEvent<Event>> =>\n Effect.runPromise(writeDurableAgentEventEffect(input))\n\nconst closedTerminalEventWriterResult = (): TerminalEventCloseResult => ({ _tag: 'Closed' })\n\nconst closeFailedTerminalEventWriterResult = (error: unknown): TerminalEventCloseResult => ({\n _tag: 'CloseFailed',\n error\n})\n\nconst committedTerminalResult = <TerminalWriteResult, CommitErrorWriteResult>(\n writeResult: TerminalWriteResult,\n closeResult: TerminalEventCloseResult\n): CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult> => ({\n _tag: 'Committed',\n writeResult,\n closeResult\n})\n\nconst commitFailedTerminalResult = <TerminalWriteResult, CommitErrorWriteResult>(\n commitError: unknown,\n writeResult: CommitErrorWriteResult,\n closeResult: TerminalEventCloseResult\n): CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult> => ({\n _tag: 'CommitFailed',\n commitError,\n writeResult,\n closeResult\n})\n\nconst terminalWriteFailedResult = <TerminalWriteResult, CommitErrorWriteResult>(\n error: unknown,\n closeResult: TerminalEventCloseResult\n): CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult> => ({\n _tag: 'TerminalWriteFailed',\n error,\n closeResult\n})\n\nconst commitErrorWriteFailedResult = <TerminalWriteResult, CommitErrorWriteResult>(\n commitError: unknown,\n error: unknown,\n closeResult: TerminalEventCloseResult\n): CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult> => ({\n _tag: 'CommitErrorWriteFailed',\n commitError,\n error,\n closeResult\n})\n\nconst closeTerminalEventWriterEffect = <CloseError>(\n close: Effect.Effect<void, CloseError>\n): Effect.Effect<TerminalEventCloseResult, never> =>\n close.pipe(\n Effect.match({\n onFailure: closeFailedTerminalEventWriterResult,\n onSuccess: () => closedTerminalEventWriterResult()\n })\n )\n\nexport const commitThenWriteTerminalEventEffect = <\n TerminalEvent extends object,\n TerminalWriteResult,\n CommitErrorWriteResult,\n CommitError,\n TerminalWriteError,\n CommitErrorWriteError,\n CloseError\n>(\n input: CommitThenWriteTerminalEventEffectInput<\n TerminalEvent,\n TerminalWriteResult,\n CommitErrorWriteResult,\n CommitError,\n TerminalWriteError,\n CommitErrorWriteError,\n CloseError\n >\n): Effect.Effect<\n CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult>,\n never\n> =>\n input.commit.pipe(\n Effect.matchEffect({\n onFailure: commitError =>\n input.writeCommitError(commitError).pipe(\n Effect.matchEffect({\n onFailure: error =>\n closeTerminalEventWriterEffect(input.close).pipe(\n Effect.map(closeResult =>\n commitErrorWriteFailedResult<TerminalWriteResult, CommitErrorWriteResult>(\n commitError,\n error,\n closeResult\n )\n )\n ),\n onSuccess: writeResult =>\n closeTerminalEventWriterEffect(input.close).pipe(\n Effect.map(closeResult =>\n commitFailedTerminalResult<TerminalWriteResult, CommitErrorWriteResult>(\n commitError,\n writeResult,\n closeResult\n )\n )\n )\n })\n ),\n onSuccess: () =>\n input.write(input.terminal).pipe(\n Effect.matchEffect({\n onFailure: error =>\n closeTerminalEventWriterEffect(input.close).pipe(\n Effect.map(closeResult =>\n terminalWriteFailedResult<TerminalWriteResult, CommitErrorWriteResult>(\n error,\n closeResult\n )\n )\n ),\n onSuccess: writeResult =>\n closeTerminalEventWriterEffect(input.close).pipe(\n Effect.map(closeResult =>\n committedTerminalResult<TerminalWriteResult, CommitErrorWriteResult>(\n writeResult,\n closeResult\n )\n )\n )\n })\n )\n })\n )\n\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 Effect.runPromise(\n commitThenWriteTerminalEventEffect({\n terminal: input.terminal,\n commit: Effect.tryPromise({\n try: input.commit,\n catch: cause => cause\n }),\n write: event =>\n Effect.tryPromise({\n try: () => input.write(event),\n catch: cause => cause\n }),\n writeCommitError: error =>\n Effect.tryPromise({\n try: () => input.writeCommitError(error),\n catch: cause => cause\n }),\n close: Effect.tryPromise({\n try: input.close,\n catch: cause => cause\n })\n })\n )\n"],"mappings":";;AAsGA,MAAM,cAAc,IAAI,YAAY;AAEpC,MAAa,uCACX,gBAAgB,OACqB,EAAE,cAAc;AAEvD,MAAa,uBAAuB,UAClC,GAAG,MAAM,SAAS,GAAG,MAAM,KAAK,GAAG,MAAM;AAE3C,MAAa,6BACX,UACsC;CACtC,MAAM,gBAAgB,MAAM,MAAM;CAClC,MAAM,oBAAoB,gBAAgB;CAW1C,OAAO;EACL,OAAA;GAVA,GAAG,MAAM;GACT,SAAS,oBAAoB;IAC3B,UAAU,MAAM;IAChB,MAAM,MAAM;IACZ;GACF,CAAC;GACD,GAAI,MAAM,gBAAgB,KAAA,IAAY,CAAC,IAAI,EAAE,aAAa,MAAM,YAAY;EAIxE;EACJ;EACA;EACA,WAAW,oCAAoC,iBAAiB;CAClE;AACF;AAEA,MAAM,iCAAuD,UAC3D,YAAY,OAAO,GAAG,KAAK,UAAU,KAAK,EAAE,GAAG;AAEjD,MAAa,gCACX,UAEA,OAAO,IAAI,aAAa;CACtB,MAAM,YAAY,0BAA0B,KAAK;CACjD,OAAO,OAAO,WAAW;EACvB,WAAW,MAAM,OAAO,MAAM,8BAA8B,UAAU,KAAK,CAAC;EAC5E,QAAO,UAAS;CAClB,CAAC;CAED,OAAO;AACT,CAAC;AAEH,MAAa,yBAAyB,OACpC,UAEA,OAAO,WAAW,6BAA6B,KAAK,CAAC;AAEvD,MAAM,yCAAmE,EAAE,MAAM,SAAS;AAE1F,MAAM,wCAAwC,WAA8C;CAC1F,MAAM;CACN;AACF;AAEA,MAAM,2BACJ,aACA,iBACqF;CACrF,MAAM;CACN;CACA;AACF;AAEA,MAAM,8BACJ,aACA,aACA,iBACqF;CACrF,MAAM;CACN;CACA;CACA;AACF;AAEA,MAAM,6BACJ,OACA,iBACqF;CACrF,MAAM;CACN;CACA;AACF;AAEA,MAAM,gCACJ,aACA,OACA,iBACqF;CACrF,MAAM;CACN;CACA;CACA;AACF;AAEA,MAAM,kCACJ,UAEA,MAAM,KACJ,OAAO,MAAM;CACX,WAAW;CACX,iBAAiB,gCAAgC;AACnD,CAAC,CACH;AAEF,MAAa,sCASX,UAaA,MAAM,OAAO,KACX,OAAO,YAAY;CACjB,YAAW,gBACT,MAAM,iBAAiB,WAAW,EAAE,KAClC,OAAO,YAAY;EACjB,YAAW,UACT,+BAA+B,MAAM,KAAK,EAAE,KAC1C,OAAO,KAAI,gBACT,6BACE,aACA,OACA,WACF,CACF,CACF;EACF,YAAW,gBACT,+BAA+B,MAAM,KAAK,EAAE,KAC1C,OAAO,KAAI,gBACT,2BACE,aACA,aACA,WACF,CACF,CACF;CACJ,CAAC,CACH;CACF,iBACE,MAAM,MAAM,MAAM,QAAQ,EAAE,KAC1B,OAAO,YAAY;EACjB,YAAW,UACT,+BAA+B,MAAM,KAAK,EAAE,KAC1C,OAAO,KAAI,gBACT,0BACE,OACA,WACF,CACF,CACF;EACF,YAAW,gBACT,+BAA+B,MAAM,KAAK,EAAE,KAC1C,OAAO,KAAI,gBACT,wBACE,aACA,WACF,CACF,CACF;CACJ,CAAC,CACH;AACJ,CAAC,CACH;AAEF,MAAa,+BAA+B,OAK1C,UAMA,OAAO,WACL,mCAAmC;CACjC,UAAU,MAAM;CAChB,QAAQ,OAAO,WAAW;EACxB,KAAK,MAAM;EACX,QAAO,UAAS;CAClB,CAAC;CACD,QAAO,UACL,OAAO,WAAW;EAChB,WAAW,MAAM,MAAM,KAAK;EAC5B,QAAO,UAAS;CAClB,CAAC;CACH,mBAAkB,UAChB,OAAO,WAAW;EAChB,WAAW,MAAM,iBAAiB,KAAK;EACvC,QAAO,UAAS;CAClB,CAAC;CACH,OAAO,OAAO,WAAW;EACvB,KAAK,MAAM;EACX,QAAO,UAAS;CAClB,CAAC;AACH,CAAC,CACH"}
@@ -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 { 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 };
2
+ import { CommitThenWriteTerminalEventEffectInput, CommitThenWriteTerminalEventInput, CommitThenWriteTerminalEventResult, DurableAgentEvent, DurableAgentEventIdInput, DurableAgentEventSequencerState, SequenceDurableAgentEventInput, SequencedDurableAgentEvent, TerminalEventCloseResult, WriteDurableAgentEventInput, commitThenWriteTerminalEvent, commitThenWriteTerminalEventEffect, durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent, writeDurableAgentEventEffect } from "./workflow-events.mjs";
3
+ export { type CommitThenWriteTerminalEventEffectInput, 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, commitThenWriteTerminalEventEffect, defaultMaxWorkflowTurns, durableAgentEventId, makeDurableAgentEventSequencerState, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, sequenceDurableAgentEvent, settleWorkflowStep, writeDurableAgentEvent, writeDurableAgentEventEffect };
package/dist/workflow.mjs CHANGED
@@ -1,3 +1,3 @@
1
1
  import { defaultMaxWorkflowTurns, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, settleWorkflowStep } from "./workflow-loop.mjs";
2
- import { commitThenWriteTerminalEvent, durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent } from "./workflow-events.mjs";
3
- export { commitThenWriteTerminalEvent, defaultMaxWorkflowTurns, durableAgentEventId, makeDurableAgentEventSequencerState, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, sequenceDurableAgentEvent, settleWorkflowStep, writeDurableAgentEvent };
2
+ import { commitThenWriteTerminalEvent, commitThenWriteTerminalEventEffect, durableAgentEventId, makeDurableAgentEventSequencerState, sequenceDurableAgentEvent, writeDurableAgentEvent, writeDurableAgentEventEffect } from "./workflow-events.mjs";
3
+ export { commitThenWriteTerminalEvent, commitThenWriteTerminalEventEffect, defaultMaxWorkflowTurns, durableAgentEventId, makeDurableAgentEventSequencerState, noWorkflowStepRetry, retryWorkflowStep, runVercelAgentWorkflow, sequenceDurableAgentEvent, settleWorkflowStep, writeDurableAgentEvent, writeDurableAgentEventEffect };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yolk-sdk/vercel-workflows",
3
- "version": "0.1.0-canary.38",
3
+ "version": "0.1.0-canary.39",
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,5 +1,6 @@
1
1
  export {
2
2
  commitThenWriteTerminalEvent,
3
+ commitThenWriteTerminalEventEffect,
3
4
  durableAgentEventId,
4
5
  defaultMaxWorkflowTurns,
5
6
  makeDurableAgentEventSequencerState,
@@ -8,9 +9,11 @@ export {
8
9
  runVercelAgentWorkflow,
9
10
  sequenceDurableAgentEvent,
10
11
  settleWorkflowStep,
11
- writeDurableAgentEvent
12
+ writeDurableAgentEvent,
13
+ writeDurableAgentEventEffect
12
14
  } from './workflow.ts'
13
15
  export type {
16
+ CommitThenWriteTerminalEventEffectInput,
14
17
  CommitThenWriteTerminalEventInput,
15
18
  CommitThenWriteTerminalEventResult,
16
19
  DurableAgentEvent,
@@ -1,3 +1,5 @@
1
+ import { Effect } from 'effect'
2
+
1
3
  export type DurableAgentEventSequencerState = {
2
4
  readonly eventSequence: number
3
5
  }
@@ -15,6 +17,13 @@ export type DurableAgentEventIdInput = {
15
17
 
16
18
  export type SequenceDurableAgentEventInput<Event extends object = object> = {
17
19
  readonly state: DurableAgentEventSequencerState
20
+ /**
21
+ * Stable id namespace for one independent durable stream.
22
+ *
23
+ * Include the workflow/session/run id when multiple logical runs can be
24
+ * projected in the same client. Replay-safe clients de-dupe by `eventId`, so
25
+ * reusing a stream id across runs can drop legitimate follow-up events.
26
+ */
18
27
  readonly streamId: string
19
28
  readonly turn: number
20
29
  readonly event: Event
@@ -49,6 +58,24 @@ export type CommitThenWriteTerminalEventInput<
49
58
  readonly close: () => Promise<void>
50
59
  }
51
60
 
61
+ export type CommitThenWriteTerminalEventEffectInput<
62
+ TerminalEvent extends object,
63
+ TerminalWriteResult,
64
+ CommitErrorWriteResult,
65
+ CommitError,
66
+ TerminalWriteError,
67
+ CommitErrorWriteError,
68
+ CloseError
69
+ > = {
70
+ readonly commit: Effect.Effect<void, CommitError>
71
+ readonly terminal: TerminalEvent
72
+ readonly write: (event: TerminalEvent) => Effect.Effect<TerminalWriteResult, TerminalWriteError>
73
+ readonly writeCommitError: (
74
+ error: unknown
75
+ ) => Effect.Effect<CommitErrorWriteResult, CommitErrorWriteError>
76
+ readonly close: Effect.Effect<void, CloseError>
77
+ }
78
+
52
79
  export type CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult> =
53
80
  | {
54
81
  readonly _tag: 'Committed'
@@ -108,26 +135,155 @@ export const sequenceDurableAgentEvent = <Event extends object>(
108
135
  const encodeDurableAgentEventNdjson = <Event extends object>(event: DurableAgentEvent<Event>) =>
109
136
  textEncoder.encode(`${JSON.stringify(event)}\n`)
110
137
 
138
+ export const writeDurableAgentEventEffect = <Event extends object>(
139
+ input: WriteDurableAgentEventInput<Event>
140
+ ): Effect.Effect<SequencedDurableAgentEvent<Event>, unknown> =>
141
+ Effect.gen(function* () {
142
+ const sequenced = sequenceDurableAgentEvent(input)
143
+ yield* Effect.tryPromise({
144
+ try: () => input.writer.write(encodeDurableAgentEventNdjson(sequenced.event)),
145
+ catch: cause => cause
146
+ })
147
+
148
+ return sequenced
149
+ })
150
+
111
151
  export const writeDurableAgentEvent = async <Event extends object>(
112
152
  input: WriteDurableAgentEventInput<Event>
113
- ): Promise<SequencedDurableAgentEvent<Event>> => {
114
- const sequenced = sequenceDurableAgentEvent(input)
115
- await input.writer.write(encodeDurableAgentEventNdjson(sequenced.event))
153
+ ): Promise<SequencedDurableAgentEvent<Event>> =>
154
+ Effect.runPromise(writeDurableAgentEventEffect(input))
116
155
 
117
- return sequenced
118
- }
156
+ const closedTerminalEventWriterResult = (): TerminalEventCloseResult => ({ _tag: 'Closed' })
119
157
 
120
- const closeTerminalEventWriter = async (
121
- close: () => Promise<void>
122
- ): Promise<TerminalEventCloseResult> => {
123
- try {
124
- await close()
158
+ const closeFailedTerminalEventWriterResult = (error: unknown): TerminalEventCloseResult => ({
159
+ _tag: 'CloseFailed',
160
+ error
161
+ })
125
162
 
126
- return { _tag: 'Closed' }
127
- } catch (error) {
128
- return { _tag: 'CloseFailed', error }
129
- }
130
- }
163
+ const committedTerminalResult = <TerminalWriteResult, CommitErrorWriteResult>(
164
+ writeResult: TerminalWriteResult,
165
+ closeResult: TerminalEventCloseResult
166
+ ): CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult> => ({
167
+ _tag: 'Committed',
168
+ writeResult,
169
+ closeResult
170
+ })
171
+
172
+ const commitFailedTerminalResult = <TerminalWriteResult, CommitErrorWriteResult>(
173
+ commitError: unknown,
174
+ writeResult: CommitErrorWriteResult,
175
+ closeResult: TerminalEventCloseResult
176
+ ): CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult> => ({
177
+ _tag: 'CommitFailed',
178
+ commitError,
179
+ writeResult,
180
+ closeResult
181
+ })
182
+
183
+ const terminalWriteFailedResult = <TerminalWriteResult, CommitErrorWriteResult>(
184
+ error: unknown,
185
+ closeResult: TerminalEventCloseResult
186
+ ): CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult> => ({
187
+ _tag: 'TerminalWriteFailed',
188
+ error,
189
+ closeResult
190
+ })
191
+
192
+ const commitErrorWriteFailedResult = <TerminalWriteResult, CommitErrorWriteResult>(
193
+ commitError: unknown,
194
+ error: unknown,
195
+ closeResult: TerminalEventCloseResult
196
+ ): CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult> => ({
197
+ _tag: 'CommitErrorWriteFailed',
198
+ commitError,
199
+ error,
200
+ closeResult
201
+ })
202
+
203
+ const closeTerminalEventWriterEffect = <CloseError>(
204
+ close: Effect.Effect<void, CloseError>
205
+ ): Effect.Effect<TerminalEventCloseResult, never> =>
206
+ close.pipe(
207
+ Effect.match({
208
+ onFailure: closeFailedTerminalEventWriterResult,
209
+ onSuccess: () => closedTerminalEventWriterResult()
210
+ })
211
+ )
212
+
213
+ export const commitThenWriteTerminalEventEffect = <
214
+ TerminalEvent extends object,
215
+ TerminalWriteResult,
216
+ CommitErrorWriteResult,
217
+ CommitError,
218
+ TerminalWriteError,
219
+ CommitErrorWriteError,
220
+ CloseError
221
+ >(
222
+ input: CommitThenWriteTerminalEventEffectInput<
223
+ TerminalEvent,
224
+ TerminalWriteResult,
225
+ CommitErrorWriteResult,
226
+ CommitError,
227
+ TerminalWriteError,
228
+ CommitErrorWriteError,
229
+ CloseError
230
+ >
231
+ ): Effect.Effect<
232
+ CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult>,
233
+ never
234
+ > =>
235
+ input.commit.pipe(
236
+ Effect.matchEffect({
237
+ onFailure: commitError =>
238
+ input.writeCommitError(commitError).pipe(
239
+ Effect.matchEffect({
240
+ onFailure: error =>
241
+ closeTerminalEventWriterEffect(input.close).pipe(
242
+ Effect.map(closeResult =>
243
+ commitErrorWriteFailedResult<TerminalWriteResult, CommitErrorWriteResult>(
244
+ commitError,
245
+ error,
246
+ closeResult
247
+ )
248
+ )
249
+ ),
250
+ onSuccess: writeResult =>
251
+ closeTerminalEventWriterEffect(input.close).pipe(
252
+ Effect.map(closeResult =>
253
+ commitFailedTerminalResult<TerminalWriteResult, CommitErrorWriteResult>(
254
+ commitError,
255
+ writeResult,
256
+ closeResult
257
+ )
258
+ )
259
+ )
260
+ })
261
+ ),
262
+ onSuccess: () =>
263
+ input.write(input.terminal).pipe(
264
+ Effect.matchEffect({
265
+ onFailure: error =>
266
+ closeTerminalEventWriterEffect(input.close).pipe(
267
+ Effect.map(closeResult =>
268
+ terminalWriteFailedResult<TerminalWriteResult, CommitErrorWriteResult>(
269
+ error,
270
+ closeResult
271
+ )
272
+ )
273
+ ),
274
+ onSuccess: writeResult =>
275
+ closeTerminalEventWriterEffect(input.close).pipe(
276
+ Effect.map(closeResult =>
277
+ committedTerminalResult<TerminalWriteResult, CommitErrorWriteResult>(
278
+ writeResult,
279
+ closeResult
280
+ )
281
+ )
282
+ )
283
+ })
284
+ )
285
+ })
286
+ )
131
287
 
132
288
  export const commitThenWriteTerminalEvent = async <
133
289
  TerminalEvent extends object,
@@ -139,30 +295,27 @@ export const commitThenWriteTerminalEvent = async <
139
295
  TerminalWriteResult,
140
296
  CommitErrorWriteResult
141
297
  >
142
- ): Promise<CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult>> => {
143
- try {
144
- await input.commit()
145
- } catch (commitError) {
146
- try {
147
- const writeResult = await input.writeCommitError(commitError)
148
- const closeResult = await closeTerminalEventWriter(input.close)
149
-
150
- return { _tag: 'CommitFailed', commitError, writeResult, closeResult }
151
- } catch (error) {
152
- const closeResult = await closeTerminalEventWriter(input.close)
153
-
154
- return { _tag: 'CommitErrorWriteFailed', commitError, error, closeResult }
155
- }
156
- }
157
-
158
- try {
159
- const writeResult = await input.write(input.terminal)
160
- const closeResult = await closeTerminalEventWriter(input.close)
161
-
162
- return { _tag: 'Committed', writeResult, closeResult }
163
- } catch (error) {
164
- const closeResult = await closeTerminalEventWriter(input.close)
165
-
166
- return { _tag: 'TerminalWriteFailed', error, closeResult }
167
- }
168
- }
298
+ ): Promise<CommitThenWriteTerminalEventResult<TerminalWriteResult, CommitErrorWriteResult>> =>
299
+ Effect.runPromise(
300
+ commitThenWriteTerminalEventEffect({
301
+ terminal: input.terminal,
302
+ commit: Effect.tryPromise({
303
+ try: input.commit,
304
+ catch: cause => cause
305
+ }),
306
+ write: event =>
307
+ Effect.tryPromise({
308
+ try: () => input.write(event),
309
+ catch: cause => cause
310
+ }),
311
+ writeCommitError: error =>
312
+ Effect.tryPromise({
313
+ try: () => input.writeCommitError(error),
314
+ catch: cause => cause
315
+ }),
316
+ close: Effect.tryPromise({
317
+ try: input.close,
318
+ catch: cause => cause
319
+ })
320
+ })
321
+ )
package/src/workflow.ts CHANGED
@@ -7,10 +7,12 @@ export {
7
7
  } from './workflow-loop.ts'
8
8
  export {
9
9
  commitThenWriteTerminalEvent,
10
+ commitThenWriteTerminalEventEffect,
10
11
  durableAgentEventId,
11
12
  makeDurableAgentEventSequencerState,
12
13
  sequenceDurableAgentEvent,
13
- writeDurableAgentEvent
14
+ writeDurableAgentEvent,
15
+ writeDurableAgentEventEffect
14
16
  } from './workflow-events.ts'
15
17
  export type {
16
18
  SerializableWorkflowState,
@@ -29,6 +31,7 @@ export type {
29
31
  DurableAgentEvent,
30
32
  DurableAgentEventIdInput,
31
33
  DurableAgentEventSequencerState,
34
+ CommitThenWriteTerminalEventEffectInput,
32
35
  CommitThenWriteTerminalEventInput,
33
36
  CommitThenWriteTerminalEventResult,
34
37
  SequenceDurableAgentEventInput,