@ekairos/events 1.22.79-beta.development.0 → 1.22.80-beta.development.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,8 +3,8 @@ import { OUTPUT_ITEM_TYPE, WEB_CHANNEL } from "./context.events.js";
3
3
  import { applyToolExecutionResultToParts } from "./context.toolcalls.js";
4
4
  import { isContextPartEnvelope, normalizePartsForPersistence, } from "./context.parts.js";
5
5
  import { createAiSdkReactor, } from "./context.reactor.js";
6
- import { abortPersistedContextStepStream, closeContextStream, createPersistedContextStepStreamForRuntime, finalizePersistedContextStepStreamForRuntime, writeActionResultPartChunks, } from "./steps/stream.steps.js";
7
- import { completeExecution, createContextStep, finalizeReactionStep, getContextItems, initializeContext, openReactionStep, saveTriggerAndCreateExecution, saveContextPartsAndUpdateReaction, saveContextPartsStep, updateContextContent, updateContextReactor, updateContextStatus, updateItem, updateContextStep, updateExecutionWorkflowRun, } from "./steps/store.steps.js";
6
+ import { abortPersistedContextStepStream, closeContextStream, createPersistedContextStepStreamForRuntime, finalizePersistedContextStepStreamForRuntime, writeActionResultPartChunksToSession, } from "./steps/stream.steps.js";
7
+ import { completeExecution, completeExecutionStep, createContextStep, getContextItems, initializeContext, openExecutionStep, openExecution, saveExecutionStepOutput, updateContextContent, updateContextReactor, updateContextStatus, updateItem, updateContextStep, updateExecutionWorkflowRun, } from "./steps/store.steps.js";
8
8
  import { readContextDurableWorkflowReturnValue, readContextDurableWorkflowStatus, resumeContextReturnValueHook, startContextDurableWorkflow, } from "./steps/durable.steps.js";
9
9
  import { getClientResumeHookUrl, toolApprovalHookToken, toolApprovalWebhookToken, } from "./context.hooks.js";
10
10
  import { getContextDurableWorkflow } from "./context.durable.js";
@@ -195,7 +195,7 @@ async function createRuntimeOps(runtimeHandle, benchmark) {
195
195
  updatedAt: new Date(),
196
196
  }),
197
197
  ]),
198
- saveTriggerAndCreateExecution: async ({ contextIdentifier, triggerEvent }) => {
198
+ openExecution: async ({ contextIdentifier, triggerEvent }) => {
199
199
  const contextId = requireContextId(contextIdentifier);
200
200
  const triggerId = String(triggerEvent.id);
201
201
  const reactionId = makeRuntimeId();
@@ -253,7 +253,7 @@ async function createRuntimeOps(runtimeHandle, benchmark) {
253
253
  },
254
254
  };
255
255
  },
256
- openReactionStep: async ({ contextIdentifier, content, executionId, iteration }) => {
256
+ openExecutionStep: async ({ contextIdentifier, content, executionId, iteration }) => {
257
257
  const stepId = makeRuntimeId();
258
258
  const now = new Date();
259
259
  await instrumentedDb.transact([
@@ -301,7 +301,17 @@ async function createRuntimeOps(runtimeHandle, benchmark) {
301
301
  instrumentedDb.tx.event_steps[params.stepId].update(update),
302
302
  ]);
303
303
  },
304
- finalizeReactionStep: async (params) => {
304
+ completeExecutionStep: async (params) => {
305
+ const actionResultChunkEvents = await writeActionResultPartChunksToSession({
306
+ session: params.session,
307
+ contextId: String(params.contextId ?? ""),
308
+ executionId: String(params.executionId ?? ""),
309
+ itemId: String(params.reactionEventId ?? ""),
310
+ actionResults: params.actionResults ?? [],
311
+ });
312
+ if (params.parts) {
313
+ await store.saveStepParts({ stepId: params.stepId, parts: params.parts });
314
+ }
305
315
  if (params.session) {
306
316
  await finalizePersistedContextStepStreamForRuntime({
307
317
  runtime: { db: instrumentedDb },
@@ -310,15 +320,14 @@ async function createRuntimeOps(runtimeHandle, benchmark) {
310
320
  });
311
321
  }
312
322
  const update = { updatedAt: new Date() };
313
- if (params.patch.status !== undefined)
314
- update.status = params.patch.status;
315
- if (params.patch.errorText !== undefined)
316
- update.errorText = params.patch.errorText;
323
+ update.status = params.stepStatus ?? "completed";
324
+ if (params.errorText !== undefined)
325
+ update.errorText = params.errorText;
317
326
  await instrumentedDb.transact([
318
327
  instrumentedDb.tx.event_steps[params.stepId].update(update),
319
328
  ]);
320
329
  if (!params.reactionEventId || !params.reactionEvent) {
321
- return {};
330
+ return { actionResultChunkEvents };
322
331
  }
323
332
  await instrumentedDb.transact([
324
333
  instrumentedDb.tx.event_items[params.reactionEventId].update(params.reactionEvent),
@@ -328,12 +337,10 @@ async function createRuntimeOps(runtimeHandle, benchmark) {
328
337
  ...params.reactionEvent,
329
338
  id: params.reactionEventId,
330
339
  },
340
+ actionResultChunkEvents,
331
341
  };
332
342
  },
333
- saveContextPartsStep: async (params) => {
334
- await store.saveStepParts({ stepId: params.stepId, parts: params.parts });
335
- },
336
- saveContextPartsAndUpdateReaction: async (params) => {
343
+ saveExecutionStepOutput: async (params) => {
337
344
  await store.saveStepParts({ stepId: params.stepId, parts: params.parts });
338
345
  await instrumentedDb.transact([
339
346
  instrumentedDb.tx.event_items[params.reactionEventId].update(params.reactionEvent),
@@ -353,9 +360,9 @@ async function createRuntimeOps(runtimeHandle, benchmark) {
353
360
  id: itemId,
354
361
  };
355
362
  },
356
- completeExecution: async (contextIdentifier, executionId, status) => {
363
+ completeExecution: async (contextIdentifier, executionId, status, opts) => {
357
364
  const contextId = requireContextId(contextIdentifier);
358
- await instrumentedDb.transact([
365
+ const txs = [
359
366
  instrumentedDb.tx.event_executions[executionId].update({
360
367
  status,
361
368
  updatedAt: new Date(),
@@ -364,7 +371,19 @@ async function createRuntimeOps(runtimeHandle, benchmark) {
364
371
  status: "closed",
365
372
  updatedAt: new Date(),
366
373
  }),
367
- ]);
374
+ ];
375
+ if (opts?.reactionEventId && opts.reactionEvent) {
376
+ txs.push(instrumentedDb.tx.event_items[opts.reactionEventId].update(opts.reactionEvent));
377
+ }
378
+ await instrumentedDb.transact(txs);
379
+ return opts?.reactionEventId && opts.reactionEvent
380
+ ? {
381
+ reactionEvent: {
382
+ ...opts.reactionEvent,
383
+ id: opts.reactionEventId,
384
+ },
385
+ }
386
+ : {};
368
387
  },
369
388
  };
370
389
  }
@@ -375,16 +394,15 @@ async function createWorkflowOps(runtime) {
375
394
  updateContextContent: async (contextIdentifier, content) => await updateContextContent({ runtime, contextIdentifier, content }),
376
395
  updateContextReactor: async (contextIdentifier, reactor) => await updateContextReactor({ runtime, contextIdentifier, reactor }),
377
396
  updateContextStatus: async (contextIdentifier, status) => await updateContextStatus({ runtime, contextIdentifier, status }),
378
- saveTriggerAndCreateExecution: async ({ contextIdentifier, triggerEvent }) => await saveTriggerAndCreateExecution({ runtime, contextIdentifier, triggerEvent }),
379
- openReactionStep: async (params) => await openReactionStep({ runtime, ...params }),
397
+ openExecution: async ({ contextIdentifier, triggerEvent }) => await openExecution({ runtime, contextIdentifier, triggerEvent }),
398
+ openExecutionStep: async (params) => await openExecutionStep({ runtime, ...params }),
380
399
  createContextStep: async ({ executionId, iteration }) => await createContextStep({ runtime, executionId, iteration }),
381
400
  updateContextStep: async (params) => await updateContextStep({ runtime, ...params }),
382
- finalizeReactionStep: async (params) => await finalizeReactionStep({ runtime, ...params }),
383
- saveContextPartsStep: async (params) => await saveContextPartsStep({ runtime, ...params }),
384
- saveContextPartsAndUpdateReaction: async (params) => await saveContextPartsAndUpdateReaction({ runtime, ...params }),
401
+ completeExecutionStep: async (params) => await completeExecutionStep({ runtime, ...params }),
402
+ saveExecutionStepOutput: async (params) => await saveExecutionStepOutput({ runtime, ...params }),
385
403
  getItems: async (contextIdentifier) => await getContextItems({ runtime, contextIdentifier }),
386
404
  updateItem: async (itemId, item, opts) => await updateItem({ runtime, eventId: itemId, event: item, opts }),
387
- completeExecution: async (contextIdentifier, executionId, status) => await completeExecution({ runtime, contextIdentifier, executionId, status }),
405
+ completeExecution: async (contextIdentifier, executionId, status, opts) => await completeExecution({ runtime, contextIdentifier, executionId, status, ...opts }),
388
406
  };
389
407
  }
390
408
  async function getContextEngineOps(runtime, benchmark) {
@@ -467,7 +485,7 @@ export class ContextEngine {
467
485
  await measureBenchmark(params.__benchmark, "react.reopenClosedContextMs", async () => await ops.updateContextStatus(contextSelector, "open_idle"));
468
486
  currentContext = { ...currentContext, status: "open_idle" };
469
487
  }
470
- const shell = await measureBenchmark(params.__benchmark, "react.bootstrapShellMs", async () => await ops.saveTriggerAndCreateExecution({
488
+ const shell = await measureBenchmark(params.__benchmark, "react.openExecutionMs", async () => await ops.openExecution({
471
489
  contextIdentifier: contextSelector,
472
490
  triggerEvent,
473
491
  }));
@@ -690,7 +708,7 @@ export class ContextEngine {
690
708
  const stagePrefix = `react.iteration.${iter}`;
691
709
  // Hook: Context DSL `context()` (implemented by subclasses via `initialize()`)
692
710
  const nextContent = await measureBenchmark(params.__benchmark, `${stagePrefix}.contextMs`, async () => await story.initialize(updatedContext, env, runtimeHandle));
693
- const openedStep = await measureBenchmark(params.__benchmark, `${stagePrefix}.openReactionStepMs`, async () => await ops.openReactionStep({
711
+ const openedStep = await measureBenchmark(params.__benchmark, `${stagePrefix}.openExecutionStepMs`, async () => await ops.openExecutionStep({
694
712
  contextIdentifier: activeContextSelector,
695
713
  content: nextContent,
696
714
  executionId,
@@ -748,7 +766,7 @@ export class ContextEngine {
748
766
  if (nextSignature === persistedReactionPartsSignature)
749
767
  return;
750
768
  persistedReactionPartsSignature = nextSignature;
751
- const saved = await ops.saveContextPartsAndUpdateReaction({
769
+ const saved = await ops.saveExecutionStepOutput({
752
770
  stepId: openedStep.stepId,
753
771
  parts: normalizedParts,
754
772
  reactionEventId: reactionEvent.id,
@@ -829,7 +847,7 @@ export class ContextEngine {
829
847
  },
830
848
  status: "pending",
831
849
  };
832
- const appendedReactorOutput = await measureBenchmark(params.__benchmark, `${stagePrefix}.appendReactorOutputMs`, async () => await ops.saveContextPartsAndUpdateReaction({
850
+ const appendedReactorOutput = await measureBenchmark(params.__benchmark, `${stagePrefix}.saveExecutionStepOutputMs`, async () => await ops.saveExecutionStepOutput({
833
851
  stepId: openedStep.stepId,
834
852
  parts: stepParts,
835
853
  reactionEventId: reactionEvent.id,
@@ -886,12 +904,10 @@ export class ContextEngine {
886
904
  ...reactionEvent,
887
905
  status: "completed",
888
906
  };
889
- const finalized = await measureBenchmark(params.__benchmark, `${stagePrefix}.finalizeReactionStepMs`, async () => await ops.finalizeReactionStep({
907
+ const finalized = await measureBenchmark(params.__benchmark, `${stagePrefix}.completeExecutionStepMs`, async () => await ops.completeExecutionStep({
890
908
  session: currentStepStream,
891
909
  stepId: openedStep.stepId,
892
- patch: {
893
- status: "completed",
894
- },
910
+ stepStatus: "completed",
895
911
  reactionEventId,
896
912
  reactionEvent: completedReactionEvent,
897
913
  executionId,
@@ -899,6 +915,7 @@ export class ContextEngine {
899
915
  iteration: iter,
900
916
  }));
901
917
  currentStepStream = null;
918
+ currentStepId = null;
902
919
  reactionEvent = finalized.reactionEvent ?? completedReactionEvent;
903
920
  await emitContextEvents({
904
921
  silent,
@@ -1037,19 +1054,7 @@ export class ContextEngine {
1037
1054
  };
1038
1055
  }
1039
1056
  })));
1040
- const actionResultChunkEvents = await measureBenchmark(params.__benchmark, `${stagePrefix}.writeActionResultPartChunksMs`, async () => await writeActionResultPartChunks({
1041
- session: currentStepStream,
1042
- contextId: String(currentContext.id),
1043
- executionId,
1044
- itemId: reactionEventId,
1045
- actionResults: actionResults,
1046
- }));
1047
- await emitContextEvents({
1048
- silent,
1049
- writable,
1050
- events: actionResultChunkEvents,
1051
- });
1052
- // Merge action results into persisted parts (so next LLM call can see them)
1057
+ // Merge action results into step parts so the next reaction can see them.
1053
1058
  let finalizedStepParts = Array.isArray(stepParts) ? [...stepParts] : [];
1054
1059
  for (const r of actionResults) {
1055
1060
  finalizedStepParts = applyToolExecutionResultToParts(finalizedStepParts, {
@@ -1061,14 +1066,7 @@ export class ContextEngine {
1061
1066
  message: r.errorText,
1062
1067
  });
1063
1068
  }
1064
- await measureBenchmark(params.__benchmark, `${stagePrefix}.saveFinalStepPartsMs`, async () => await ops.saveContextPartsStep({
1065
- stepId: openedStep.stepId,
1066
- parts: finalizedStepParts,
1067
- executionId,
1068
- contextId: String(currentContext.id),
1069
- iteration: iter,
1070
- }));
1071
- reactionEvent = {
1069
+ const pendingReactionEvent = {
1072
1070
  ...reactionEvent,
1073
1071
  content: {
1074
1072
  ...reactionEvent.content,
@@ -1078,48 +1076,26 @@ export class ContextEngine {
1078
1076
  },
1079
1077
  status: "pending",
1080
1078
  };
1081
- // Callback for observability/integration
1082
- for (const r of actionResults) {
1083
- await story.opts.onActionExecuted?.({
1084
- actionRequest: r.actionRequest,
1085
- success: r.success,
1086
- output: r.output,
1087
- errorText: r.errorText,
1088
- eventId: reactionEventId,
1089
- executionId,
1090
- });
1091
- }
1092
- // Stop/continue boundary: allow the Context to decide if the loop should continue.
1093
- // IMPORTANT: we call this after tool results have been merged into the persisted `reactionEvent`,
1094
- // so stories can inspect `reactionEvent.content.parts` deterministically.
1095
- const continueLoop = await measureBenchmark(params.__benchmark, `${stagePrefix}.shouldContinueMs`, async () => await story.shouldContinue({
1096
- env,
1097
- runtime: runtimeHandle,
1098
- context: updatedContext,
1099
- reactionEvent,
1100
- assistantEvent: assistantEventEffective,
1101
- actionRequests,
1102
- actionResults: actionResults,
1103
- }));
1104
- const finalizedReactionStatus = continueLoop === false ? "completed" : "pending";
1105
- const finalizedReactionEvent = {
1106
- ...reactionEvent,
1107
- status: finalizedReactionStatus,
1108
- };
1109
- const finalizedStep = await measureBenchmark(params.__benchmark, `${stagePrefix}.finalizeReactionStepMs`, async () => await ops.finalizeReactionStep({
1079
+ const completedStep = await measureBenchmark(params.__benchmark, `${stagePrefix}.completeExecutionStepMs`, async () => await ops.completeExecutionStep({
1110
1080
  session: currentStepStream,
1111
1081
  stepId: openedStep.stepId,
1112
- patch: {
1113
- status: "completed",
1114
- },
1082
+ parts: finalizedStepParts,
1083
+ actionResults: actionResults,
1084
+ stepStatus: "completed",
1115
1085
  reactionEventId,
1116
- reactionEvent: finalizedReactionEvent,
1086
+ reactionEvent: pendingReactionEvent,
1117
1087
  executionId,
1118
1088
  contextId: String(currentContext.id),
1119
1089
  iteration: iter,
1120
1090
  }));
1121
1091
  currentStepStream = null;
1122
- reactionEvent = finalizedStep.reactionEvent ?? finalizedReactionEvent;
1092
+ currentStepId = null;
1093
+ reactionEvent = completedStep.reactionEvent ?? pendingReactionEvent;
1094
+ await emitContextEvents({
1095
+ silent,
1096
+ writable,
1097
+ events: completedStep.actionResultChunkEvents,
1098
+ });
1123
1099
  await emitContextEvents({
1124
1100
  silent,
1125
1101
  writable,
@@ -1142,6 +1118,28 @@ export class ContextEngine {
1142
1118
  },
1143
1119
  ],
1144
1120
  });
1121
+ // Callback for observability/integration
1122
+ for (const r of actionResults) {
1123
+ await story.opts.onActionExecuted?.({
1124
+ actionRequest: r.actionRequest,
1125
+ success: r.success,
1126
+ output: r.output,
1127
+ errorText: r.errorText,
1128
+ eventId: reactionEventId,
1129
+ executionId,
1130
+ });
1131
+ }
1132
+ // Stop/continue boundary: allow the Context to decide if the loop should continue.
1133
+ // Tool results are already persisted in the completed reaction step here.
1134
+ const continueLoop = await measureBenchmark(params.__benchmark, `${stagePrefix}.shouldContinueMs`, async () => await story.shouldContinue({
1135
+ env,
1136
+ runtime: runtimeHandle,
1137
+ context: updatedContext,
1138
+ reactionEvent,
1139
+ assistantEvent: assistantEventEffective,
1140
+ actionRequests,
1141
+ actionResults: actionResults,
1142
+ }));
1145
1143
  if (continueLoop !== false) {
1146
1144
  await emitContextEvents({
1147
1145
  silent,
@@ -1159,6 +1157,10 @@ export class ContextEngine {
1159
1157
  });
1160
1158
  }
1161
1159
  if (continueLoop === false) {
1160
+ reactionEvent = {
1161
+ ...reactionEvent,
1162
+ status: "completed",
1163
+ };
1162
1164
  await emitContextEvents({
1163
1165
  silent,
1164
1166
  writable,
@@ -1173,7 +1175,11 @@ export class ContextEngine {
1173
1175
  },
1174
1176
  ],
1175
1177
  });
1176
- await measureBenchmark(params.__benchmark, `${stagePrefix}.completeExecutionMs`, async () => await ops.completeExecution(activeContextSelector, executionId, "completed"));
1178
+ await measureBenchmark(params.__benchmark, `${stagePrefix}.completeExecutionMs`, async () => await ops.completeExecution(activeContextSelector, executionId, "completed", {
1179
+ contextId: String(currentContext.id),
1180
+ reactionEventId,
1181
+ reactionEvent,
1182
+ }));
1177
1183
  execution = { ...execution, status: "completed" };
1178
1184
  updatedContext = { ...updatedContext, status: "closed" };
1179
1185
  await emitContextEvents({
@@ -2,7 +2,8 @@ import type { UIMessageChunk } from "ai";
2
2
  import type { ContextEnvironment } from "../context.config.js";
3
3
  import type { ContextRuntime } from "../context.runtime.js";
4
4
  import type { ContextExecution, ContextItem, ContextIdentifier, StoredContext, ContextStatus } from "../context.store.js";
5
- import { type PersistedContextStepStreamSession } from "./stream.steps.js";
5
+ import type { ContextStreamEvent } from "../context.stream.js";
6
+ import { type ContextActionResultForStream, type PersistedContextStepStreamSession } from "./stream.steps.js";
6
7
  type RuntimeParams<Env extends ContextEnvironment = ContextEnvironment> = {
7
8
  runtime: ContextRuntime<Env>;
8
9
  };
@@ -48,7 +49,7 @@ export declare function saveTriggerItem(params: RuntimeParams & {
48
49
  contextIdentifier: ContextIdentifier;
49
50
  event: ContextItem;
50
51
  }): Promise<ContextItem>;
51
- export declare function saveTriggerAndCreateExecution(params: {
52
+ export declare function openExecution(params: {
52
53
  runtime: ContextRuntime<ContextEnvironment>;
53
54
  contextIdentifier: ContextIdentifier;
54
55
  triggerEvent: ContextItem;
@@ -96,13 +97,18 @@ export declare function completeExecution(params: RuntimeParams & {
96
97
  contextIdentifier: ContextIdentifier;
97
98
  executionId: string;
98
99
  status: "completed" | "failed";
99
- }): Promise<void>;
100
+ contextId?: string;
101
+ reactionEventId?: string;
102
+ reactionEvent?: ContextItem;
103
+ }): Promise<{
104
+ reactionEvent?: ContextItem;
105
+ }>;
100
106
  export declare function updateExecutionWorkflowRun(params: {
101
107
  runtime: ContextRuntime<ContextEnvironment>;
102
108
  executionId: string;
103
109
  workflowRunId: string;
104
110
  }): Promise<void>;
105
- export declare function openReactionStep<C>(params: {
111
+ export declare function openExecutionStep<C>(params: {
106
112
  runtime: ContextRuntime<ContextEnvironment>;
107
113
  contextIdentifier: ContextIdentifier;
108
114
  content: C;
@@ -129,33 +135,29 @@ export declare function updateContextStep(params: {
129
135
  iteration?: number;
130
136
  patch: ContextStepPatch;
131
137
  }): Promise<void>;
132
- export declare function finalizeReactionStep(params: {
138
+ export declare function completeExecutionStep(params: {
133
139
  runtime: ContextRuntime<ContextEnvironment>;
134
140
  session?: PersistedContextStepStreamSession | null;
135
141
  stepId: string;
136
142
  executionId?: string;
137
143
  contextId?: string;
138
144
  iteration?: number;
139
- patch: ContextStepPatch;
145
+ parts?: any[];
146
+ actionResults?: ContextActionResultForStream[];
147
+ stepStatus?: ContextStepPatch["status"];
148
+ errorText?: string;
140
149
  reactionEventId?: string;
141
150
  reactionEvent?: ContextItem;
142
151
  }): Promise<{
143
152
  reactionEvent?: ContextItem;
153
+ actionResultChunkEvents: ContextStreamEvent[];
144
154
  }>;
145
155
  export declare function linkItemToExecutionStep(params: {
146
156
  runtime: ContextRuntime<ContextEnvironment>;
147
157
  itemId: string;
148
158
  executionId: string;
149
159
  }): Promise<void>;
150
- export declare function saveContextPartsStep(params: {
151
- runtime: ContextRuntime<ContextEnvironment>;
152
- stepId: string;
153
- executionId?: string;
154
- contextId?: string;
155
- iteration?: number;
156
- parts: any[];
157
- }): Promise<void>;
158
- export declare function saveContextPartsAndUpdateReaction(params: {
160
+ export declare function saveExecutionStepOutput(params: {
159
161
  runtime: ContextRuntime<ContextEnvironment>;
160
162
  stepId: string;
161
163
  executionId?: string;
@@ -2,7 +2,7 @@ import { getContextRuntimeServices } from "../context.runtime.js";
2
2
  import { OUTPUT_ITEM_TYPE, WEB_CHANNEL } from "../context.events.js";
3
3
  import { writeContextTraceEvents } from "./trace.steps.js";
4
4
  import { getClientResumeHookUrl, toolApprovalHookToken, toolApprovalWebhookToken, } from "../context.hooks.js";
5
- import { createPersistedContextStepStreamForRuntime, finalizePersistedContextStepStreamForRuntime, } from "./stream.steps.js";
5
+ import { createPersistedContextStepStreamForRuntime, finalizePersistedContextStepStreamForRuntime, writeActionResultPartChunksToSession, } from "./stream.steps.js";
6
6
  async function getRuntimeAndEnv(params) {
7
7
  const env = params.runtime.env;
8
8
  const runtime = await getContextRuntimeServices(params.runtime);
@@ -158,11 +158,11 @@ export async function saveTriggerItem(params) {
158
158
  const { runtime } = await getRuntimeAndEnv(params);
159
159
  return await runtime.store.saveItem(params.contextIdentifier, params.event);
160
160
  }
161
- export async function saveTriggerAndCreateExecution(params) {
161
+ export async function openExecution(params) {
162
162
  "use step";
163
163
  const { runtime, env } = await getRuntimeAndEnv(params);
164
164
  const { store, db } = runtime;
165
- logStepDebug("saveTriggerAndCreateExecution:start", {
165
+ logStepDebug("openExecution:start", {
166
166
  contextIdentifier: summarizeContextIdentifierForLog(params.contextIdentifier),
167
167
  triggerEventId: params.triggerEvent?.id,
168
168
  triggerEventType: params.triggerEvent?.type,
@@ -174,7 +174,7 @@ export async function saveTriggerAndCreateExecution(params) {
174
174
  saved = await store.saveItem(params.contextIdentifier, params.triggerEvent);
175
175
  }
176
176
  catch (error) {
177
- logStepDebug("saveTriggerAndCreateExecution:saveItem:error", {
177
+ logStepDebug("openExecution:saveItem:error", {
178
178
  contextIdentifier: summarizeContextIdentifierForLog(params.contextIdentifier),
179
179
  triggerEventId: params.triggerEvent?.id,
180
180
  error: summarizeStepError(error),
@@ -206,7 +206,7 @@ export async function saveTriggerAndCreateExecution(params) {
206
206
  });
207
207
  }
208
208
  catch (error) {
209
- logStepDebug("saveTriggerAndCreateExecution:saveReaction:error", {
209
+ logStepDebug("openExecution:saveReaction:error", {
210
210
  contextIdentifier: summarizeContextIdentifierForLog(params.contextIdentifier),
211
211
  reactionEventId,
212
212
  error: summarizeStepError(error),
@@ -218,7 +218,7 @@ export async function saveTriggerAndCreateExecution(params) {
218
218
  execution = await store.createExecution(params.contextIdentifier, saved.id, savedReaction.id);
219
219
  }
220
220
  catch (error) {
221
- logStepDebug("saveTriggerAndCreateExecution:createExecution:error", {
221
+ logStepDebug("openExecution:createExecution:error", {
222
222
  contextIdentifier: summarizeContextIdentifierForLog(params.contextIdentifier),
223
223
  triggerEventId: saved.id,
224
224
  reactionEventId: savedReaction.id,
@@ -237,7 +237,7 @@ export async function saveTriggerAndCreateExecution(params) {
237
237
  });
238
238
  }
239
239
  catch (error) {
240
- logStepDebug("saveTriggerAndCreateExecution:linkItemsToExecution:error", {
240
+ logStepDebug("openExecution:linkItemsToExecution:error", {
241
241
  contextIdentifier: summarizeContextIdentifierForLog(params.contextIdentifier),
242
242
  triggerEventId: saved.id,
243
243
  reactionEventId: savedReaction.id,
@@ -474,16 +474,22 @@ export async function completeExecution(params) {
474
474
  const { runtime, env } = await getRuntimeAndEnv(params);
475
475
  const { store, db } = runtime;
476
476
  await store.completeExecution(params.contextIdentifier, params.executionId, params.status);
477
- const contextId = typeof params.contextIdentifier?.id === "string"
478
- ? String(params.contextIdentifier.id)
479
- : undefined;
477
+ let savedReaction;
478
+ if (params.reactionEventId && params.reactionEvent) {
479
+ savedReaction = await store.updateItem(params.reactionEventId, params.reactionEvent);
480
+ }
481
+ const contextId = typeof params.contextId === "string"
482
+ ? params.contextId
483
+ : typeof params.contextIdentifier?.id === "string"
484
+ ? String(params.contextIdentifier.id)
485
+ : undefined;
480
486
  const { runId } = await resolveWorkflowRunId({
481
487
  env,
482
488
  db,
483
489
  executionId: params.executionId,
484
490
  });
485
491
  if (runId) {
486
- await maybeWriteTraceEvents(env, [
492
+ const events = [
487
493
  {
488
494
  workflowRunId: runId,
489
495
  eventId: `context_execution:${String(params.executionId)}:${params.status}`,
@@ -495,8 +501,25 @@ export async function completeExecution(params) {
495
501
  status: params.status,
496
502
  },
497
503
  },
498
- ]);
504
+ ];
505
+ if (savedReaction) {
506
+ events.push({
507
+ workflowRunId: runId,
508
+ eventId: `context_item:${String(savedReaction.id)}`,
509
+ eventKind: "context.item",
510
+ eventAt: new Date().toISOString(),
511
+ contextId,
512
+ executionId: String(params.executionId),
513
+ contextEventId: String(savedReaction.id),
514
+ payload: {
515
+ ...savedReaction,
516
+ direction: inferDirection(savedReaction),
517
+ },
518
+ });
519
+ }
520
+ await maybeWriteTraceEvents(env, events);
499
521
  }
522
+ return { reactionEvent: savedReaction };
500
523
  }
501
524
  export async function updateExecutionWorkflowRun(params) {
502
525
  "use step";
@@ -511,7 +534,7 @@ export async function updateExecutionWorkflowRun(params) {
511
534
  ]);
512
535
  }
513
536
  }
514
- export async function openReactionStep(params) {
537
+ export async function openExecutionStep(params) {
515
538
  "use step";
516
539
  const { runtime } = await getRuntimeAndEnv(params);
517
540
  const { store } = runtime;
@@ -574,10 +597,20 @@ export async function updateContextStep(params) {
574
597
  ]);
575
598
  }
576
599
  }
577
- export async function finalizeReactionStep(params) {
600
+ export async function completeExecutionStep(params) {
578
601
  "use step";
579
602
  const { runtime, env } = await getRuntimeAndEnv(params);
580
603
  const { store, db } = runtime;
604
+ const actionResultChunkEvents = await writeActionResultPartChunksToSession({
605
+ session: params.session,
606
+ contextId: String(params.contextId ?? ""),
607
+ executionId: String(params.executionId ?? ""),
608
+ itemId: String(params.reactionEventId ?? ""),
609
+ actionResults: params.actionResults ?? [],
610
+ });
611
+ if (params.parts) {
612
+ await store.saveStepParts({ stepId: params.stepId, parts: params.parts });
613
+ }
581
614
  if (params.session) {
582
615
  await finalizePersistedContextStepStreamForRuntime({
583
616
  runtime,
@@ -586,7 +619,8 @@ export async function finalizeReactionStep(params) {
586
619
  });
587
620
  }
588
621
  await store.updateStep(params.stepId, {
589
- ...params.patch,
622
+ status: params.stepStatus ?? "completed",
623
+ ...(params.errorText !== undefined ? { errorText: params.errorText } : {}),
590
624
  updatedAt: new Date(),
591
625
  });
592
626
  let savedReaction;
@@ -609,12 +643,29 @@ export async function finalizeReactionStep(params) {
609
643
  executionId: params.executionId,
610
644
  stepId: String(params.stepId),
611
645
  payload: {
612
- status: params.patch.status,
646
+ status: params.stepStatus ?? "completed",
613
647
  iteration: params.iteration,
614
- errorText: params.patch.errorText,
648
+ errorText: params.errorText,
615
649
  },
616
650
  },
617
651
  ];
652
+ if (params.parts?.length) {
653
+ for (let idx = 0; idx < params.parts.length; idx += 1) {
654
+ const part = params.parts[idx];
655
+ events.push({
656
+ workflowRunId: runId,
657
+ eventId: `context_part:${String(params.stepId)}:${idx}`,
658
+ eventKind: "context.part",
659
+ eventAt: new Date().toISOString(),
660
+ contextId: params.contextId,
661
+ executionId: params.executionId,
662
+ stepId: String(params.stepId),
663
+ partKey: `${String(params.stepId)}:${idx}`,
664
+ partIdx: idx,
665
+ payload: part,
666
+ });
667
+ }
668
+ }
618
669
  if (savedReaction) {
619
670
  events.push({
620
671
  workflowRunId: runId,
@@ -632,7 +683,7 @@ export async function finalizeReactionStep(params) {
632
683
  }
633
684
  await maybeWriteTraceEvents(env, events);
634
685
  }
635
- return { reactionEvent: savedReaction };
686
+ return { reactionEvent: savedReaction, actionResultChunkEvents };
636
687
  }
637
688
  export async function linkItemToExecutionStep(params) {
638
689
  "use step";
@@ -640,37 +691,7 @@ export async function linkItemToExecutionStep(params) {
640
691
  const { store } = runtime;
641
692
  await store.linkItemToExecution({ itemId: params.itemId, executionId: params.executionId });
642
693
  }
643
- export async function saveContextPartsStep(params) {
644
- "use step";
645
- const { runtime, env } = await getRuntimeAndEnv(params);
646
- const { store, db } = runtime;
647
- await store.saveStepParts({ stepId: params.stepId, parts: params.parts });
648
- const { runId } = await resolveWorkflowRunId({
649
- env,
650
- db,
651
- executionId: params.executionId,
652
- });
653
- if (runId && params.parts?.length) {
654
- const events = [];
655
- for (let idx = 0; idx < params.parts.length; idx += 1) {
656
- const part = params.parts[idx];
657
- events.push({
658
- workflowRunId: runId,
659
- eventId: `context_part:${String(params.stepId)}:${idx}`,
660
- eventKind: "context.part",
661
- eventAt: new Date().toISOString(),
662
- contextId: params.contextId,
663
- executionId: params.executionId,
664
- stepId: String(params.stepId),
665
- partKey: `${String(params.stepId)}:${idx}`,
666
- partIdx: idx,
667
- payload: part,
668
- });
669
- }
670
- await maybeWriteTraceEvents(env, events);
671
- }
672
- }
673
- export async function saveContextPartsAndUpdateReaction(params) {
694
+ export async function saveExecutionStepOutput(params) {
674
695
  "use step";
675
696
  const { runtime, env } = await getRuntimeAndEnv(params);
676
697
  const { store, db } = runtime;
@@ -50,21 +50,22 @@ export declare function abortPersistedContextStepStream(params: {
50
50
  session: PersistedContextStepStreamSession;
51
51
  reason?: string | null;
52
52
  }): Promise<void>;
53
- export declare function writeActionResultPartChunks(params: {
53
+ export type ContextActionResultForStream = {
54
+ actionRequest: {
55
+ actionRef: string;
56
+ actionName: string;
57
+ input: unknown;
58
+ };
59
+ success: boolean;
60
+ output: unknown;
61
+ errorText?: string;
62
+ };
63
+ export declare function writeActionResultPartChunksToSession(params: {
54
64
  session?: PersistedContextStepStreamSession | null;
55
65
  contextId: string;
56
66
  executionId: string;
57
67
  itemId: string;
58
- actionResults: Array<{
59
- actionRequest: {
60
- actionRef: string;
61
- actionName: string;
62
- input: unknown;
63
- };
64
- success: boolean;
65
- output: unknown;
66
- errorText?: string;
67
- }>;
68
+ actionResults: ContextActionResultForStream[];
68
69
  }): Promise<ContextStreamEvent[]>;
69
70
  export declare function readPersistedContextStepStream(params: {
70
71
  db: any;
@@ -183,8 +183,7 @@ export async function abortPersistedContextStepStream(params) {
183
183
  abortReason: params.reason,
184
184
  });
185
185
  }
186
- export async function writeActionResultPartChunks(params) {
187
- "use step";
186
+ export async function writeActionResultPartChunksToSession(params) {
188
187
  if (!params.session || params.actionResults.length === 0)
189
188
  return [];
190
189
  const writer = params.session.stream.getWriter();
@@ -71,6 +71,43 @@ function ensureValidEntityId(value, label) {
71
71
  }
72
72
  return normalized;
73
73
  }
74
+ function sanitizeInstantString(value) {
75
+ return value.includes("\u0000") ? value.replace(/\u0000/g, "") : value;
76
+ }
77
+ function isOpaqueJsonValue(value) {
78
+ return (value instanceof Date ||
79
+ value instanceof ArrayBuffer ||
80
+ ArrayBuffer.isView(value));
81
+ }
82
+ function sanitizeInstantValue(value, seen = new WeakMap()) {
83
+ if (typeof value === "string") {
84
+ return sanitizeInstantString(value);
85
+ }
86
+ if (value === null || value === undefined || typeof value !== "object") {
87
+ return value;
88
+ }
89
+ if (isOpaqueJsonValue(value)) {
90
+ return value;
91
+ }
92
+ const cached = seen.get(value);
93
+ if (cached) {
94
+ return cached;
95
+ }
96
+ if (Array.isArray(value)) {
97
+ const out = [];
98
+ seen.set(value, out);
99
+ for (const item of value) {
100
+ out.push(sanitizeInstantValue(item, seen));
101
+ }
102
+ return out;
103
+ }
104
+ const out = {};
105
+ seen.set(value, out);
106
+ for (const [key, entryValue] of Object.entries(value)) {
107
+ out[sanitizeInstantString(key)] = sanitizeInstantValue(entryValue, seen);
108
+ }
109
+ return out;
110
+ }
74
111
  function logInstantTransactFailure(params) {
75
112
  if (!shouldDebugInstantStore())
76
113
  return;
@@ -244,6 +281,7 @@ export class InstantStore {
244
281
  }
245
282
  async saveItem(contextIdentifier, event) {
246
283
  const eventId = ensureValidEntityId(event?.id, "event.id");
284
+ const sanitizedEvent = sanitizeInstantValue(event);
247
285
  const context = await this.resolveContext(contextIdentifier);
248
286
  const existing = await this.getItem(eventId);
249
287
  if (existing?.status && existing.status !== "stored") {
@@ -251,7 +289,7 @@ export class InstantStore {
251
289
  }
252
290
  const txs = [
253
291
  this.db.tx.event_items[eventId].update({
254
- ...event,
292
+ ...sanitizedEvent,
255
293
  id: eventId,
256
294
  status: "stored",
257
295
  }),
@@ -277,7 +315,7 @@ export class InstantStore {
277
315
  throw error;
278
316
  }
279
317
  return {
280
- ...event,
318
+ ...sanitizedEvent,
281
319
  id: eventId,
282
320
  status: "stored",
283
321
  };
@@ -287,10 +325,11 @@ export class InstantStore {
287
325
  if (current?.status && event.status && current.status !== event.status) {
288
326
  assertItemTransition(current.status, event.status);
289
327
  }
290
- await this.db.transact([this.db.tx.event_items[eventId].update(event)]);
328
+ const sanitizedEvent = sanitizeInstantValue(event);
329
+ await this.db.transact([this.db.tx.event_items[eventId].update(sanitizedEvent)]);
291
330
  return {
292
331
  ...current,
293
- ...event,
332
+ ...sanitizedEvent,
294
333
  id: eventId,
295
334
  };
296
335
  }
@@ -531,7 +570,7 @@ export class InstantStore {
531
570
  ]);
532
571
  }
533
572
  async saveStepParts(params) {
534
- const parts = normalizePartsForPersistence(Array.isArray(params.parts) ? params.parts : []);
573
+ const parts = sanitizeInstantValue(normalizePartsForPersistence(Array.isArray(params.parts) ? params.parts : []));
535
574
  if (parts.length === 0)
536
575
  return;
537
576
  const txs = parts.map((part, idx) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ekairos/events",
3
- "version": "1.22.79-beta.development.0",
3
+ "version": "1.22.80-beta.development.0",
4
4
  "description": "Ekairos Events - Context-first workflow runtime",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -127,7 +127,7 @@
127
127
  },
128
128
  "dependencies": {
129
129
  "@ai-sdk/openai": "^2.0.52",
130
- "@ekairos/domain": "^1.22.79-beta.development.0",
130
+ "@ekairos/domain": "^1.22.80-beta.development.0",
131
131
  "@instantdb/admin": "0.22.158",
132
132
  "@instantdb/core": "0.22.142",
133
133
  "@vercel/mcp-adapter": "^1.0.0",