@ekairos/story 1.21.40-beta.0 → 1.21.43-beta.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,15 +1,4 @@
1
1
  import { configureStoryRuntime, configureStoryRuntimeBootstrap, isStoryRuntimeConfigured, } from "./story.config";
2
- const GLOBAL_EKAIROS_CONFIG = Symbol.for("@ekairos/story.ekairosConfig");
3
- function setGlobalEkairosConfig(config) {
4
- try {
5
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
- ;
7
- globalThis[GLOBAL_EKAIROS_CONFIG] = config;
8
- }
9
- catch {
10
- // ignore
11
- }
12
- }
13
2
  /**
14
3
  * Creates a small "framework-style" config object that can be executed in the step runtime.
15
4
  *
@@ -18,7 +7,7 @@ function setGlobalEkairosConfig(config) {
18
7
  */
19
8
  export function createEkairosConfig(params) {
20
9
  const stories = params.stories ?? [];
21
- const config = {
10
+ return {
22
11
  stories,
23
12
  runtime: params.runtime,
24
13
  setup() {
@@ -34,8 +23,4 @@ export function createEkairosConfig(params) {
34
23
  s.register();
35
24
  },
36
25
  };
37
- // Register globally (process-level) so libraries/steps can access it transparently.
38
- // Note: This does NOT call `setup()` (no runtime side-effects).
39
- setGlobalEkairosConfig(config);
40
- return config;
41
26
  }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- export { story, createStory, type StoryConfig, type StoryInstance, type StoryOptions, type StoryStreamOptions, Story, type RegistrableStoryBuilder, } from "./story";
2
- export type { StoryStore, ContextIdentifier, StoredContext, ContextEvent, } from "./story.store";
3
- export { registerStory, getStory, getStoryFactory, hasStory, listStories, type StoryKey, } from "./story.registry";
4
- export { storyDomain } from "./schema";
5
- export { didToolExecute } from "./story.toolcalls";
6
- export { USER_MESSAGE_TYPE, ASSISTANT_MESSAGE_TYPE, SYSTEM_MESSAGE_TYPE, WEB_CHANNEL, AGENT_CHANNEL, EMAIL_CHANNEL, createUserEventFromUIMessages, createAssistantEventFromUIMessages, convertToUIMessage, convertEventToModelMessages, convertEventsToModelMessages, convertModelMessageToEvent, type ResponseMessage, } from "./events";
1
+ export { story, createStory, type StoryConfig, type StoryInstance, type StoryOptions, type StoryStreamOptions, Story, type RegistrableStoryBuilder, } from "./story.js";
2
+ export type { StoryStore, ContextIdentifier, StoredContext, ContextEvent, } from "./story.store.js";
3
+ export { registerStory, getStory, getStoryFactory, hasStory, listStories, type StoryKey, } from "./story.registry.js";
4
+ export { storyDomain } from "./schema.js";
5
+ export { didToolExecute } from "./story.toolcalls.js";
6
+ export { USER_MESSAGE_TYPE, ASSISTANT_MESSAGE_TYPE, SYSTEM_MESSAGE_TYPE, WEB_CHANNEL, AGENT_CHANNEL, EMAIL_CHANNEL, createUserEventFromUIMessages, createAssistantEventFromUIMessages, convertToUIMessage, convertEventToModelMessages, convertEventsToModelMessages, convertModelMessageToEvent, type ResponseMessage, } from "./events.js";
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  export {
2
2
  // Story API
3
- story, createStory, Story, } from "./story";
4
- export { registerStory, getStory, getStoryFactory, hasStory, listStories, } from "./story.registry";
5
- export { storyDomain } from "./schema";
6
- export { didToolExecute } from "./story.toolcalls";
7
- export { USER_MESSAGE_TYPE, ASSISTANT_MESSAGE_TYPE, SYSTEM_MESSAGE_TYPE, WEB_CHANNEL, AGENT_CHANNEL, EMAIL_CHANNEL, createUserEventFromUIMessages, createAssistantEventFromUIMessages, convertToUIMessage, convertEventToModelMessages, convertEventsToModelMessages, convertModelMessageToEvent, } from "./events";
3
+ story, createStory, Story, } from "./story.js";
4
+ export { registerStory, getStory, getStoryFactory, hasStory, listStories, } from "./story.registry.js";
5
+ export { storyDomain } from "./schema.js";
6
+ export { didToolExecute } from "./story.toolcalls.js";
7
+ export { USER_MESSAGE_TYPE, ASSISTANT_MESSAGE_TYPE, SYSTEM_MESSAGE_TYPE, WEB_CHANNEL, AGENT_CHANNEL, EMAIL_CHANNEL, createUserEventFromUIMessages, createAssistantEventFromUIMessages, convertToUIMessage, convertEventToModelMessages, convertEventsToModelMessages, convertModelMessageToEvent, } from "./events.js";
package/dist/next.d.ts CHANGED
@@ -11,6 +11,7 @@ type WithEkairosRuntimeOptions = {
11
11
  */
12
12
  bootstrapModule: string;
13
13
  };
14
+ type NextConfigFnLike = (phase: string, ctx: any) => Promise<any> | any;
14
15
  /**
15
16
  * Next.js helper to ensure the story runtime factory is registered in *every* server bundle.
16
17
  *
@@ -19,5 +20,5 @@ type WithEkairosRuntimeOptions = {
19
20
  * - No "magic" root bootstrap file
20
21
  * - Works for step runtimes because the server entry will always evaluate your bootstrap module
21
22
  */
22
- export declare function withEkairosRuntime(nextConfig: NextConfigLike, opts: WithEkairosRuntimeOptions): NextConfigLike;
23
+ export declare function withEkairosRuntime(nextConfigOrFn: NextConfigLike | NextConfigFnLike, opts: WithEkairosRuntimeOptions): any;
23
24
  export {};
package/dist/next.js CHANGED
@@ -72,34 +72,47 @@ function injectBootstrapIntoEntries(entries, bootstrap) {
72
72
  * - No "magic" root bootstrap file
73
73
  * - Works for step runtimes because the server entry will always evaluate your bootstrap module
74
74
  */
75
- export function withEkairosRuntime(nextConfig, opts) {
75
+ export function withEkairosRuntime(nextConfigOrFn, opts) {
76
76
  const bootstrapModule = opts.bootstrapModule;
77
- const userWebpack = nextConfig.webpack ?? undefined;
78
- return {
79
- ...nextConfig,
80
- webpack: (config, options) => {
81
- const out = userWebpack ? userWebpack(config, options) : config;
82
- // Patch the generated workflow step route (esbuild output) so it imports
83
- // the app's `ekairos.ts`, which registers `ekairosConfig` globally.
84
- //
85
- // This is necessary because the steps bundle is produced by @workflow/builders
86
- // (esbuild) and does NOT run through Next's webpack entrypoints.
87
- patchWorkflowStepRouteToImportBootstrap(bootstrapModule);
88
- if (!options?.isServer)
77
+ const apply = (nextConfig) => {
78
+ const userWebpack = nextConfig.webpack ?? undefined;
79
+ return {
80
+ ...nextConfig,
81
+ webpack: (config, options) => {
82
+ const out = userWebpack ? userWebpack(config, options) : config;
83
+ // NOTE:
84
+ // - We still attempt the patch here for webpack builds.
85
+ // - But for Turbopack builds, this hook may never run, so we ALSO patch
86
+ // in the config-function wrapper below (after withWorkflow generates the file).
87
+ patchWorkflowStepRouteToImportBootstrap(bootstrapModule);
88
+ if (!options?.isServer)
89
+ return out;
90
+ const req = createRequire(import.meta.url);
91
+ const contextDir = (out && out.context) || process.cwd();
92
+ // Resolve relative to the app project (webpack context), not to this package.
93
+ const resolvedBootstrap = req.resolve(bootstrapModule, {
94
+ paths: [contextDir],
95
+ });
96
+ const originalEntry = out.entry;
97
+ out.entry = async () => {
98
+ const entries = typeof originalEntry === "function" ? await originalEntry() : originalEntry;
99
+ injectBootstrapIntoEntries(entries, resolvedBootstrap);
100
+ return entries;
101
+ };
89
102
  return out;
90
- const req = createRequire(import.meta.url);
91
- const contextDir = (out && out.context) || process.cwd();
92
- // Resolve relative to the app project (webpack context), not to this package.
93
- const resolvedBootstrap = req.resolve(bootstrapModule, {
94
- paths: [contextDir],
95
- });
96
- const originalEntry = out.entry;
97
- out.entry = async () => {
98
- const entries = typeof originalEntry === "function" ? await originalEntry() : originalEntry;
99
- injectBootstrapIntoEntries(entries, resolvedBootstrap);
100
- return entries;
101
- };
102
- return out;
103
- },
103
+ },
104
+ };
104
105
  };
106
+ // Critical path for Vercel/Turbopack:
107
+ // `@workflow/next` generates `src/app/.well-known/workflow/v1/step/route.js` inside its config function.
108
+ // So we must patch AFTER that function runs (not inside webpack).
109
+ if (typeof nextConfigOrFn === "function") {
110
+ return async (phase, ctx) => {
111
+ const cfg = await nextConfigOrFn(phase, ctx);
112
+ patchWorkflowStepRouteToImportBootstrap(bootstrapModule);
113
+ return apply(cfg);
114
+ };
115
+ }
116
+ // Object config: best-effort patch (file may not exist yet here)
117
+ return apply(nextConfigOrFn);
105
118
  }
package/dist/runtime.d.ts CHANGED
@@ -8,6 +8,5 @@
8
8
  * - Do NOT import this entrypoint from client/browser code.
9
9
  * - Keep `@ekairos/story` main entrypoint safe to import from schema/domain modules.
10
10
  */
11
- export { configureStoryRuntime, configureStoryRuntimeBootstrap, getEkairosConfig, isStoryRuntimeConfigured, resolveStoryRuntime, type StoryEnvironment, type StoryRuntime, type StoryRuntimeResolver, } from "./story.config";
11
+ export { configureStoryRuntime, configureStoryRuntimeBootstrap, isStoryRuntimeConfigured, resolveStoryRuntime, type StoryEnvironment, type StoryRuntime, type StoryRuntimeResolver, } from "./story.config";
12
12
  export { createEkairosConfig, type EkairosConfig, type RegistrableStory, } from "./ekairos.config";
13
- export { withEkairosRuntime } from "./next";
package/dist/runtime.js CHANGED
@@ -8,6 +8,5 @@
8
8
  * - Do NOT import this entrypoint from client/browser code.
9
9
  * - Keep `@ekairos/story` main entrypoint safe to import from schema/domain modules.
10
10
  */
11
- export { configureStoryRuntime, configureStoryRuntimeBootstrap, getEkairosConfig, isStoryRuntimeConfigured, resolveStoryRuntime, } from "./story.config";
11
+ export { configureStoryRuntime, configureStoryRuntimeBootstrap, isStoryRuntimeConfigured, resolveStoryRuntime, } from "./story.config";
12
12
  export { createEkairosConfig, } from "./ekairos.config";
13
- export { withEkairosRuntime } from "./next";
@@ -0,0 +1,25 @@
1
+ import { type ModelMessage } from "ai";
2
+ import type { StoryEnvironment } from "../story.config";
3
+ import type { ContextEvent, ContextIdentifier } from "../story.store";
4
+ import type { SerializableToolForModel } from "../tools-to-model-tools";
5
+ /**
6
+ * Executes a full "reaction" inside a single workflow step:
7
+ * - load events from store
8
+ * - convert events to model messages
9
+ * - run the streaming model call and emit chunks
10
+ * - extract tool calls from the resulting assistant event
11
+ */
12
+ export declare function executeReaction(params: {
13
+ env: StoryEnvironment;
14
+ contextIdentifier: ContextIdentifier;
15
+ model: any;
16
+ system: string;
17
+ tools: Record<string, SerializableToolForModel>;
18
+ eventId: string;
19
+ maxSteps: number;
20
+ sendStart?: boolean;
21
+ }): Promise<{
22
+ assistantEvent: ContextEvent;
23
+ toolCalls: any[];
24
+ messagesForModel: ModelMessage[];
25
+ }>;
@@ -0,0 +1,135 @@
1
+ import { jsonSchema, gateway, smoothStream, stepCountIs, streamText, } from "ai";
2
+ import { getWritable } from "workflow";
3
+ import { resolveStoryRuntime } from "../story.config";
4
+ import { extractToolCallsFromParts } from "../story.toolcalls";
5
+ function safeErrorJson(error) {
6
+ const seen = new WeakSet();
7
+ const redactKey = (k) => /token|authorization|cookie|secret|api[_-]?key|password/i.test(k);
8
+ const err = error;
9
+ const payload = {
10
+ name: err?.name,
11
+ message: err?.message,
12
+ status: err?.status,
13
+ body: err?.body,
14
+ data: err?.data,
15
+ stack: err?.stack,
16
+ };
17
+ try {
18
+ return JSON.stringify(payload, (k, v) => {
19
+ if (redactKey(k))
20
+ return "[redacted]";
21
+ if (typeof v === "string" && v.length > 5000)
22
+ return "[truncated-string]";
23
+ if (typeof v === "object" && v !== null) {
24
+ if (seen.has(v))
25
+ return "[circular]";
26
+ seen.add(v);
27
+ }
28
+ return v;
29
+ });
30
+ }
31
+ catch {
32
+ return JSON.stringify({ message: String(err?.message ?? "error") });
33
+ }
34
+ }
35
+ /**
36
+ * Executes a full "reaction" inside a single workflow step:
37
+ * - load events from store
38
+ * - convert events to model messages
39
+ * - run the streaming model call and emit chunks
40
+ * - extract tool calls from the resulting assistant event
41
+ */
42
+ export async function executeReaction(params) {
43
+ "use step";
44
+ const { store } = await resolveStoryRuntime(params.env);
45
+ console.log("executeReaction: begin");
46
+ let events;
47
+ try {
48
+ console.log("executeReaction: store.getEvents begin");
49
+ events = await store.getEvents(params.contextIdentifier);
50
+ console.log("executeReaction: store.getEvents ok");
51
+ }
52
+ catch (error) {
53
+ console.error("executeReaction: store.getEvents failed");
54
+ throw error;
55
+ }
56
+ let messagesForModel;
57
+ try {
58
+ console.log("executeReaction: store.eventsToModelMessages begin");
59
+ messagesForModel = (await store.eventsToModelMessages(events));
60
+ console.log("executeReaction: store.eventsToModelMessages ok");
61
+ }
62
+ catch (error) {
63
+ console.error("executeReaction: store.eventsToModelMessages failed", safeErrorJson(error));
64
+ throw error;
65
+ }
66
+ const writable = getWritable();
67
+ // Match DurableAgent-style model init behavior:
68
+ const resolvedModel = typeof params.model === "string"
69
+ ? gateway(params.model)
70
+ : typeof params.model === "function"
71
+ ? await params.model()
72
+ : params.model;
73
+ // Wrap plain JSON Schema objects so the AI SDK doesn't attempt Zod conversion at runtime.
74
+ const toolsForStreamText = {};
75
+ for (const [name, t] of Object.entries(params.tools)) {
76
+ toolsForStreamText[name] = {
77
+ description: t?.description,
78
+ inputSchema: jsonSchema(t.inputSchema),
79
+ };
80
+ }
81
+ console.log("executeReaction: streamText begin");
82
+ const result = streamText({
83
+ model: resolvedModel,
84
+ system: params.system,
85
+ messages: messagesForModel,
86
+ tools: toolsForStreamText,
87
+ toolChoice: "required",
88
+ stopWhen: stepCountIs(params.maxSteps),
89
+ experimental_transform: smoothStream({ delayInMs: 30, chunking: "word" }),
90
+ });
91
+ console.log("executeReaction: streamText ok");
92
+ // Ensure the underlying stream is consumed (AI SDK requirement)
93
+ result.consumeStream();
94
+ let resolveFinish;
95
+ let rejectFinish;
96
+ const finishPromise = new Promise((resolve, reject) => {
97
+ resolveFinish = resolve;
98
+ rejectFinish = reject;
99
+ });
100
+ const uiStream = result
101
+ .toUIMessageStream({
102
+ sendStart: Boolean(params.sendStart),
103
+ generateMessageId: () => params.eventId,
104
+ messageMetadata() {
105
+ return { eventId: params.eventId };
106
+ },
107
+ onFinish: ({ messages }) => {
108
+ const lastMessage = messages[messages.length - 1];
109
+ const event = {
110
+ id: params.eventId,
111
+ type: "assistant.message",
112
+ channel: "web",
113
+ createdAt: new Date().toISOString(),
114
+ content: { parts: lastMessage?.parts ?? [] },
115
+ };
116
+ resolveFinish(event);
117
+ },
118
+ onError: (e) => {
119
+ rejectFinish(e);
120
+ return e instanceof Error ? e.message : String(e);
121
+ },
122
+ })
123
+ // Filter out per-step finish boundary. Workflow will emit a single finish.
124
+ .pipeThrough(new TransformStream({
125
+ transform(chunk, controller) {
126
+ if (chunk.type === "finish")
127
+ return;
128
+ controller.enqueue(chunk);
129
+ },
130
+ }));
131
+ await uiStream.pipeTo(writable, { preventClose: true });
132
+ const assistantEvent = await finishPromise;
133
+ const toolCalls = extractToolCallsFromParts(assistantEvent?.content?.parts);
134
+ return { assistantEvent, toolCalls, messagesForModel };
135
+ }
@@ -1,43 +1,28 @@
1
- import type { ModelMessage } from "ai";
2
1
  import { type StoryEnvironment } from "../story.config";
3
2
  import type { ContextEvent, ContextIdentifier, StoredContext } from "../story.store";
4
- export declare function generateId(): Promise<string>;
5
- export declare function getOrCreateContext<C>(env: StoryEnvironment, contextIdentifier: ContextIdentifier | null): Promise<{
6
- context: StoredContext<C>;
7
- isNew: boolean;
8
- }>;
9
3
  /**
10
- * Ensures a context exists and emits a single `data-context-id` chunk to the workflow stream.
4
+ * Initializes/ensures the story context exists and emits a single `data-context-id` chunk.
11
5
  *
12
- * Why this exists:
13
- * - `getOrCreateContext(...)` and `writeContextIdChunk(...)` are semantically coupled.
14
- * - Keeping them in a single step reduces step invocations per run (cheaper) without changing behavior.
6
+ * This is the "context init" boundary for the story engine.
15
7
  */
16
- export declare function ensureContextAndEmitContextId<C>(env: StoryEnvironment, contextIdentifier: ContextIdentifier | null): Promise<{
8
+ export declare function initializeContext<C>(env: StoryEnvironment, contextIdentifier: ContextIdentifier | null): Promise<{
17
9
  context: StoredContext<C>;
18
10
  isNew: boolean;
19
11
  }>;
20
- export declare function getContext<C>(env: StoryEnvironment, contextIdentifier: ContextIdentifier): Promise<StoredContext<C> | null>;
21
- /**
22
- * Loads the state needed for a single Story loop iteration.
23
- *
24
- * This is a "read aggregation" step: it groups read-only store calls into a single workflow step
25
- * invocation to reduce step overhead (cheaper) without changing behavior.
26
- */
27
- export declare function loadTurnState<C>(params: {
28
- env: StoryEnvironment;
29
- contextIdentifier: ContextIdentifier;
30
- }): Promise<{
31
- context: StoredContext<C> | null;
32
- events: ContextEvent[];
33
- }>;
34
12
  export declare function updateContextContent<C>(env: StoryEnvironment, contextIdentifier: ContextIdentifier, content: C): Promise<StoredContext<C>>;
35
13
  export declare function updateContextStatus(env: StoryEnvironment, contextIdentifier: ContextIdentifier, status: "open" | "streaming" | "closed"): Promise<void>;
36
- export declare function saveEvent(env: StoryEnvironment, contextIdentifier: ContextIdentifier, event: ContextEvent): Promise<ContextEvent>;
14
+ export declare function saveTriggerEvent(env: StoryEnvironment, contextIdentifier: ContextIdentifier, event: ContextEvent): Promise<ContextEvent>;
15
+ export declare function saveReactionEvent(env: StoryEnvironment, contextIdentifier: ContextIdentifier, event: ContextEvent): Promise<ContextEvent>;
37
16
  export declare function updateEvent(env: StoryEnvironment, eventId: string, event: ContextEvent): Promise<ContextEvent>;
38
- export declare function getEvents(env: StoryEnvironment, contextIdentifier: ContextIdentifier): Promise<ContextEvent[]>;
39
17
  export declare function createExecution(env: StoryEnvironment, contextIdentifier: ContextIdentifier, triggerEventId: string, reactionEventId: string): Promise<{
40
18
  id: string;
41
19
  }>;
20
+ export declare function createReactionEvent(params: {
21
+ env: StoryEnvironment;
22
+ contextIdentifier: ContextIdentifier;
23
+ triggerEventId: string;
24
+ }): Promise<{
25
+ reactionEventId: string;
26
+ executionId: string;
27
+ }>;
42
28
  export declare function completeExecution(env: StoryEnvironment, contextIdentifier: ContextIdentifier, executionId: string, status: "completed" | "failed"): Promise<void>;
43
- export declare function eventsToModelMessages(env: StoryEnvironment, events: ContextEvent[]): Promise<ModelMessage[]>;
@@ -1,36 +1,11 @@
1
1
  import { getWritable } from "workflow";
2
2
  import { resolveStoryRuntime } from "../story.config";
3
- export async function generateId() {
4
- "use step";
5
- // Use crypto.randomUUID when available (Node 18+)
6
- const uuid = globalThis.crypto?.randomUUID?.();
7
- if (uuid)
8
- return uuid;
9
- // Fallback
10
- return `${Date.now()}-${Math.random().toString(16).slice(2)}`;
11
- }
12
- export async function getOrCreateContext(env, contextIdentifier) {
13
- "use step";
14
- const { store } = await resolveStoryRuntime(env);
15
- // Detect creation explicitly so the engine can run onContextCreated hooks.
16
- if (!contextIdentifier) {
17
- const context = await store.getOrCreateContext(null);
18
- return { context, isNew: true };
19
- }
20
- const existing = await store.getContext(contextIdentifier);
21
- if (existing)
22
- return { context: existing, isNew: false };
23
- const created = await store.getOrCreateContext(contextIdentifier);
24
- return { context: created, isNew: true };
25
- }
26
3
  /**
27
- * Ensures a context exists and emits a single `data-context-id` chunk to the workflow stream.
4
+ * Initializes/ensures the story context exists and emits a single `data-context-id` chunk.
28
5
  *
29
- * Why this exists:
30
- * - `getOrCreateContext(...)` and `writeContextIdChunk(...)` are semantically coupled.
31
- * - Keeping them in a single step reduces step invocations per run (cheaper) without changing behavior.
6
+ * This is the "context init" boundary for the story engine.
32
7
  */
33
- export async function ensureContextAndEmitContextId(env, contextIdentifier) {
8
+ export async function initializeContext(env, contextIdentifier) {
34
9
  "use step";
35
10
  const { store } = await resolveStoryRuntime(env);
36
11
  // Detect creation explicitly so the engine can run onContextCreated hooks.
@@ -63,24 +38,6 @@ export async function ensureContextAndEmitContextId(env, contextIdentifier) {
63
38
  }
64
39
  return result;
65
40
  }
66
- export async function getContext(env, contextIdentifier) {
67
- "use step";
68
- const { store } = await resolveStoryRuntime(env);
69
- return await store.getContext(contextIdentifier);
70
- }
71
- /**
72
- * Loads the state needed for a single Story loop iteration.
73
- *
74
- * This is a "read aggregation" step: it groups read-only store calls into a single workflow step
75
- * invocation to reduce step overhead (cheaper) without changing behavior.
76
- */
77
- export async function loadTurnState(params) {
78
- "use step";
79
- const { store } = await resolveStoryRuntime(params.env);
80
- const context = await store.getContext(params.contextIdentifier);
81
- const events = await store.getEvents(params.contextIdentifier);
82
- return { context, events };
83
- }
84
41
  export async function updateContextContent(env, contextIdentifier, content) {
85
42
  "use step";
86
43
  const { store } = await resolveStoryRuntime(env);
@@ -91,33 +48,40 @@ export async function updateContextStatus(env, contextIdentifier, status) {
91
48
  const { store } = await resolveStoryRuntime(env);
92
49
  await store.updateContextStatus(contextIdentifier, status);
93
50
  }
94
- export async function saveEvent(env, contextIdentifier, event) {
51
+ export async function saveTriggerEvent(env, contextIdentifier, event) {
95
52
  "use step";
96
53
  const { store } = await resolveStoryRuntime(env);
97
54
  return await store.saveEvent(contextIdentifier, event);
98
55
  }
99
- export async function updateEvent(env, eventId, event) {
56
+ export async function saveReactionEvent(env, contextIdentifier, event) {
100
57
  "use step";
101
58
  const { store } = await resolveStoryRuntime(env);
102
- return await store.updateEvent(eventId, event);
59
+ return await store.saveEvent(contextIdentifier, event);
103
60
  }
104
- export async function getEvents(env, contextIdentifier) {
61
+ export async function updateEvent(env, eventId, event) {
105
62
  "use step";
106
63
  const { store } = await resolveStoryRuntime(env);
107
- return await store.getEvents(contextIdentifier);
64
+ return await store.updateEvent(eventId, event);
108
65
  }
109
66
  export async function createExecution(env, contextIdentifier, triggerEventId, reactionEventId) {
110
67
  "use step";
111
68
  const { store } = await resolveStoryRuntime(env);
112
69
  return await store.createExecution(contextIdentifier, triggerEventId, reactionEventId);
113
70
  }
114
- export async function completeExecution(env, contextIdentifier, executionId, status) {
71
+ export async function createReactionEvent(params) {
115
72
  "use step";
116
- const { store } = await resolveStoryRuntime(env);
117
- await store.completeExecution(contextIdentifier, executionId, status);
73
+ const { store } = await resolveStoryRuntime(params.env);
74
+ // Generate a new reaction event id inside the step boundary.
75
+ const uuid = globalThis.crypto?.randomUUID?.();
76
+ const reactionEventId = typeof uuid === "string"
77
+ ? uuid
78
+ : `${Date.now()}-${Math.random().toString(16).slice(2)}`;
79
+ await store.updateContextStatus(params.contextIdentifier, "streaming");
80
+ const execution = await store.createExecution(params.contextIdentifier, params.triggerEventId, reactionEventId);
81
+ return { reactionEventId, executionId: execution.id };
118
82
  }
119
- export async function eventsToModelMessages(env, events) {
83
+ export async function completeExecution(env, contextIdentifier, executionId, status) {
120
84
  "use step";
121
85
  const { store } = await resolveStoryRuntime(env);
122
- return await store.eventsToModelMessages(events);
86
+ await store.completeExecution(contextIdentifier, executionId, status);
123
87
  }
@@ -11,6 +11,13 @@ export declare function writeContextSubstate(params: {
11
11
  export declare function writeContextIdChunk(params: {
12
12
  contextId: string;
13
13
  }): Promise<void>;
14
+ export declare function writeStoryPing(params: {
15
+ /**
16
+ * Simple ping event to validate that the workflow stream is alive.
17
+ * This is intentionally generic so clients can ignore it safely.
18
+ */
19
+ label?: string;
20
+ }): Promise<void>;
14
21
  export declare function writeToolOutputs(params: {
15
22
  results: Array<{
16
23
  toolCallId: string;
@@ -29,6 +29,21 @@ export async function writeContextIdChunk(params) {
29
29
  writer.releaseLock();
30
30
  }
31
31
  }
32
+ export async function writeStoryPing(params) {
33
+ "use step";
34
+ const writable = getWritable();
35
+ const writer = writable.getWriter();
36
+ try {
37
+ await writer.write({
38
+ type: "data-story-ping",
39
+ data: { label: params.label ?? "story-ping" },
40
+ transient: true,
41
+ });
42
+ }
43
+ finally {
44
+ writer.releaseLock();
45
+ }
46
+ }
32
47
  export async function writeToolOutputs(params) {
33
48
  "use step";
34
49
  const writable = getWritable();
@@ -2,4 +2,4 @@
2
2
  * Parses a document with LlamaParse and stores it in InstantDB (document_documents + link to file).
3
3
  * Returns the created documentId.
4
4
  */
5
- export declare function parseAndStoreDocument(db: any, buffer: Buffer, fileName: string, path: string, fileId: string): Promise<string>;
5
+ export declare function parseAndStoreDocument(db: any, buffer: Buffer, fileName: string, fileId: string): Promise<string>;