@ekairos/events 1.22.82-beta.development.0 → 1.22.84-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.
@@ -1,14 +1,14 @@
1
1
  import type { ModelMessage, UIMessageChunk } from "ai";
2
- import type { DomainSchemaResult } from "@ekairos/domain";
2
+ import type { DomainLike } from "@ekairos/domain";
3
3
  import type { ContextEnvironment } from "./context.config.js";
4
4
  import type { ContextTool } from "./context.action.js";
5
5
  import type { ContextRuntime, ContextRuntimeHandleForDomain, ContextRuntimeForDomain } from "./context.runtime.js";
6
6
  import { eventsDomain } from "./schema.js";
7
- import type { ContextExecution, ContextItem, ContextIdentifier, StoredContext } from "./context.store.js";
7
+ import type { ContextExecution, ContextItem, ContextIdentifier, ContextResource, StoredContext } from "./context.store.js";
8
8
  import type { ContextSkillPackage } from "./context.skill.js";
9
9
  import { type ContextReactor } from "./context.reactor.js";
10
10
  import { getClientResumeHookUrl, toolApprovalHookToken, toolApprovalWebhookToken } from "./context.hooks.js";
11
- export interface ContextOptions<Context = any, Env extends ContextEnvironment = ContextEnvironment, RequiredDomain extends DomainSchemaResult = typeof eventsDomain> {
11
+ export interface ContextOptions<Context = any, Env extends ContextEnvironment = ContextEnvironment, RequiredDomain extends DomainLike = typeof eventsDomain> {
12
12
  onContextCreated?: (args: {
13
13
  env: Env;
14
14
  runtime: ContextRuntimeHandleForDomain<Env, RequiredDomain>;
@@ -28,7 +28,7 @@ type ContextBenchmarkRecorder = {
28
28
  add?(name: string, value: number): void;
29
29
  getCurrentStage?(): string | undefined;
30
30
  };
31
- export declare function runContextReactionDirect<Context, Env extends ContextEnvironment = ContextEnvironment, RequiredDomain extends DomainSchemaResult = typeof eventsDomain, Runtime extends ContextRuntime<Env> = ContextRuntime<Env>>(context: ContextEngine<Context, Env, RequiredDomain>, triggerEvent: ContextItem, params: ContextReactParams<Env, RequiredDomain, Runtime>): Promise<ContextReactResult<Context>>;
31
+ export declare function runContextReactionDirect<Context, Env extends ContextEnvironment = ContextEnvironment, RequiredDomain extends DomainLike = typeof eventsDomain, Runtime extends ContextRuntime<Env> = ContextRuntime<Env>>(context: ContextEngine<Context, Env, RequiredDomain>, triggerEvent: ContextItem, params: ContextReactParams<Env, RequiredDomain, Runtime>): Promise<ContextReactResult<Context>>;
32
32
  export interface ContextStreamOptions {
33
33
  /**
34
34
  * Maximum loop iterations (LLM call → tool execution → repeat).
@@ -50,14 +50,6 @@ export interface ContextStreamOptions {
50
50
  * Default: true.
51
51
  */
52
52
  sendFinish?: boolean;
53
- /**
54
- * If true, the story loop runs silently (no UI streaming output).
55
- *
56
- * Persistence (contexts/events/executions) still happens normally.
57
- *
58
- * Default: false.
59
- */
60
- silent?: boolean;
61
53
  /**
62
54
  * Optional writable stream used by direct/non-durable execution.
63
55
  *
@@ -73,7 +65,7 @@ export interface ContextStreamOptions {
73
65
  * be a `"use-step"` function (so it can be serialized by reference).
74
66
  */
75
67
  export type ContextModelInit = string | (() => Promise<any>);
76
- export type ContextReactParams<Env extends ContextEnvironment = ContextEnvironment, RequiredDomain extends DomainSchemaResult = typeof eventsDomain, Runtime extends ContextRuntime<Env> = ContextRuntime<Env>> = {
68
+ export type ContextReactParams<Env extends ContextEnvironment = ContextEnvironment, RequiredDomain extends DomainLike = typeof eventsDomain, Runtime extends ContextRuntime<Env> = ContextRuntime<Env>> = {
77
69
  runtime: ContextRuntimeForDomain<Runtime, RequiredDomain>;
78
70
  /**
79
71
  * Context selector (exclusive: `{ id }` OR `{ key }`).
@@ -98,10 +90,10 @@ export type ContextReactParams<Env extends ContextEnvironment = ContextEnvironme
98
90
  __initialContent?: unknown;
99
91
  __benchmark?: ContextBenchmarkRecorder;
100
92
  };
101
- export type ContextDurableReactParams<Env extends ContextEnvironment = ContextEnvironment, RequiredDomain extends DomainSchemaResult = typeof eventsDomain, Runtime extends ContextRuntime<Env> = ContextRuntime<Env>> = Omit<ContextReactParams<Env, RequiredDomain, Runtime>, "durable"> & {
93
+ export type ContextDurableReactParams<Env extends ContextEnvironment = ContextEnvironment, RequiredDomain extends DomainLike = typeof eventsDomain, Runtime extends ContextRuntime<Env> = ContextRuntime<Env>> = Omit<ContextReactParams<Env, RequiredDomain, Runtime>, "durable"> & {
102
94
  durable?: true | undefined;
103
95
  };
104
- export type ContextDirectReactParams<Env extends ContextEnvironment = ContextEnvironment, RequiredDomain extends DomainSchemaResult = typeof eventsDomain, Runtime extends ContextRuntime<Env> = ContextRuntime<Env>> = Omit<ContextReactParams<Env, RequiredDomain, Runtime>, "durable"> & {
96
+ export type ContextDirectReactParams<Env extends ContextEnvironment = ContextEnvironment, RequiredDomain extends DomainLike = typeof eventsDomain, Runtime extends ContextRuntime<Env> = ContextRuntime<Env>> = Omit<ContextReactParams<Env, RequiredDomain, Runtime>, "durable"> & {
105
97
  durable: false;
106
98
  };
107
99
  export type ContextReactBase<Context = any> = {
@@ -125,7 +117,7 @@ export type ContextReactRun<Context = any> = ContextWorkflowRun<Context> | Conte
125
117
  export type ContextReactResult<Context = any, Run extends ContextReactRun<Context> = ContextReactRun<Context>> = ContextReactBase<Context> & {
126
118
  run?: Run;
127
119
  };
128
- export type ContextDurableWorkflowPayload<Env extends ContextEnvironment = ContextEnvironment, RequiredDomain extends DomainSchemaResult = typeof eventsDomain, Runtime extends ContextRuntime<Env> = ContextRuntime<Env>> = {
120
+ export type ContextDurableWorkflowPayload<Env extends ContextEnvironment = ContextEnvironment, RequiredDomain extends DomainLike = typeof eventsDomain, Runtime extends ContextRuntime<Env> = ContextRuntime<Env>> = {
129
121
  contextKey: string;
130
122
  runtime: ContextRuntimeForDomain<Runtime, RequiredDomain>;
131
123
  context?: ContextIdentifier | null;
@@ -133,8 +125,8 @@ export type ContextDurableWorkflowPayload<Env extends ContextEnvironment = Conte
133
125
  options?: Omit<ContextStreamOptions, "writable">;
134
126
  bootstrap: NonNullable<ContextReactParams<Env, RequiredDomain, Runtime>["__bootstrap"]>;
135
127
  };
136
- export type ContextDurableWorkflowFunction<Context = any, Env extends ContextEnvironment = ContextEnvironment, RequiredDomain extends DomainSchemaResult = typeof eventsDomain, Runtime extends ContextRuntime<Env> = ContextRuntime<Env>> = (payload: ContextDurableWorkflowPayload<Env, RequiredDomain, Runtime>) => Promise<ContextReactFinalResult<Context>>;
137
- export type ContextToolExecuteContext<Context = any, Env extends ContextEnvironment = ContextEnvironment, RequiredDomain extends DomainSchemaResult = typeof eventsDomain, Runtime extends ContextRuntime<Env> = ContextRuntime<Env>> = {
128
+ export type ContextDurableWorkflowFunction<Context = any, Env extends ContextEnvironment = ContextEnvironment, RequiredDomain extends DomainLike = typeof eventsDomain, Runtime extends ContextRuntime<Env> = ContextRuntime<Env>> = (payload: ContextDurableWorkflowPayload<Env, RequiredDomain, Runtime>) => Promise<ContextReactFinalResult<Context>>;
129
+ export type ContextToolExecuteContext<Context = any, Env extends ContextEnvironment = ContextEnvironment, RequiredDomain extends DomainLike = typeof eventsDomain, Runtime extends ContextRuntime<Env> = ContextRuntime<Env>> = {
138
130
  runtime: ContextRuntimeForDomain<Runtime, RequiredDomain>;
139
131
  context: StoredContext<Context>;
140
132
  contextIdentifier: ContextIdentifier;
@@ -168,7 +160,7 @@ export { toolApprovalHookToken, toolApprovalWebhookToken, getClientResumeHookUrl
168
160
  * (No imports required in callers.)
169
161
  */
170
162
  export type ShouldContinue = boolean;
171
- export type ContextShouldContinueArgs<Context = any, Env extends ContextEnvironment = ContextEnvironment, RequiredDomain extends DomainSchemaResult = typeof eventsDomain> = {
163
+ export type ContextShouldContinueArgs<Context = any, Env extends ContextEnvironment = ContextEnvironment, RequiredDomain extends DomainLike = typeof eventsDomain> = {
172
164
  env: Env;
173
165
  runtime: ContextRuntimeHandleForDomain<Env, RequiredDomain>;
174
166
  context: StoredContext<Context>;
@@ -199,12 +191,15 @@ export type ContextShouldContinueArgs<Context = any, Env extends ContextEnvironm
199
191
  errorText?: string;
200
192
  }>;
201
193
  };
202
- export declare abstract class ContextEngine<Context, Env extends ContextEnvironment = ContextEnvironment, RequiredDomain extends DomainSchemaResult = typeof eventsDomain> {
194
+ export declare abstract class ContextEngine<Context, Env extends ContextEnvironment = ContextEnvironment, RequiredDomain extends DomainLike = typeof eventsDomain> {
203
195
  protected readonly opts: ContextOptions<Context, Env, RequiredDomain>;
204
196
  private readonly reactor;
205
197
  constructor(opts?: ContextOptions<Context, Env, RequiredDomain>, reactor?: ContextReactor<Context, Env, RequiredDomain>);
206
198
  protected abstract initialize(context: StoredContext<Context>, env: Env, runtime: ContextRuntimeHandleForDomain<Env, RequiredDomain>): Promise<Context> | Context;
207
199
  protected abstract buildSystemPrompt(context: StoredContext<Context>, env: Env, runtime: ContextRuntimeHandleForDomain<Env, RequiredDomain>): Promise<string> | string;
200
+ protected describeContext(_content: Context, _context: StoredContext<Context>, _env: Env, _runtime: ContextRuntimeHandleForDomain<Env, RequiredDomain>): Promise<string | null>;
201
+ protected defineGoal(_content: Context, _context: StoredContext<Context>, _env: Env, _runtime: ContextRuntimeHandleForDomain<Env, RequiredDomain>): Promise<string | null>;
202
+ protected defineResources(_content: Context, _context: StoredContext<Context>, _env: Env, _runtime: ContextRuntimeHandleForDomain<Env, RequiredDomain>): Promise<ContextResource[]>;
208
203
  protected abstract buildTools(context: StoredContext<Context>, env: Env, runtime: ContextRuntimeHandleForDomain<Env, RequiredDomain>): Promise<Record<string, ContextTool<Context, Env, RequiredDomain>>> | Record<string, ContextTool<Context, Env, RequiredDomain>>;
209
204
  protected buildSkills(_context: StoredContext<Context>, _env: Env, _runtime: ContextRuntimeHandleForDomain<Env, RequiredDomain>): Promise<ContextSkillPackage[]>;
210
205
  /**
@@ -241,7 +236,7 @@ export declare abstract class ContextEngine<Context, Env extends ContextEnvironm
241
236
  react<Runtime extends ContextRuntime<Env>>(triggerEvent: ContextItem, params: ContextReactParams<Env, RequiredDomain, Runtime>): Promise<ContextReactResult<Context>>;
242
237
  private static prepareExecutionShell;
243
238
  private static startDurable;
244
- static runDirect<Context, Env extends ContextEnvironment, RequiredDomain extends DomainSchemaResult, Runtime extends ContextRuntime<Env>>(story: ContextEngine<Context, Env, RequiredDomain>, triggerEvent: ContextItem, params: ContextReactParams<Env, RequiredDomain, Runtime>): Promise<ContextReactResult<Context, ContextDirectRun<Context>>>;
239
+ static runDirect<Context, Env extends ContextEnvironment, RequiredDomain extends DomainLike, Runtime extends ContextRuntime<Env>>(story: ContextEngine<Context, Env, RequiredDomain>, triggerEvent: ContextItem, params: ContextReactParams<Env, RequiredDomain, Runtime>): Promise<ContextReactResult<Context, ContextDirectRun<Context>>>;
245
240
  /**
246
241
  * @deprecated Use `react()` instead. Kept for backwards compatibility.
247
242
  */
@@ -1,10 +1,10 @@
1
1
  import { getContextRuntimeServices } from "./context.runtime.js";
2
2
  import { OUTPUT_ITEM_TYPE, WEB_CHANNEL } from "./context.events.js";
3
- import { applyToolExecutionResultToParts } from "./context.toolcalls.js";
3
+ import { applyActionExecutionResultToParts } from "./context.action-calls.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, 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";
7
+ import { completeExecution, completeExecutionStep, createContextStep, getContextItems, initializeContext, openExecutionStep, openExecution, saveExecutionStepOutput, updateContextContent, updateContextDefinition, updateContextReactor, updateContextStatus, updateItem, updateContextStep, updateExecutionWorkflowRun, upsertContextResources, } 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";
@@ -188,6 +188,8 @@ async function createRuntimeOps(runtimeHandle, benchmark) {
188
188
  return { context, isNew: true };
189
189
  },
190
190
  updateContextContent: async (contextIdentifier, content) => await store.updateContextContent(contextIdentifier, content),
191
+ updateContextDefinition: async (contextIdentifier, definition) => await store.updateContextDefinition(contextIdentifier, definition),
192
+ upsertContextResources: async (contextIdentifier, resources) => await store.upsertContextResources(contextIdentifier, resources),
191
193
  updateContextReactor: async (contextIdentifier, reactor) => await store.updateContextReactor(contextIdentifier, reactor),
192
194
  updateContextStatus: async (contextIdentifier, status) => await instrumentedDb.transact([
193
195
  instrumentedDb.tx.event_contexts[requireContextId(contextIdentifier)].update({
@@ -390,8 +392,10 @@ async function createRuntimeOps(runtimeHandle, benchmark) {
390
392
  async function createWorkflowOps(runtime) {
391
393
  const env = runtime.env;
392
394
  return {
393
- initializeContext: async (contextIdentifier, opts) => await initializeContext({ runtime, contextIdentifier, opts }),
395
+ initializeContext: async (contextIdentifier) => await initializeContext({ runtime, contextIdentifier }),
394
396
  updateContextContent: async (contextIdentifier, content) => await updateContextContent({ runtime, contextIdentifier, content }),
397
+ updateContextDefinition: async (contextIdentifier, definition) => await updateContextDefinition({ runtime, contextIdentifier, definition }),
398
+ upsertContextResources: async (contextIdentifier, resources) => await upsertContextResources({ runtime, contextIdentifier, resources }),
395
399
  updateContextReactor: async (contextIdentifier, reactor) => await updateContextReactor({ runtime, contextIdentifier, reactor }),
396
400
  updateContextStatus: async (contextIdentifier, status) => await updateContextStatus({ runtime, contextIdentifier, status }),
397
401
  openExecution: async ({ contextIdentifier, triggerEvent }) => await openExecution({ runtime, contextIdentifier, triggerEvent }),
@@ -420,6 +424,15 @@ export class ContextEngine {
420
424
  reactor ??
421
425
  createAiSdkReactor();
422
426
  }
427
+ async describeContext(_content, _context, _env, _runtime) {
428
+ return null;
429
+ }
430
+ async defineGoal(_content, _context, _env, _runtime) {
431
+ return null;
432
+ }
433
+ async defineResources(_content, _context, _env, _runtime) {
434
+ return [];
435
+ }
423
436
  async buildSkills(_context, _env, _runtime) {
424
437
  return [];
425
438
  }
@@ -470,8 +483,7 @@ export class ContextEngine {
470
483
  const runtimeHandle = await resolveReactRuntime(params);
471
484
  const env = runtimeHandle.env;
472
485
  const ops = await measureBenchmark(params.__benchmark, "react.resolveOpsMs", async () => await getContextEngineOps(runtimeHandle, params.__benchmark));
473
- const silent = params.options?.silent ?? false;
474
- const ctxResult = await measureBenchmark(params.__benchmark, "react.initializeContextMs", async () => await ops.initializeContext(params.context ?? null, { silent }));
486
+ const ctxResult = await measureBenchmark(params.__benchmark, "react.initializeContextMs", async () => await ops.initializeContext(params.context ?? null));
475
487
  let currentContext = ctxResult.context;
476
488
  const contextSelector = { id: String(currentContext.id) };
477
489
  if (ctxResult.isNew) {
@@ -566,7 +578,6 @@ export class ContextEngine {
566
578
  maxModelSteps: params.options?.maxModelSteps,
567
579
  preventClose: params.options?.preventClose,
568
580
  sendFinish: params.options?.sendFinish,
569
- silent: params.options?.silent,
570
581
  },
571
582
  bootstrap: {
572
583
  contextId: shell.currentContext.id,
@@ -634,7 +645,6 @@ export class ContextEngine {
634
645
  const maxModelSteps = params.options?.maxModelSteps ?? 1;
635
646
  const preventClose = params.options?.preventClose ?? false;
636
647
  const sendFinish = params.options?.sendFinish ?? true;
637
- const silent = params.options?.silent ?? false;
638
648
  const writable = params.options?.writable;
639
649
  const bootstrapped = params.__bootstrap;
640
650
  const returnValueHookToken = bootstrapped?.returnValueHookToken ?? null;
@@ -649,7 +659,7 @@ export class ContextEngine {
649
659
  const shell = bootstrapped
650
660
  ? {
651
661
  contextSelector: { id: String(bootstrapped.contextId) },
652
- currentContext: (await measureBenchmark(params.__benchmark, "react.bootstrapContextLookupMs", async () => await ops.initializeContext({ id: String(bootstrapped.contextId) }, { silent }))).context,
662
+ currentContext: (await measureBenchmark(params.__benchmark, "react.bootstrapContextLookupMs", async () => await ops.initializeContext({ id: String(bootstrapped.contextId) }))).context,
653
663
  trigger: bootstrapped.trigger,
654
664
  reaction: bootstrapped.reaction,
655
665
  execution: bootstrapped.execution,
@@ -672,7 +682,6 @@ export class ContextEngine {
672
682
  execution = { ...execution, status: "failed" };
673
683
  updatedContext = { ...updatedContext, status: "closed" };
674
684
  await emitContextEvents({
675
- silent,
676
685
  writable,
677
686
  events: [
678
687
  {
@@ -695,9 +704,7 @@ export class ContextEngine {
695
704
  // noop
696
705
  }
697
706
  try {
698
- if (!silent) {
699
- await closeContextStream({ preventClose, sendFinish, writable });
700
- }
707
+ await closeContextStream({ preventClose, sendFinish, writable });
701
708
  }
702
709
  catch {
703
710
  // noop
@@ -706,6 +713,13 @@ export class ContextEngine {
706
713
  try {
707
714
  for (let iter = 0; iter < maxIterations; iter++) {
708
715
  const stagePrefix = `react.iteration.${iter}`;
716
+ runtimeHandle.__ekairosContextRun = {
717
+ contextId: currentContext.id,
718
+ executionId,
719
+ triggerEventId,
720
+ reactionEventId,
721
+ iteration: iter,
722
+ };
709
723
  // Hook: Context DSL `context()` (implemented by subclasses via `initialize()`)
710
724
  const nextContent = await measureBenchmark(params.__benchmark, `${stagePrefix}.contextMs`, async () => await story.initialize(updatedContext, env, runtimeHandle));
711
725
  const openedStep = await measureBenchmark(params.__benchmark, `${stagePrefix}.openExecutionStepMs`, async () => await ops.openExecutionStep({
@@ -718,8 +732,36 @@ export class ContextEngine {
718
732
  currentStepStream = openedStep.stream;
719
733
  updatedContext = openedStep.context;
720
734
  const rawEvents = openedStep.events;
735
+ const previousResources = updatedContext.resources ?? [];
736
+ const resources = await measureBenchmark(params.__benchmark, `${stagePrefix}.resourcesMs`, async () => await story.defineResources(nextContent, updatedContext, env, runtimeHandle));
737
+ const shouldPersistResources = resources.length > 0 || previousResources.length > 0;
738
+ let contextResources = previousResources;
739
+ if (shouldPersistResources) {
740
+ contextResources = await measureBenchmark(params.__benchmark, `${stagePrefix}.contextResourcesMs`, async () => await ops.upsertContextResources(activeContextSelector, resources));
741
+ updatedContext = {
742
+ ...updatedContext,
743
+ resources: contextResources,
744
+ };
745
+ }
746
+ else {
747
+ updatedContext = {
748
+ ...updatedContext,
749
+ resources: [],
750
+ };
751
+ }
752
+ const description = await measureBenchmark(params.__benchmark, `${stagePrefix}.descriptionMs`, async () => await story.describeContext(nextContent, updatedContext, env, runtimeHandle));
753
+ const goal = await measureBenchmark(params.__benchmark, `${stagePrefix}.goalMs`, async () => await story.defineGoal(nextContent, updatedContext, env, runtimeHandle));
754
+ if (description !== null || goal !== null) {
755
+ updatedContext = await measureBenchmark(params.__benchmark, `${stagePrefix}.contextDefinitionMs`, async () => await ops.updateContextDefinition(activeContextSelector, {
756
+ ...(description !== null ? { description } : {}),
757
+ ...(goal !== null ? { goal } : {}),
758
+ }));
759
+ updatedContext = {
760
+ ...updatedContext,
761
+ resources: contextResources,
762
+ };
763
+ }
721
764
  await emitContextEvents({
722
- silent,
723
765
  writable,
724
766
  events: [
725
767
  {
@@ -735,6 +777,24 @@ export class ContextEngine {
735
777
  at: nowIso(),
736
778
  contextId: String(updatedContext.id),
737
779
  },
780
+ ...(description !== null || goal !== null
781
+ ? [
782
+ {
783
+ type: "context.definition_updated",
784
+ at: nowIso(),
785
+ contextId: String(updatedContext.id),
786
+ },
787
+ ]
788
+ : []),
789
+ ...(shouldPersistResources
790
+ ? [
791
+ {
792
+ type: "context.resources_updated",
793
+ at: nowIso(),
794
+ contextId: String(updatedContext.id),
795
+ },
796
+ ]
797
+ : []),
738
798
  ],
739
799
  });
740
800
  await story.opts.onContextUpdated?.({
@@ -788,6 +848,7 @@ export class ContextEngine {
788
848
  runtime: runtimeHandle,
789
849
  context: updatedContext,
790
850
  contextIdentifier: activeContextSelector,
851
+ resources: contextResources,
791
852
  events: expandedEvents,
792
853
  triggerEvent,
793
854
  model: story.getModel(updatedContext, env, runtimeHandle),
@@ -801,8 +862,7 @@ export class ContextEngine {
801
862
  iteration: iter,
802
863
  maxModelSteps,
803
864
  // Only emit a `start` chunk once per story turn.
804
- sendStart: !silent && iter === 0,
805
- silent,
865
+ sendStart: iter === 0,
806
866
  contextStepStream: currentStepStream?.stream,
807
867
  writable,
808
868
  persistReactionParts,
@@ -858,7 +918,6 @@ export class ContextEngine {
858
918
  }));
859
919
  reactionEvent = appendedReactorOutput.reactionEvent;
860
920
  await emitContextEvents({
861
- silent,
862
921
  writable,
863
922
  events: stepParts.map((part, idx) => ({
864
923
  type: "part.created",
@@ -883,7 +942,6 @@ export class ContextEngine {
883
942
  }
884
943
  story.opts.onEventCreated?.(assistantEventEffective);
885
944
  await emitContextEvents({
886
- silent,
887
945
  writable,
888
946
  events: [
889
947
  {
@@ -918,7 +976,6 @@ export class ContextEngine {
918
976
  currentStepId = null;
919
977
  reactionEvent = finalized.reactionEvent ?? completedReactionEvent;
920
978
  await emitContextEvents({
921
- silent,
922
979
  writable,
923
980
  events: [
924
981
  {
@@ -940,7 +997,6 @@ export class ContextEngine {
940
997
  ],
941
998
  });
942
999
  await emitContextEvents({
943
- silent,
944
1000
  writable,
945
1001
  events: [
946
1002
  {
@@ -957,7 +1013,6 @@ export class ContextEngine {
957
1013
  execution = { ...execution, status: "completed" };
958
1014
  updatedContext = { ...updatedContext, status: "closed" };
959
1015
  await emitContextEvents({
960
- silent,
961
1016
  writable,
962
1017
  events: [
963
1018
  {
@@ -975,9 +1030,7 @@ export class ContextEngine {
975
1030
  },
976
1031
  ],
977
1032
  });
978
- if (!silent) {
979
- await closeContextStream({ preventClose, sendFinish, writable });
980
- }
1033
+ await closeContextStream({ preventClose, sendFinish, writable });
981
1034
  const result = {
982
1035
  context: updatedContext,
983
1036
  trigger,
@@ -1057,9 +1110,9 @@ export class ContextEngine {
1057
1110
  // Merge action results into step parts so the next reaction can see them.
1058
1111
  let finalizedStepParts = Array.isArray(stepParts) ? [...stepParts] : [];
1059
1112
  for (const r of actionResults) {
1060
- finalizedStepParts = applyToolExecutionResultToParts(finalizedStepParts, {
1061
- toolCallId: r.actionRequest.actionRef,
1062
- toolName: r.actionRequest.actionName,
1113
+ finalizedStepParts = applyActionExecutionResultToParts(finalizedStepParts, {
1114
+ actionCallId: r.actionRequest.actionRef,
1115
+ actionName: r.actionRequest.actionName,
1063
1116
  }, {
1064
1117
  success: Boolean(r.success),
1065
1118
  result: r.output,
@@ -1092,12 +1145,10 @@ export class ContextEngine {
1092
1145
  currentStepId = null;
1093
1146
  reactionEvent = completedStep.reactionEvent ?? pendingReactionEvent;
1094
1147
  await emitContextEvents({
1095
- silent,
1096
1148
  writable,
1097
1149
  events: completedStep.actionResultChunkEvents,
1098
1150
  });
1099
1151
  await emitContextEvents({
1100
- silent,
1101
1152
  writable,
1102
1153
  events: [
1103
1154
  {
@@ -1142,7 +1193,6 @@ export class ContextEngine {
1142
1193
  }));
1143
1194
  if (continueLoop !== false) {
1144
1195
  await emitContextEvents({
1145
- silent,
1146
1196
  writable,
1147
1197
  events: [
1148
1198
  {
@@ -1162,7 +1212,6 @@ export class ContextEngine {
1162
1212
  status: "completed",
1163
1213
  };
1164
1214
  await emitContextEvents({
1165
- silent,
1166
1215
  writable,
1167
1216
  events: [
1168
1217
  {
@@ -1183,7 +1232,6 @@ export class ContextEngine {
1183
1232
  execution = { ...execution, status: "completed" };
1184
1233
  updatedContext = { ...updatedContext, status: "closed" };
1185
1234
  await emitContextEvents({
1186
- silent,
1187
1235
  writable,
1188
1236
  events: [
1189
1237
  {
@@ -1201,9 +1249,7 @@ export class ContextEngine {
1201
1249
  },
1202
1250
  ],
1203
1251
  });
1204
- if (!silent) {
1205
- await closeContextStream({ preventClose, sendFinish, writable });
1206
- }
1252
+ await closeContextStream({ preventClose, sendFinish, writable });
1207
1253
  const result = {
1208
1254
  context: updatedContext,
1209
1255
  trigger,
@@ -1246,7 +1292,6 @@ export class ContextEngine {
1246
1292
  contextId: String(currentContext.id),
1247
1293
  }));
1248
1294
  await emitContextEvents({
1249
- silent,
1250
1295
  writable,
1251
1296
  events: [
1252
1297
  {
@@ -216,6 +216,58 @@ function normalizeFileContentBlock(value) {
216
216
  fileId: typeof value.fileId === "string" ? value.fileId : undefined,
217
217
  }));
218
218
  }
219
+ function normalizeInlineContentBlock(value) {
220
+ const record = asRecord(value);
221
+ if (!record || typeof record.type !== "string")
222
+ return null;
223
+ if (record.type === "text" && typeof record.text === "string") {
224
+ return contextInlineContentSchema.parse({ type: "text", text: record.text });
225
+ }
226
+ if (record.type === "json") {
227
+ return contextInlineContentSchema.parse({ type: "json", value: record.value });
228
+ }
229
+ if (record.type === "file" || record.type === "image-data") {
230
+ return normalizeFileContentBlock(record);
231
+ }
232
+ return null;
233
+ }
234
+ function normalizeInlineContentBlocks(value) {
235
+ if (!Array.isArray(value))
236
+ return [];
237
+ return value
238
+ .map((block) => normalizeInlineContentBlock(block))
239
+ .filter((block) => Boolean(block));
240
+ }
241
+ function contentBlocksToActionValue(blocks) {
242
+ if (blocks.length === 0)
243
+ return undefined;
244
+ if (blocks.length === 1) {
245
+ const [first] = blocks;
246
+ if (first.type === "json")
247
+ return first.value;
248
+ if (first.type === "text")
249
+ return first.text;
250
+ if (first.type === "file")
251
+ return first;
252
+ }
253
+ return {
254
+ type: "content",
255
+ value: blocks,
256
+ };
257
+ }
258
+ function contentBlocksToErrorMessage(blocks) {
259
+ const text = blocks
260
+ .filter((block) => block.type === "text")
261
+ .map((block) => block.text)
262
+ .join("\n\n")
263
+ .trim();
264
+ if (text)
265
+ return text;
266
+ const jsonBlock = blocks.find((block) => block.type === "json");
267
+ if (jsonBlock)
268
+ return JSON.stringify(jsonBlock.value, null, 2);
269
+ return "";
270
+ }
219
271
  function readReactorMetadata(record) {
220
272
  const parsed = reactorMetadataSchema.safeParse(record.reactorMetadata);
221
273
  return parsed.success ? parsed.data : undefined;
@@ -239,6 +291,62 @@ function messageFromBlocks(blocks, reactorMetadata) {
239
291
  })),
240
292
  ];
241
293
  }
294
+ function normalizeExternalToolCallPart(record, reactorMetadata) {
295
+ const actionName = typeof record.toolName === "string" && record.toolName.length > 0
296
+ ? record.toolName
297
+ : "";
298
+ const actionCallId = typeof record.toolCallId === "string" && record.toolCallId.length > 0
299
+ ? record.toolCallId
300
+ : "";
301
+ if (!actionName || !actionCallId)
302
+ return [];
303
+ const blocks = normalizeInlineContentBlocks(record.content);
304
+ return [
305
+ contextActionPartSchema.parse(cleanRecord({
306
+ type: "action",
307
+ content: {
308
+ status: "started",
309
+ actionName,
310
+ actionCallId,
311
+ input: contentBlocksToActionValue(blocks),
312
+ },
313
+ reactorMetadata,
314
+ })),
315
+ ];
316
+ }
317
+ function normalizeExternalToolResultPart(record, reactorMetadata) {
318
+ const actionName = typeof record.toolName === "string" && record.toolName.length > 0
319
+ ? record.toolName
320
+ : "";
321
+ const actionCallId = typeof record.toolCallId === "string" && record.toolCallId.length > 0
322
+ ? record.toolCallId
323
+ : "";
324
+ if (!actionName || !actionCallId)
325
+ return [];
326
+ const blocks = normalizeInlineContentBlocks(record.content);
327
+ const failed = record.state === "output-error";
328
+ return [
329
+ contextActionPartSchema.parse(cleanRecord({
330
+ type: "action",
331
+ content: failed
332
+ ? {
333
+ status: "failed",
334
+ actionName,
335
+ actionCallId,
336
+ error: {
337
+ message: contentBlocksToErrorMessage(blocks) || "Action execution failed.",
338
+ },
339
+ }
340
+ : {
341
+ status: "completed",
342
+ actionName,
343
+ actionCallId,
344
+ output: contentBlocksToActionValue(blocks),
345
+ },
346
+ reactorMetadata,
347
+ })),
348
+ ];
349
+ }
242
350
  export function normalizeUiPartToContextPartEnvelopes(value) {
243
351
  const record = asRecord(value);
244
352
  if (!record || typeof record.type !== "string") {
@@ -307,6 +415,12 @@ export function normalizeUiPartToContextPartEnvelopes(value) {
307
415
  if (record.type.startsWith("data-")) {
308
416
  return messageFromBlocks([{ type: "json", value: record.data }], reactorMetadata);
309
417
  }
418
+ if (record.type === "tool-call") {
419
+ return normalizeExternalToolCallPart(record, reactorMetadata);
420
+ }
421
+ if (record.type === "tool-result") {
422
+ return normalizeExternalToolResultPart(record, reactorMetadata);
423
+ }
310
424
  if (record.type.startsWith("tool-")) {
311
425
  const actionName = record.type.slice("tool-".length);
312
426
  const actionCallId = typeof record.toolCallId === "string" ? record.toolCallId : "";
@@ -1,4 +1,4 @@
1
- import type { ActiveDomain, ConcreteDomain, DomainSchemaResult } from "@ekairos/domain";
1
+ import type { ConcreteDomain, DomainLike } from "@ekairos/domain";
2
2
  import type { EkairosRuntime, RuntimeForDomain, RuntimeResolveOptions } from "@ekairos/domain/runtime";
3
3
  import type { ContextEnvironment } from "./context.config.js";
4
4
  import type { ContextStore } from "./context.store.js";
@@ -9,10 +9,10 @@ export type ContextRuntimeServiceHandle = {
9
9
  resolve?: (...args: any[]) => Promise<any> | any;
10
10
  meta?: (...args: any[]) => Record<string, unknown> | undefined;
11
11
  };
12
- export type ContextRuntimeHandleForDomain<Env extends ContextEnvironment = ContextEnvironment, RequiredDomain extends DomainSchemaResult = typeof eventsDomain> = ContextRuntimeServiceHandle & {
13
- use<Subdomain extends typeof eventsDomain | RequiredDomain>(subdomain: Subdomain, options?: RuntimeResolveOptions): Promise<Omit<ActiveDomain<Subdomain, Env>, "env">>;
12
+ export type ContextRuntimeHandleForDomain<Env extends ContextEnvironment = ContextEnvironment, RequiredDomain extends DomainLike = typeof eventsDomain> = ContextRuntimeServiceHandle & {
13
+ use<Subdomain extends typeof eventsDomain | RequiredDomain>(subdomain: Subdomain, options?: RuntimeResolveOptions): Promise<unknown>;
14
14
  };
15
- export type ContextRuntimeForDomain<Runtime extends ContextRuntime<any>, RequiredDomain extends DomainSchemaResult = typeof eventsDomain> = RuntimeForDomain<Runtime, typeof eventsDomain> & RuntimeForDomain<Runtime, RequiredDomain>;
15
+ export type ContextRuntimeForDomain<Runtime extends ContextRuntime<any>, RequiredDomain extends DomainLike = typeof eventsDomain> = RuntimeForDomain<Runtime, typeof eventsDomain> & RuntimeForDomain<Runtime, RequiredDomain>;
16
16
  export type ContextRuntimeServices = {
17
17
  db: any;
18
18
  store: ContextStore;
@@ -8,6 +8,50 @@ export type ContextIdentifier = {
8
8
  id?: never;
9
9
  };
10
10
  export type { ContextStatus } from "./context.contract.js";
11
+ export type ContextResourceBase = {
12
+ key: string;
13
+ type: string;
14
+ name: string;
15
+ description: string;
16
+ role?: string | null;
17
+ metadata?: Record<string, unknown> | null;
18
+ };
19
+ export type ContextFileResource = ContextResourceBase & {
20
+ type: "file";
21
+ fileId?: string;
22
+ documentId?: string;
23
+ url?: string;
24
+ filename?: string;
25
+ mediaType?: string;
26
+ size?: number;
27
+ };
28
+ export type ContextLinkResource = ContextResourceBase & {
29
+ type: "link";
30
+ url: string;
31
+ };
32
+ export type ContextRepositoryResource = ContextResourceBase & {
33
+ type: "repository";
34
+ provider?: string;
35
+ repository: string;
36
+ ref?: string;
37
+ paths?: string[];
38
+ commitSha?: string;
39
+ };
40
+ export type ContextDatasetResource = ContextResourceBase & {
41
+ type: "dataset";
42
+ datasetId: string;
43
+ };
44
+ export type ContextExternalResource = ContextResourceBase & {
45
+ type: "external";
46
+ uri?: string;
47
+ };
48
+ export type ContextResource = ContextFileResource | ContextLinkResource | ContextRepositoryResource | ContextDatasetResource | ContextExternalResource | (ContextResourceBase & Record<string, unknown>);
49
+ export type StoredContextResource = ContextResource & {
50
+ id?: string;
51
+ storageKey?: string;
52
+ createdAt?: Date;
53
+ updatedAt?: Date;
54
+ };
11
55
  export type StoredContext<Context> = {
12
56
  id: string;
13
57
  key: string | null;
@@ -16,6 +60,9 @@ export type StoredContext<Context> = {
16
60
  createdAt: Date;
17
61
  updatedAt?: Date;
18
62
  content: Context | null;
63
+ description?: string | null;
64
+ goal?: string | null;
65
+ resources?: StoredContextResource[] | null;
19
66
  reactor?: {
20
67
  kind: string;
21
68
  state?: Record<string, unknown> | null;
@@ -53,6 +100,12 @@ export interface ContextStore {
53
100
  getOrCreateContext<C>(contextIdentifier: ContextIdentifier | null): Promise<StoredContext<C>>;
54
101
  getContext<C>(contextIdentifier: ContextIdentifier): Promise<StoredContext<C> | null>;
55
102
  updateContextContent<C>(contextIdentifier: ContextIdentifier, content: C): Promise<StoredContext<C>>;
103
+ updateContextDefinition<C>(contextIdentifier: ContextIdentifier, definition: {
104
+ description?: string | null;
105
+ goal?: string | null;
106
+ }): Promise<StoredContext<C>>;
107
+ upsertContextResources(contextIdentifier: ContextIdentifier, resources: ContextResource[]): Promise<StoredContextResource[]>;
108
+ getContextResources(contextIdentifier: ContextIdentifier): Promise<StoredContextResource[]>;
56
109
  updateContextReactor<C>(contextIdentifier: ContextIdentifier, reactor: {
57
110
  kind: string;
58
111
  state?: Record<string, unknown> | null;