@ekairos/events 1.22.4-beta.development.0 → 1.22.5-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.
package/README.md CHANGED
@@ -2,114 +2,87 @@
2
2
 
3
3
  Context-first durable execution runtime for Ekairos.
4
4
 
5
- ## Surface
5
+ ## What this package does
6
6
 
7
- - `createContext`, `context`, `ContextEngine`
8
- - `createAiSdkReactor`, `createScriptedReactor`
9
- - `useContext`
7
+ - creates durable contexts with `createContext(...)`
8
+ - persists executions, steps, parts, and items
9
+ - runs direct or durable `react(...)` loops
10
+ - adapts model/tool output into canonical `event_parts`
11
+
12
+ ## Main APIs
13
+
14
+ - `createContext`
15
+ - `ContextEngine`
16
+ - `createAiSdkReactor`
17
+ - `createScriptedReactor`
18
+ - `runContextReactionDirect`
10
19
  - `eventsDomain`
11
- - `getContextRuntime`, `getContextEnv`, `registerContextEnv`
12
20
 
13
21
  ## Runtime model
14
22
 
23
+ Canonical entities:
24
+
15
25
  - `event_contexts`
16
26
  - `event_items`
17
27
  - `event_executions`
18
28
  - `event_steps`
19
29
  - `event_parts`
20
- - `event_trace_events`
21
- - `event_trace_runs`
22
- - `event_trace_spans`
23
-
24
- The aggregate is `context`. Executions, steps, parts, and items are scoped to a context.
25
-
26
- ## Canonical Parts
30
+ - `event_trace_*`
27
31
 
28
- `event_parts` is the canonical content model for produced output.
32
+ `event_parts` is the source of truth for replay.
29
33
 
30
- Rules:
31
-
32
- - `event_parts.part` is the source of truth for replay and inspection.
33
- - `event_items.content.parts` on output items is maintained as a compatibility mirror and is deprecated as a replay source.
34
- - Provider/model-specific values must live under `metadata`, never as first-class semantic fields.
35
-
36
- Canonical part kinds:
37
-
38
- - `content`
39
- - `reasoning`
40
- - `source`
41
- - `tool-call`
42
- - `tool-result`
34
+ ## Example
43
35
 
44
- Each canonical part stores a `content` array. The entries inside that array define the payload type:
36
+ ```ts
37
+ import { createContext } from "@ekairos/events";
45
38
 
46
- - `text`
47
- - `file`
48
- - `json`
49
- - `source-url`
50
- - `source-document`
39
+ const supportContext = createContext<{ orgId: string }>("support.agent")
40
+ .context((stored, env) => ({
41
+ ...stored.content,
42
+ orgId: env.orgId,
43
+ }))
44
+ .narrative(() => "You are a precise assistant.")
45
+ .actions(() => ({}))
46
+ .build();
47
+ ```
51
48
 
52
- Example tool result:
49
+ Run directly:
53
50
 
54
51
  ```ts
55
- {
56
- type: "tool-result",
57
- toolCallId: "call_123",
58
- toolName: "inspectCanvasRegion",
59
- state: "output-available",
60
- content: [
61
- {
62
- type: "text",
63
- text: "Zoomed crop of the requested region.",
64
- },
65
- {
66
- type: "file",
67
- mediaType: "image/png",
68
- filename: "inspect-region.png",
69
- data: "iVBORw0KGgoAAAANSUhEUgAA...",
70
- },
71
- ],
72
- metadata: {
73
- provider: {
74
- itemId: "fc_041cb...",
75
- },
76
- },
77
- }
52
+ await supportContext.react(triggerEvent, {
53
+ runtime,
54
+ context: { key: "support:org_123" },
55
+ });
78
56
  ```
79
57
 
80
- The AI SDK bridge projects canonical parts to:
58
+ Run durably:
81
59
 
82
- - assistant messages with text/file/reasoning/source/tool-call parts
83
- - tool messages with `tool-result` or `tool-error`
84
-
85
- That means multipart tool outputs are replayed from `event_parts` instead of relying on the deprecated output-item mirror.
86
-
87
- ## Install
60
+ ```ts
61
+ const shell = await supportContext.react(triggerEvent, {
62
+ runtime,
63
+ context: { key: "support:org_123" },
64
+ durable: true,
65
+ });
88
66
 
89
- ```bash
90
- pnpm add @ekairos/events
67
+ const final = await shell.run?.returnValue;
91
68
  ```
92
69
 
93
- ## Example
70
+ ## Tool execution model
94
71
 
95
- ```ts
96
- import { createContext, createAiSdkReactor } from "@ekairos/events";
97
-
98
- type Env = { orgId: string };
72
+ Context tools now receive runtime-aware execution context.
73
+ That lets a tool do this inside `"use step"`:
99
74
 
100
- export const supportContext = createContext<Env>("support.agent")
101
- .context((stored, env) => ({
102
- orgId: env.orgId,
103
- ...stored.content,
104
- }))
105
- .narrative(() => "You are a precise assistant.")
106
- .actions(() => ({}))
107
- .reactor(createAiSdkReactor())
108
- .build();
75
+ ```ts
76
+ async function execute(input, ctx) {
77
+ "use step";
78
+ const domain = await ctx.runtime.use(myDomain);
79
+ return await domain.actions.doSomething(input);
80
+ }
109
81
  ```
110
82
 
111
- ## Notes
83
+ ## Tests
112
84
 
113
- - Public continuity is context-based.
114
- - Provider-specific IDs such as `providerContextId` may still exist when an upstream provider requires them.
115
- - Runtime wiring for stores lives under `@ekairos/events/runtime`.
85
+ ```bash
86
+ pnpm --filter @ekairos/events test
87
+ pnpm --filter @ekairos/events test:workflow
88
+ ```
package/dist/context.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { ContextEngine, type ContextOptions, type ContextStreamOptions, type ShouldContinue, type ContextShouldContinueArgs, type ContextReactParams, type ContextReactResult, type ContextDurableWorkflowPayload, type ContextDurableWorkflowFunction, type ContextModelInit, type ContextTool, runContextReactionDirect, } from "./context.engine.js";
1
+ export { ContextEngine, type ContextOptions, type ContextStreamOptions, type ShouldContinue, type ContextShouldContinueArgs, type ContextReactParams, type ContextReactResult, type ContextWorkflowRun, type ContextDurableWorkflowPayload, type ContextDurableWorkflowFunction, type ContextModelInit, type ContextTool, type ContextToolExecuteContext, runContextReactionDirect, } from "./context.engine.js";
2
2
  export { context, createContext, type ContextConfig, type ContextInstance, type RegistrableContextBuilder, } from "./context.builder.js";
3
3
  export { createAiSdkReactor, createScriptedReactor, type CreateAiSdkReactorOptions, type CreateScriptedReactorOptions, type ScriptedReactorStep, type ContextReactor, type ContextReactorParams, type ContextReactionResult, type ContextActionRequest, type ContextReactionLLM, } from "./context.reactor.js";
4
4
  export type { ContextSkillPackage, ContextSkillPackageFile, } from "./context.skill.js";
@@ -1,5 +1,6 @@
1
- import type { Tool, UIMessageChunk } from "ai";
1
+ import type { ModelMessage, Tool, UIMessageChunk } from "ai";
2
2
  import type { ContextEnvironment } from "./context.config.js";
3
+ import type { ContextRuntime } from "./context.runtime.js";
3
4
  import type { ContextExecution, ContextItem, ContextIdentifier, StoredContext } from "./context.store.js";
4
5
  import type { ContextSkillPackage } from "./context.skill.js";
5
6
  import { type ContextReactor } from "./context.reactor.js";
@@ -68,7 +69,7 @@ export interface ContextStreamOptions {
68
69
  */
69
70
  export type ContextModelInit = string | (() => Promise<any>);
70
71
  export type ContextReactParams<Env extends ContextEnvironment = ContextEnvironment> = {
71
- env: Env;
72
+ runtime: ContextRuntime<Env>;
72
73
  /**
73
74
  * Context selector (exclusive: `{ id }` OR `{ key }`).
74
75
  * - `{ id }` resolves a concrete context id.
@@ -95,16 +96,36 @@ export type ContextReactResult<Context = any> = {
95
96
  trigger: ContextItem;
96
97
  reaction: ContextItem;
97
98
  execution: ContextExecution;
99
+ run?: ContextWorkflowRun<Context>;
100
+ };
101
+ export type ContextWorkflowRun<Context = any> = {
102
+ runId: string;
103
+ status: Promise<"pending" | "running" | "completed" | "failed" | "cancelled">;
104
+ returnValue: Promise<ContextReactResult<Context>>;
98
105
  };
99
106
  export type ContextDurableWorkflowPayload<Env extends ContextEnvironment = ContextEnvironment> = {
100
107
  contextKey: string;
101
- env: Env;
108
+ runtime: ContextRuntime<Env>;
102
109
  context?: ContextIdentifier | null;
103
110
  triggerEvent: ContextItem;
104
111
  options?: Omit<ContextStreamOptions, "writable">;
105
112
  bootstrap: NonNullable<ContextReactParams<Env>["__bootstrap"]>;
106
113
  };
107
114
  export type ContextDurableWorkflowFunction<Context = any, Env extends ContextEnvironment = ContextEnvironment> = (payload: ContextDurableWorkflowPayload<Env>) => Promise<ContextReactResult<Context>>;
115
+ export type ContextToolExecuteContext<Context = any, Env extends ContextEnvironment = ContextEnvironment> = {
116
+ runtime: ContextRuntime<Env>;
117
+ env: Env;
118
+ context: StoredContext<Context>;
119
+ contextIdentifier: ContextIdentifier;
120
+ toolCallId: string;
121
+ messages: ModelMessage[];
122
+ eventId: string;
123
+ executionId: string;
124
+ triggerEventId: string;
125
+ contextId: string;
126
+ stepId: string;
127
+ iteration: number;
128
+ };
108
129
  export { toolApprovalHookToken, toolApprovalWebhookToken, getClientResumeHookUrl };
109
130
  /**
110
131
  * Context-level tool type.
@@ -1,4 +1,4 @@
1
- import { registerContextEnv } from "./env.js";
1
+ import { getContextRuntimeServices } from "./context.runtime.js";
2
2
  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";
@@ -89,9 +89,8 @@ async function readActiveWorkflowRunId() {
89
89
  return null;
90
90
  }
91
91
  }
92
- async function createRuntimeOps(env, benchmark) {
93
- const { getContextRuntime } = await import("./runtime.js");
94
- const runtime = await getContextRuntime(env);
92
+ async function createRuntimeOps(runtimeHandle, benchmark) {
93
+ const runtime = await getContextRuntimeServices(runtimeHandle);
95
94
  const { db } = runtime;
96
95
  const { InstantStore } = await import("./stores/instant.store.js");
97
96
  const requireContextId = (contextIdentifier) => {
@@ -255,27 +254,27 @@ async function createRuntimeOps(env, benchmark) {
255
254
  },
256
255
  };
257
256
  }
258
- async function createWorkflowOps(env) {
257
+ async function createWorkflowOps(runtime) {
258
+ const env = runtime.env;
259
259
  return {
260
- initializeContext: async (contextIdentifier, opts) => await initializeContext(env, contextIdentifier, opts),
261
- updateContextContent: async (contextIdentifier, content) => await updateContextContent(env, contextIdentifier, content),
262
- updateContextStatus: async (contextIdentifier, status) => await updateContextStatus(env, contextIdentifier, status),
263
- saveTriggerAndCreateExecution: async ({ contextIdentifier, triggerEvent }) => await saveTriggerAndCreateExecution({ env, contextIdentifier, triggerEvent }),
264
- createContextStep: async ({ executionId, iteration }) => await createContextStep({ env, executionId, iteration }),
265
- updateContextStep: async (params) => await updateContextStep({ env, ...params }),
266
- saveContextPartsStep: async (params) => await saveContextPartsStep({ env, ...params }),
267
- updateItem: async (itemId, item, opts) => await updateItem(env, itemId, item, opts),
268
- completeExecution: async (contextIdentifier, executionId, status) => await completeExecution(env, contextIdentifier, executionId, status),
260
+ initializeContext: async (contextIdentifier, opts) => await initializeContext({ runtime, contextIdentifier, opts }),
261
+ updateContextContent: async (contextIdentifier, content) => await updateContextContent({ runtime, contextIdentifier, content }),
262
+ updateContextStatus: async (contextIdentifier, status) => await updateContextStatus({ runtime, contextIdentifier, status }),
263
+ saveTriggerAndCreateExecution: async ({ contextIdentifier, triggerEvent }) => await saveTriggerAndCreateExecution({ runtime, contextIdentifier, triggerEvent }),
264
+ createContextStep: async ({ executionId, iteration }) => await createContextStep({ runtime, executionId, iteration }),
265
+ updateContextStep: async (params) => await updateContextStep({ runtime, ...params }),
266
+ saveContextPartsStep: async (params) => await saveContextPartsStep({ runtime, ...params }),
267
+ updateItem: async (itemId, item, opts) => await updateItem({ runtime, eventId: itemId, event: item, opts }),
268
+ completeExecution: async (contextIdentifier, executionId, status) => await completeExecution({ runtime, contextIdentifier, executionId, status }),
269
269
  };
270
270
  }
271
- async function getContextEngineOps(env, benchmark) {
271
+ async function getContextEngineOps(runtime, benchmark) {
272
+ const env = runtime.env;
272
273
  const workflowRunId = await readActiveWorkflowRunId();
273
274
  if (workflowRunId) {
274
- registerContextEnv(env, workflowRunId);
275
- return await createWorkflowOps(env);
275
+ return await createWorkflowOps(runtime);
276
276
  }
277
- registerContextEnv(env);
278
- return await createRuntimeOps(env, benchmark);
277
+ return await createRuntimeOps(runtime, benchmark);
279
278
  }
280
279
  export class ContextEngine {
281
280
  constructor(opts = {}, reactor) {
@@ -329,13 +328,14 @@ export class ContextEngine {
329
328
  return await ContextEngine.runDirect(this, triggerEvent, params);
330
329
  }
331
330
  static async prepareExecutionShell(story, triggerEvent, params) {
332
- const ops = await measureBenchmark(params.__benchmark, "react.resolveOpsMs", async () => await getContextEngineOps(params.env, params.__benchmark));
331
+ const env = params.runtime.env;
332
+ const ops = await measureBenchmark(params.__benchmark, "react.resolveOpsMs", async () => await getContextEngineOps(params.runtime, params.__benchmark));
333
333
  const silent = params.options?.silent ?? false;
334
334
  const ctxResult = await measureBenchmark(params.__benchmark, "react.initializeContextMs", async () => await ops.initializeContext(params.context ?? null, { silent }));
335
335
  let currentContext = ctxResult.context;
336
336
  const contextSelector = { id: String(currentContext.id) };
337
337
  if (ctxResult.isNew) {
338
- await story.opts.onContextCreated?.({ env: params.env, context: currentContext });
338
+ await story.opts.onContextCreated?.({ env, context: currentContext });
339
339
  }
340
340
  if (currentContext.status === "closed") {
341
341
  await measureBenchmark(params.__benchmark, "react.reopenClosedContextMs", async () => await ops.updateContextStatus(contextSelector, "open_idle"));
@@ -355,6 +355,7 @@ export class ContextEngine {
355
355
  };
356
356
  }
357
357
  static async startDurable(story, triggerEvent, params) {
358
+ const env = params.runtime.env;
358
359
  if (params.options?.writable) {
359
360
  throw new Error("ContextEngine.react: durable runs manage their own workflow stream");
360
361
  }
@@ -367,14 +368,15 @@ export class ContextEngine {
367
368
  throw new Error("ContextEngine.react: durable workflow is not configured. Call configureContextDurableWorkflow(...) in runtime bootstrap.");
368
369
  }
369
370
  const shell = await ContextEngine.prepareExecutionShell(story, triggerEvent, params);
371
+ let run;
370
372
  try {
371
373
  const [{ start }] = await Promise.all([
372
374
  import("workflow/api"),
373
375
  ]);
374
- const run = await start(workflow, [
376
+ const startedRun = await start(workflow, [
375
377
  {
376
378
  contextKey,
377
- env: params.env,
379
+ runtime: params.runtime,
378
380
  context: params.context ?? null,
379
381
  triggerEvent,
380
382
  options: {
@@ -392,16 +394,21 @@ export class ContextEngine {
392
394
  },
393
395
  },
394
396
  ]);
395
- const runtime = await createRuntimeOps(params.env);
397
+ run = {
398
+ runId: String(startedRun.runId),
399
+ status: startedRun.status,
400
+ returnValue: startedRun.returnValue,
401
+ };
402
+ const runtime = await createRuntimeOps(params.runtime);
396
403
  await runtime.db.transact([
397
404
  runtime.db.tx.event_executions[shell.execution.id].update({
398
- workflowRunId: run.runId,
405
+ workflowRunId: startedRun.runId,
399
406
  updatedAt: new Date(),
400
407
  }),
401
408
  ]);
402
409
  }
403
410
  catch (error) {
404
- const ops = await getContextEngineOps(params.env, params.__benchmark);
411
+ const ops = await getContextEngineOps(params.runtime, params.__benchmark);
405
412
  await ops.completeExecution(shell.contextSelector, shell.execution.id, "failed").catch(() => null);
406
413
  throw error;
407
414
  }
@@ -410,10 +417,12 @@ export class ContextEngine {
410
417
  trigger: shell.trigger,
411
418
  reaction: shell.reaction,
412
419
  execution: shell.execution,
420
+ run,
413
421
  };
414
422
  }
415
423
  static async runDirect(story, triggerEvent, params) {
416
- const ops = await measureBenchmark(params.__benchmark, "react.resolveOpsMs", async () => await getContextEngineOps(params.env, params.__benchmark));
424
+ const env = params.runtime.env;
425
+ const ops = await measureBenchmark(params.__benchmark, "react.resolveOpsMs", async () => await getContextEngineOps(params.runtime, params.__benchmark));
417
426
  const maxIterations = params.options?.maxIterations ?? 20;
418
427
  const maxModelSteps = params.options?.maxModelSteps ?? 1;
419
428
  const preventClose = params.options?.preventClose ?? false;
@@ -488,7 +497,7 @@ export class ContextEngine {
488
497
  }));
489
498
  currentStepId = stepCreate.stepId;
490
499
  currentStepStream = await createPersistedContextStepStream({
491
- env: params.env,
500
+ runtime: params.runtime,
492
501
  executionId,
493
502
  stepId: stepCreate.stepId,
494
503
  });
@@ -507,7 +516,7 @@ export class ContextEngine {
507
516
  ],
508
517
  });
509
518
  // Hook: Context DSL `context()` (implemented by subclasses via `initialize()`)
510
- const nextContent = await measureBenchmark(params.__benchmark, `${stagePrefix}.contextMs`, async () => await story.initialize(updatedContext, params.env));
519
+ const nextContent = await measureBenchmark(params.__benchmark, `${stagePrefix}.contextMs`, async () => await story.initialize(updatedContext, env));
511
520
  updatedContext = await measureBenchmark(params.__benchmark, `${stagePrefix}.persistContextMs`, async () => await ops.updateContextContent(activeContextSelector, nextContent));
512
521
  await emitContextEvents({
513
522
  silent,
@@ -520,12 +529,12 @@ export class ContextEngine {
520
529
  },
521
530
  ],
522
531
  });
523
- await story.opts.onContextUpdated?.({ env: params.env, context: updatedContext });
532
+ await story.opts.onContextUpdated?.({ env, context: updatedContext });
524
533
  // Hook: Context DSL `narrative()` (implemented by subclasses via `buildSystemPrompt()`)
525
- const systemPrompt = await measureBenchmark(params.__benchmark, `${stagePrefix}.narrativeMs`, async () => await story.buildSystemPrompt(updatedContext, params.env));
534
+ const systemPrompt = await measureBenchmark(params.__benchmark, `${stagePrefix}.narrativeMs`, async () => await story.buildSystemPrompt(updatedContext, env));
526
535
  // Hook: Context DSL `actions()` (implemented by subclasses via `buildTools()`)
527
- const toolsAll = await measureBenchmark(params.__benchmark, `${stagePrefix}.actionsMs`, async () => await story.buildTools(updatedContext, params.env));
528
- const skillsAll = await measureBenchmark(params.__benchmark, `${stagePrefix}.skillsMs`, async () => await story.buildSkills(updatedContext, params.env));
536
+ const toolsAll = await measureBenchmark(params.__benchmark, `${stagePrefix}.actionsMs`, async () => await story.buildTools(updatedContext, env));
537
+ const skillsAll = await measureBenchmark(params.__benchmark, `${stagePrefix}.skillsMs`, async () => await story.buildSkills(updatedContext, env));
529
538
  // IMPORTANT: step args must be serializable.
530
539
  // Match DurableAgent behavior: convert tool input schemas to plain JSON Schema in workflow context.
531
540
  const toolsForModel = toolsToModelTools(toolsAll);
@@ -536,7 +545,7 @@ export class ContextEngine {
536
545
  // If we stream with a per-step id, the UI will render an optimistic assistant message
537
546
  // (step id) and then a second persisted assistant message (reaction id) with the same
538
547
  // content once InstantDB updates.
539
- const reactor = story.getReactor(updatedContext, params.env);
548
+ const reactor = story.getReactor(updatedContext, env);
540
549
  const reactionPartsBeforeStep = Array.isArray(reactionEvent.content?.parts)
541
550
  ? [...reactionEvent.content.parts]
542
551
  : [];
@@ -564,11 +573,12 @@ export class ContextEngine {
564
573
  }, { executionId, contextId: String(currentContext.id) });
565
574
  };
566
575
  const { assistantEvent, actionRequests, messagesForModel } = await measureBenchmark(params.__benchmark, `${stagePrefix}.reactorMs`, async () => await reactor({
567
- env: params.env,
576
+ runtime: params.runtime,
577
+ env,
568
578
  context: updatedContext,
569
579
  contextIdentifier: activeContextSelector,
570
580
  triggerEvent,
571
- model: story.getModel(updatedContext, params.env),
581
+ model: story.getModel(updatedContext, env),
572
582
  systemPrompt,
573
583
  actions: toolsAll,
574
584
  toolsForModel,
@@ -651,7 +661,7 @@ export class ContextEngine {
651
661
  reactionEvent = await measureBenchmark(params.__benchmark, `${stagePrefix}.persistAssistantReactionMs`, async () => await ops.updateItem(reactionEvent.id, nextReactionEvent, { executionId, contextId: String(currentContext.id) }));
652
662
  if (currentStepStream) {
653
663
  await closePersistedContextStepStream({
654
- env: params.env,
664
+ runtime: params.runtime,
655
665
  session: currentStepStream,
656
666
  });
657
667
  currentStepStream = null;
@@ -832,12 +842,18 @@ export class ContextEngine {
832
842
  }
833
843
  }
834
844
  const output = await toolDef.execute(actionInput, {
845
+ runtime: params.runtime,
846
+ env,
847
+ context: updatedContext,
848
+ contextIdentifier: activeContextSelector,
835
849
  toolCallId: actionRequest.actionRef,
836
850
  messages: messagesForModel,
837
851
  eventId: reactionEventId,
838
852
  executionId,
839
853
  triggerEventId,
840
854
  contextId: currentContext.id,
855
+ stepId: String(stepCreate.stepId),
856
+ iteration: iter,
841
857
  });
842
858
  return { actionRequest, success: true, output };
843
859
  }
@@ -894,7 +910,7 @@ export class ContextEngine {
894
910
  // IMPORTANT: we call this after tool results have been merged into the persisted `reactionEvent`,
895
911
  // so stories can inspect `reactionEvent.content.parts` deterministically.
896
912
  const continueLoop = await measureBenchmark(params.__benchmark, `${stagePrefix}.shouldContinueMs`, async () => await story.shouldContinue({
897
- env: params.env,
913
+ env,
898
914
  context: updatedContext,
899
915
  reactionEvent,
900
916
  assistantEvent: assistantEventEffective,
@@ -1033,7 +1049,7 @@ export class ContextEngine {
1033
1049
  if (currentStepStream) {
1034
1050
  try {
1035
1051
  await abortPersistedContextStepStream({
1036
- env: params.env,
1052
+ runtime: params.runtime,
1037
1053
  session: currentStepStream,
1038
1054
  reason: error instanceof Error ? error.message : String(error),
1039
1055
  });
@@ -0,0 +1,11 @@
1
+ import type { ConcreteDomain } from "@ekairos/domain";
2
+ import type { ExplicitRuntimeLike } from "@ekairos/domain/runtime";
3
+ import type { ContextEnvironment } from "./context.config.js";
4
+ import type { ContextStore } from "./context.store.js";
5
+ export type ContextRuntime<Env extends ContextEnvironment = ContextEnvironment> = ExplicitRuntimeLike<Env, any, any>;
6
+ export type ContextRuntimeServices = {
7
+ db: any;
8
+ store: ContextStore;
9
+ domain?: ConcreteDomain<any, any>;
10
+ };
11
+ export declare function getContextRuntimeServices(runtime: ContextRuntime<any>): Promise<ContextRuntimeServices>;
@@ -0,0 +1,21 @@
1
+ const storeByDb = new WeakMap();
2
+ export async function getContextRuntimeServices(runtime) {
3
+ const db = await runtime.db();
4
+ if (!db) {
5
+ throw new Error("Context runtime did not provide a database instance.");
6
+ }
7
+ let store = typeof db === "object" && db !== null ? storeByDb.get(db) : undefined;
8
+ if (!store) {
9
+ const { InstantStore } = await import("./stores/instant.store.js");
10
+ store = new InstantStore(db);
11
+ if (typeof db === "object" && db !== null) {
12
+ storeByDb.set(db, store);
13
+ }
14
+ }
15
+ const resolved = await runtime.resolve();
16
+ return {
17
+ db,
18
+ store,
19
+ domain: typeof resolved === "object" && resolved !== null ? resolved.meta?.()?.domain : undefined,
20
+ };
21
+ }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { context, createContext, createAiSdkReactor, createScriptedReactor, type CreateAiSdkReactorOptions, type CreateScriptedReactorOptions, type ScriptedReactorStep, type ContextConfig, type ContextInstance, type ContextOptions, type ContextStreamOptions, type ContextReactor, type ContextReactorParams, type ContextReactionResult, type ContextActionRequest, type ContextReactionLLM, ContextEngine, type RegistrableContextBuilder, type ContextReactParams, type ContextReactResult, type ContextDurableWorkflowPayload, type ContextDurableWorkflowFunction, type ContextModelInit, type ContextTool, runContextReactionDirect, } from "./context.js";
1
+ export { context, createContext, createAiSdkReactor, createScriptedReactor, type CreateAiSdkReactorOptions, type CreateScriptedReactorOptions, type ScriptedReactorStep, type ContextConfig, type ContextInstance, type ContextOptions, type ContextStreamOptions, type ContextReactor, type ContextReactorParams, type ContextReactionResult, type ContextActionRequest, type ContextReactionLLM, ContextEngine, type RegistrableContextBuilder, type ContextReactParams, type ContextReactResult, type ContextWorkflowRun, type ContextDurableWorkflowPayload, type ContextDurableWorkflowFunction, type ContextModelInit, type ContextTool, type ContextToolExecuteContext, runContextReactionDirect, } from "./context.js";
2
2
  export type { ContextStore, ContextIdentifier, StoredContext, ContextItem, ContextExecution, } from "./context.store.js";
3
3
  export type { WireDate, ContextMirrorContext, ContextMirrorExecution, ContextMirrorWrite, ContextMirrorRequest, } from "./mirror.js";
4
4
  export { registerContext, getContext, getContextFactory, hasContext, listContexts, type ContextKey, } from "./context.registry.js";
@@ -1,9 +1,11 @@
1
1
  import type { ContextEnvironment } from "../context.config.js";
2
+ import type { ContextRuntime } from "../context.runtime.js";
2
3
  import type { ContextModelInit } from "../context.engine.js";
3
4
  import type { ContextIdentifier, StoredContext, ContextItem } from "../context.store.js";
4
5
  import type { ContextReactor } from "./types.js";
5
6
  export type CreateAiSdkReactorOptions<Context = unknown, Env extends ContextEnvironment = ContextEnvironment, Config = unknown> = {
6
7
  resolveConfig?: (params: {
8
+ runtime: ContextRuntime<Env>;
7
9
  env: Env;
8
10
  context: StoredContext<Context>;
9
11
  contextIdentifier: ContextIdentifier;
@@ -16,6 +18,7 @@ export type CreateAiSdkReactorOptions<Context = unknown, Env extends ContextEnvi
16
18
  iteration: number;
17
19
  }) => Promise<Config> | Config;
18
20
  selectModel?: (params: {
21
+ runtime: ContextRuntime<Env>;
19
22
  env: Env;
20
23
  context: StoredContext<Context>;
21
24
  triggerEvent: ContextItem;
@@ -23,6 +26,7 @@ export type CreateAiSdkReactorOptions<Context = unknown, Env extends ContextEnvi
23
26
  config: Config;
24
27
  }) => Promise<ContextModelInit> | ContextModelInit;
25
28
  selectMaxModelSteps?: (params: {
29
+ runtime: ContextRuntime<Env>;
26
30
  env: Env;
27
31
  context: StoredContext<Context>;
28
32
  triggerEvent: ContextItem;
@@ -4,6 +4,7 @@ export function createAiSdkReactor(options) {
4
4
  let config;
5
5
  if (options?.resolveConfig) {
6
6
  config = await options.resolveConfig({
7
+ runtime: params.runtime,
7
8
  env: params.env,
8
9
  context: params.context,
9
10
  contextIdentifier: params.contextIdentifier,
@@ -18,6 +19,7 @@ export function createAiSdkReactor(options) {
18
19
  }
19
20
  const model = options?.selectModel && config !== undefined
20
21
  ? await options.selectModel({
22
+ runtime: params.runtime,
21
23
  env: params.env,
22
24
  context: params.context,
23
25
  triggerEvent: params.triggerEvent,
@@ -27,6 +29,7 @@ export function createAiSdkReactor(options) {
27
29
  : params.model;
28
30
  const maxSteps = options?.selectMaxModelSteps && config !== undefined
29
31
  ? await options.selectMaxModelSteps({
32
+ runtime: params.runtime,
30
33
  env: params.env,
31
34
  context: params.context,
32
35
  triggerEvent: params.triggerEvent,
@@ -35,6 +38,7 @@ export function createAiSdkReactor(options) {
35
38
  })
36
39
  : params.maxModelSteps;
37
40
  const result = await executeAiSdkReaction({
41
+ runtime: params.runtime,
38
42
  env: params.env,
39
43
  contextIdentifier: params.contextIdentifier,
40
44
  model,
@@ -14,6 +14,7 @@ import type { SerializableToolForModel } from "../tools-to-model-tools.js";
14
14
  * - emit UI chunks and persist step stream chunks
15
15
  */
16
16
  export declare function executeAiSdkReaction(params: {
17
+ runtime: import("../context.runtime.js").ContextRuntime<ContextEnvironment>;
17
18
  env: ContextEnvironment;
18
19
  contextIdentifier: ContextIdentifier;
19
20
  model: ContextModelInit;
@@ -1,3 +1,4 @@
1
+ import { getContextRuntimeServices } from "../context.runtime.js";
1
2
  import { OUTPUT_ITEM_TYPE } from "../context.events.js";
2
3
  import { createContextStepStreamChunk, encodeContextStepStreamChunk, } from "../context.step-stream.js";
3
4
  import { mapAiSdkChunkToContextEvent } from "./ai-sdk.chunk-map.js";
@@ -82,8 +83,7 @@ function safeErrorJson(error) {
82
83
  */
83
84
  export async function executeAiSdkReaction(params) {
84
85
  "use step";
85
- const { getContextRuntime } = await import("../runtime.js");
86
- const { store } = await getContextRuntime(params.env);
86
+ const { store } = await getContextRuntimeServices(params.runtime);
87
87
  let events;
88
88
  try {
89
89
  events = await store.getItems(params.contextIdentifier);
@@ -221,7 +221,10 @@ export async function executeAiSdkReaction(params) {
221
221
  }
222
222
  }
223
223
  finally {
224
- contextStepStreamWriter?.releaseLock();
224
+ const streamWriter = contextStepStreamWriter;
225
+ if (typeof streamWriter?.releaseLock === "function") {
226
+ streamWriter.releaseLock();
227
+ }
225
228
  }
226
229
  const assistantEvent = await finishPromise;
227
230
  const finishedAtMs = Date.now();
@@ -1,5 +1,6 @@
1
1
  import type { ModelMessage, UIMessageChunk } from "ai";
2
2
  import type { ContextEnvironment } from "../context.config.js";
3
+ import type { ContextRuntime } from "../context.runtime.js";
3
4
  import type { ContextModelInit } from "../context.engine.js";
4
5
  import type { ContextIdentifier, StoredContext, ContextItem } from "../context.store.js";
5
6
  import type { ContextSkillPackage } from "../context.skill.js";
@@ -28,6 +29,7 @@ export type ContextReactionResult = {
28
29
  llm?: ContextReactionLLM;
29
30
  };
30
31
  export type ContextReactorParams<Context = unknown, Env extends ContextEnvironment = ContextEnvironment> = {
32
+ runtime: ContextRuntime<Env>;
31
33
  env: Env;
32
34
  context: StoredContext<Context>;
33
35
  contextIdentifier: ContextIdentifier;
@@ -1,7 +1,7 @@
1
1
  import { coerceContextRuntime } from "./context.config.js";
2
2
  import { eventsDomain } from "./schema.js";
3
3
  export async function getContextRuntime(env) {
4
- const { resolveRuntime } = await import("@ekairos/domain/runtime-step");
4
+ const { resolveRuntime } = await import("@ekairos/domain/runtime");
5
5
  const resolved = await resolveRuntime(eventsDomain, env);
6
6
  return await coerceContextRuntime(resolved);
7
7
  }