@ekairos/events 1.22.49-beta.development.0 → 1.22.51-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.
@@ -93,6 +93,7 @@ export type ContextReactParams<Env extends ContextEnvironment = ContextEnvironme
93
93
  trigger: ContextItem;
94
94
  reaction: ContextItem;
95
95
  execution: ContextExecution;
96
+ returnValueHookToken?: string | null;
96
97
  };
97
98
  __benchmark?: ContextBenchmarkRecorder;
98
99
  };
@@ -114,6 +115,10 @@ export type ContextWorkflowRun<Context = any> = {
114
115
  runId: string;
115
116
  status: Promise<"pending" | "running" | "completed" | "failed" | "cancelled">;
116
117
  returnValue: Promise<ContextReactFinalResult<Context>>;
118
+ returnValueHook?: {
119
+ token: string;
120
+ parentWorkflowRunId: string;
121
+ } | null;
117
122
  };
118
123
  export type ContextReactRun<Context = any> = ContextWorkflowRun<Context> | ContextDirectRun<Context>;
119
124
  export type ContextReactResult<Context = any, Run extends ContextReactRun<Context> = ContextReactRun<Context>> = ContextReactBase<Context> & {
@@ -4,7 +4,8 @@ import { applyToolExecutionResultToParts } from "./context.toolcalls.js";
4
4
  import { isContextPartEnvelope, normalizePartsForPersistence, } from "./context.parts.js";
5
5
  import { createAiSdkReactor, } from "./context.reactor.js";
6
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, } from "./steps/store.steps.js";
7
+ import { completeExecution, createContextStep, finalizeReactionStep, getContextItems, initializeContext, openReactionStep, saveTriggerAndCreateExecution, saveContextPartsAndUpdateReaction, saveContextPartsStep, updateContextContent, updateContextReactor, updateContextStatus, updateItem, updateContextStep, updateExecutionWorkflowRun, } from "./steps/store.steps.js";
8
+ import { readContextDurableWorkflowReturnValue, readContextDurableWorkflowStatus, resumeContextReturnValueHook, startContextDurableWorkflow, } from "./steps/durable.steps.js";
8
9
  import { getClientResumeHookUrl, toolApprovalHookToken, toolApprovalWebhookToken, } from "./context.hooks.js";
9
10
  import { getContextDurableWorkflow } from "./context.durable.js";
10
11
  export async function runContextReactionDirect(context, triggerEvent, params) {
@@ -101,6 +102,30 @@ async function readActiveWorkflowRunId() {
101
102
  return null;
102
103
  }
103
104
  }
105
+ function serializeContextReturnValueError(error) {
106
+ if (error instanceof Error) {
107
+ return {
108
+ name: error.name,
109
+ message: error.message,
110
+ stack: error.stack,
111
+ };
112
+ }
113
+ return {
114
+ message: String(error),
115
+ };
116
+ }
117
+ function unwrapContextReturnValueHookPayload(payload) {
118
+ if (payload.ok)
119
+ return payload.result;
120
+ const error = new Error(payload.error.message);
121
+ if (payload.error.name) {
122
+ error.name = payload.error.name;
123
+ }
124
+ if (payload.error.stack) {
125
+ error.stack = payload.error.stack;
126
+ }
127
+ throw error;
128
+ }
104
129
  async function createRuntimeOps(runtimeHandle, benchmark) {
105
130
  const runtime = await getContextRuntimeServices(runtimeHandle);
106
131
  const { db } = runtime;
@@ -461,47 +486,73 @@ export class ContextEngine {
461
486
  }
462
487
  const workflow = getContextDurableWorkflow();
463
488
  if (typeof workflow !== "function") {
464
- throw new Error("ContextEngine.react: durable workflow is not configured. Call configureContextDurableWorkflow(...) in runtime bootstrap.");
489
+ const contextKeyLabel = contextKey || "(missing)";
490
+ throw new Error([
491
+ "ContextEngine.react(..., { durable: true }) needs a registered durable context workflow.",
492
+ "Call configureContextDurableWorkflow(contextDurableWorkflow) during server/workflow bootstrap.",
493
+ "If you want inline execution inside the current workflow step, pass durable: false.",
494
+ `Context key: ${contextKeyLabel}.`,
495
+ ].join(" "));
465
496
  }
466
497
  const shell = await ContextEngine.prepareExecutionShell(story, triggerEvent, params);
467
498
  let run;
468
499
  try {
469
- const [{ start }] = await measureBenchmark(params.__benchmark, "react.durable.importWorkflowApiMs", async () => await Promise.all([
470
- import("workflow/api"),
471
- ]));
472
- const startedRun = await measureBenchmark(params.__benchmark, "react.durable.startWorkflowMs", async () => await start(workflow, [
473
- {
474
- contextKey,
475
- runtime: runtimeHandle,
476
- context: params.context ?? null,
477
- triggerEvent,
478
- options: {
479
- maxIterations: params.options?.maxIterations,
480
- maxModelSteps: params.options?.maxModelSteps,
481
- preventClose: params.options?.preventClose,
482
- sendFinish: params.options?.sendFinish,
483
- silent: params.options?.silent,
484
- },
485
- bootstrap: {
500
+ const parentWorkflowRunId = await readActiveWorkflowRunId();
501
+ let returnValueHook = null;
502
+ let returnValueHookPromise = null;
503
+ if (parentWorkflowRunId) {
504
+ const { createHook } = await import("workflow");
505
+ const hook = createHook({
506
+ token: `context:return:${shell.execution.id}`,
507
+ metadata: {
508
+ kind: "context.returnValue",
486
509
  contextId: shell.currentContext.id,
487
- trigger: shell.trigger,
488
- reaction: shell.reaction,
489
- execution: shell.execution,
510
+ executionId: shell.execution.id,
511
+ parentWorkflowRunId,
490
512
  },
513
+ });
514
+ returnValueHook = {
515
+ token: hook.token,
516
+ parentWorkflowRunId,
517
+ };
518
+ returnValueHookPromise = Promise.resolve(hook);
519
+ }
520
+ const payload = {
521
+ contextKey,
522
+ runtime: runtimeHandle,
523
+ context: params.context ?? null,
524
+ triggerEvent,
525
+ options: {
526
+ maxIterations: params.options?.maxIterations,
527
+ maxModelSteps: params.options?.maxModelSteps,
528
+ preventClose: params.options?.preventClose,
529
+ sendFinish: params.options?.sendFinish,
530
+ silent: params.options?.silent,
531
+ },
532
+ bootstrap: {
533
+ contextId: shell.currentContext.id,
534
+ trigger: shell.trigger,
535
+ reaction: shell.reaction,
536
+ execution: shell.execution,
537
+ returnValueHookToken: returnValueHook?.token ?? null,
491
538
  },
492
- ]));
539
+ };
540
+ const startedRun = await measureBenchmark(params.__benchmark, "react.durable.startWorkflowMs", async () => await startContextDurableWorkflow({ payload }));
493
541
  run = {
494
542
  runId: String(startedRun.runId),
495
- status: startedRun.status,
496
- returnValue: startedRun.returnValue,
543
+ status: readContextDurableWorkflowStatus({ runId: String(startedRun.runId) }),
544
+ returnValue: returnValueHookPromise
545
+ ? returnValueHookPromise.then(unwrapContextReturnValueHookPayload)
546
+ : readContextDurableWorkflowReturnValue({
547
+ runId: String(startedRun.runId),
548
+ }),
549
+ returnValueHook,
497
550
  };
498
- const runtime = await measureBenchmark(params.__benchmark, "react.durable.resolveRuntimeOpsMs", async () => await createRuntimeOps(runtimeHandle, params.__benchmark));
499
- await measureBenchmark(params.__benchmark, "react.durable.persistWorkflowRunIdMs", async () => await runtime.db.transact([
500
- runtime.db.tx.event_executions[shell.execution.id].update({
501
- workflowRunId: startedRun.runId,
502
- updatedAt: new Date(),
503
- }),
504
- ]));
551
+ await measureBenchmark(params.__benchmark, "react.durable.persistWorkflowRunIdMs", async () => await updateExecutionWorkflowRun({
552
+ runtime: runtimeHandle,
553
+ executionId: shell.execution.id,
554
+ workflowRunId: String(startedRun.runId),
555
+ }));
505
556
  }
506
557
  catch (error) {
507
558
  const ops = await getContextEngineOps(runtimeHandle, params.__benchmark);
@@ -547,6 +598,15 @@ export class ContextEngine {
547
598
  const silent = params.options?.silent ?? false;
548
599
  const writable = params.options?.writable;
549
600
  const bootstrapped = params.__bootstrap;
601
+ const returnValueHookToken = bootstrapped?.returnValueHookToken ?? null;
602
+ const resumeReturnValueHook = async (payload) => {
603
+ if (!returnValueHookToken)
604
+ return;
605
+ await resumeContextReturnValueHook({
606
+ token: returnValueHookToken,
607
+ payload,
608
+ });
609
+ };
550
610
  const shell = bootstrapped
551
611
  ? {
552
612
  contextSelector: { id: String(bootstrapped.contextId) },
@@ -880,12 +940,14 @@ export class ContextEngine {
880
940
  if (!silent) {
881
941
  await closeContextStream({ preventClose, sendFinish, writable });
882
942
  }
883
- return {
943
+ const result = {
884
944
  context: updatedContext,
885
945
  trigger,
886
946
  reaction: reactionEvent,
887
947
  execution,
888
948
  };
949
+ await resumeReturnValueHook({ ok: true, result });
950
+ return result;
889
951
  }
890
952
  }
891
953
  // Execute actions (workflow context; action implementations decide step vs workflow)
@@ -1115,12 +1177,14 @@ export class ContextEngine {
1115
1177
  if (!silent) {
1116
1178
  await closeContextStream({ preventClose, sendFinish, writable });
1117
1179
  }
1118
- return {
1180
+ const result = {
1119
1181
  context: updatedContext,
1120
1182
  trigger,
1121
1183
  reaction: reactionEvent,
1122
1184
  execution,
1123
1185
  };
1186
+ await resumeReturnValueHook({ ok: true, result });
1187
+ return result;
1124
1188
  }
1125
1189
  }
1126
1190
  throw new Error(`ContextEngine: maxIterations reached (${maxIterations}) without completion`);
@@ -1174,6 +1238,10 @@ export class ContextEngine {
1174
1238
  }
1175
1239
  }
1176
1240
  await failExecution();
1241
+ await resumeReturnValueHook({
1242
+ ok: false,
1243
+ error: serializeContextReturnValueError(error),
1244
+ }).catch(() => null);
1177
1245
  throw error;
1178
1246
  }
1179
1247
  }
package/dist/schema.d.ts CHANGED
@@ -221,7 +221,7 @@ export declare const eventsDomain: import("@ekairos/domain").DomainSchemaResult<
221
221
  readonly label: "stream";
222
222
  };
223
223
  readonly reverse: {
224
- readonly on: any;
224
+ readonly on: "$streams";
225
225
  readonly has: "many";
226
226
  readonly label: "step";
227
227
  };
@@ -233,7 +233,7 @@ export declare const eventsDomain: import("@ekairos/domain").DomainSchemaResult<
233
233
  readonly label: "activeStream";
234
234
  };
235
235
  readonly reverse: {
236
- readonly on: any;
236
+ readonly on: "$streams";
237
237
  readonly has: "many";
238
238
  readonly label: "activeOf";
239
239
  };
@@ -245,7 +245,7 @@ export declare const eventsDomain: import("@ekairos/domain").DomainSchemaResult<
245
245
  readonly label: "lastStream";
246
246
  };
247
247
  readonly reverse: {
248
- readonly on: any;
248
+ readonly on: "$streams";
249
249
  readonly has: "many";
250
250
  readonly label: "lastOf";
251
251
  };
@@ -0,0 +1,28 @@
1
+ import type { ContextDurableWorkflowPayload, ContextReactFinalResult } from "../context.engine.js";
2
+ export type ContextDurableWorkflowStatus = "pending" | "running" | "completed" | "failed" | "cancelled";
3
+ export type ContextReturnValueHookPayload<Context = any> = {
4
+ ok: true;
5
+ result: ContextReactFinalResult<Context>;
6
+ } | {
7
+ ok: false;
8
+ error: {
9
+ name?: string;
10
+ message: string;
11
+ stack?: string;
12
+ };
13
+ };
14
+ export declare function startContextDurableWorkflow(params: {
15
+ payload: ContextDurableWorkflowPayload<any, any, any>;
16
+ }): Promise<{
17
+ runId: string;
18
+ }>;
19
+ export declare function readContextDurableWorkflowStatus(params: {
20
+ runId: string;
21
+ }): Promise<ContextDurableWorkflowStatus>;
22
+ export declare function readContextDurableWorkflowReturnValue(params: {
23
+ runId: string;
24
+ }): Promise<ContextReactFinalResult<any>>;
25
+ export declare function resumeContextReturnValueHook(params: {
26
+ token: string;
27
+ payload: ContextReturnValueHookPayload;
28
+ }): Promise<void>;
@@ -0,0 +1,34 @@
1
+ import { getContextDurableWorkflow } from "../context.durable.js";
2
+ export async function startContextDurableWorkflow(params) {
3
+ "use step";
4
+ const workflow = getContextDurableWorkflow();
5
+ if (typeof workflow !== "function") {
6
+ const contextKey = String(params.payload.contextKey || "(missing)");
7
+ throw new Error([
8
+ "ContextEngine.react(..., { durable: true }) needs a registered durable context workflow.",
9
+ "Call configureContextDurableWorkflow(contextDurableWorkflow) during server/workflow bootstrap.",
10
+ "If you want inline execution inside the current workflow step, pass durable: false.",
11
+ `Context key: ${contextKey}.`,
12
+ ].join(" "));
13
+ }
14
+ const { start } = await import("workflow/api");
15
+ const run = await start(workflow, [params.payload]);
16
+ return { runId: String(run.runId) };
17
+ }
18
+ export async function readContextDurableWorkflowStatus(params) {
19
+ "use step";
20
+ const { getRun } = await import("workflow/api");
21
+ const run = getRun(params.runId);
22
+ return (await run.status);
23
+ }
24
+ export async function readContextDurableWorkflowReturnValue(params) {
25
+ "use step";
26
+ const { getRun } = await import("workflow/api");
27
+ const run = getRun(params.runId);
28
+ return (await run.returnValue);
29
+ }
30
+ export async function resumeContextReturnValueHook(params) {
31
+ "use step";
32
+ const { resumeHook } = await import("workflow/api");
33
+ await resumeHook(params.token, params.payload);
34
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ekairos/events",
3
- "version": "1.22.49-beta.development.0",
3
+ "version": "1.22.51-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.49-beta.development.0",
130
+ "@ekairos/domain": "^1.22.51-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",