@ekairos/story 1.21.57-beta.0 → 1.21.58-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.
@@ -7,6 +7,8 @@ export async function initializeContext(env, contextIdentifier, opts) {
7
7
  "use step";
8
8
  const { resolveStoryRuntime } = await import("@ekairos/story/runtime");
9
9
  const { store } = await resolveStoryRuntime(env);
10
+ console.log("[ekairos/story] story.engine react begin");
11
+ console.log("[ekairos/story] story.engine react contextIdentifier", contextIdentifier);
10
12
  // Detect creation explicitly so the engine can run onContextCreated hooks.
11
13
  let result;
12
14
  if (!contextIdentifier) {
@@ -23,6 +25,9 @@ export async function initializeContext(env, contextIdentifier, opts) {
23
25
  result = { context: created, isNew: true };
24
26
  }
25
27
  }
28
+ console.log("[ekairos/story] story.engine initializeContext ok");
29
+ console.log("[ekairos/story] story.engine initializeContext contextId", result.context.id);
30
+ console.log("[ekairos/story] story.engine initializeContext isNew", result.isNew);
26
31
  // If we're running in a non-streaming context (e.g. tests or headless usage),
27
32
  // we skip writing stream chunks entirely.
28
33
  if (!opts?.silent) {
@@ -58,7 +63,10 @@ export async function saveTriggerEvent(env, contextIdentifier, event) {
58
63
  "use step";
59
64
  const { resolveStoryRuntime } = await import("@ekairos/story/runtime");
60
65
  const { store } = await resolveStoryRuntime(env);
61
- return await store.saveEvent(contextIdentifier, event);
66
+ const saved = await store.saveEvent(contextIdentifier, event);
67
+ console.log("[ekairos/story] story.engine saveTriggerEvent ok");
68
+ console.log("[ekairos/story] story.engine saveTriggerEvent triggerEventId", saved.id);
69
+ return saved;
62
70
  }
63
71
  export async function saveReactionEvent(env, contextIdentifier, event) {
64
72
  "use step";
@@ -89,6 +97,9 @@ export async function createReactionEvent(params) {
89
97
  : `${Date.now()}-${Math.random().toString(16).slice(2)}`;
90
98
  await store.updateContextStatus(params.contextIdentifier, "streaming");
91
99
  const execution = await store.createExecution(params.contextIdentifier, params.triggerEventId, reactionEventId);
100
+ console.log("[ekairos/story] story.engine createReactionEvent ok");
101
+ console.log("[ekairos/story] story.engine createReactionEvent reactionEventId", reactionEventId);
102
+ console.log("[ekairos/story] story.engine createReactionEvent executionId", execution.id);
92
103
  return { reactionEventId, executionId: execution.id };
93
104
  }
94
105
  export async function completeExecution(env, contextIdentifier, executionId, status) {
@@ -1,8 +1,3 @@
1
- export declare function writeStoryLog(params: {
2
- level?: "info" | "debug" | "warn" | "error";
3
- message: string;
4
- args?: Array<string | number | boolean | null>;
5
- }): Promise<void>;
6
1
  export declare function writeContextSubstate(params: {
7
2
  /**
8
3
  * Ephemeral substate key for the UI (story engine internal state).
@@ -1,15 +1,3 @@
1
- export async function writeStoryLog(params) {
2
- "use step";
3
- const level = params.level ?? "info";
4
- const fn = level === "debug"
5
- ? console.debug
6
- : level === "warn"
7
- ? console.warn
8
- : level === "error"
9
- ? console.error
10
- : console.log;
11
- fn(params.message, ...(params.args ?? []));
12
- }
13
1
  export async function writeContextSubstate(params) {
14
2
  "use step";
15
3
  const { getWritable } = await import("workflow");
@@ -1,50 +1,8 @@
1
1
  import { applyToolExecutionResultToParts } from "./story.toolcalls.js";
2
2
  import { executeReaction } from "./steps/reaction.steps.js";
3
3
  import { toolsToModelTools } from "./tools-to-model-tools.js";
4
- import { closeStoryStream, writeContextSubstate, writeStoryLog, writeStoryPing, writeToolOutputs, } from "./steps/stream.steps.js";
4
+ import { closeStoryStream, writeContextSubstate, writeStoryPing, writeToolOutputs } from "./steps/stream.steps.js";
5
5
  import { completeExecution, createReactionEvent, initializeContext, saveReactionEvent, saveTriggerEvent, updateContextContent, updateContextStatus, updateEvent, } from "./steps/store.steps.js";
6
- function safeLogArg(value) {
7
- if (value === null)
8
- return null;
9
- if (value === undefined)
10
- return null;
11
- const t = typeof value;
12
- if (t === "string" || t === "number" || t === "boolean")
13
- return value;
14
- if (t === "bigint")
15
- return String(value);
16
- try {
17
- const seen = new WeakSet();
18
- return JSON.stringify(value, (_k, v) => {
19
- if (typeof v === "bigint")
20
- return String(v);
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
- }, 2);
30
- }
31
- catch {
32
- try {
33
- return String(value);
34
- }
35
- catch {
36
- return "[unserializable]";
37
- }
38
- }
39
- }
40
- async function storyEngineInfo(message, ...args) {
41
- // CRITICAL: static string log messages only. Dynamic values go in args.
42
- await writeStoryLog({ level: "info", message, args: args.map(safeLogArg) });
43
- }
44
- async function storyEngineDebug(message, ...args) {
45
- // CRITICAL: static string log messages only. Dynamic values go in args.
46
- await writeStoryLog({ level: "debug", message, args: args.map(safeLogArg) });
47
- }
48
6
  export class Story {
49
7
  constructor(opts = {}) {
50
8
  this.opts = opts;
@@ -101,17 +59,9 @@ export class Story {
101
59
  const preventClose = params.options?.preventClose ?? false;
102
60
  const sendFinish = params.options?.sendFinish ?? true;
103
61
  const silent = params.options?.silent ?? false;
104
- await storyEngineInfo("[ekairos/story] story.engine react begin");
105
- await storyEngineInfo("[ekairos/story] story.engine react contextIdentifier", params.contextIdentifier);
106
- await storyEngineInfo("[ekairos/story] story.engine react maxIterations", maxIterations);
107
- await storyEngineInfo("[ekairos/story] story.engine react maxModelSteps", maxModelSteps);
108
- await storyEngineInfo("[ekairos/story] story.engine react silent", silent);
109
62
  // 1) Ensure context exists (step)
110
63
  const ctxResult = await initializeContext(params.env, params.contextIdentifier, { silent });
111
64
  const currentContext = ctxResult.context;
112
- await storyEngineInfo("[ekairos/story] story.engine initializeContext ok");
113
- await storyEngineInfo("[ekairos/story] story.engine initializeContext contextId", currentContext.id);
114
- await storyEngineInfo("[ekairos/story] story.engine initializeContext isNew", ctxResult.isNew);
115
65
  const contextSelector = params.contextIdentifier?.id
116
66
  ? { id: String(params.contextIdentifier.id) }
117
67
  : params.contextIdentifier?.key
@@ -123,16 +73,11 @@ export class Story {
123
73
  // 2) Persist trigger event + create execution shell (steps)
124
74
  const persistedTriggerEvent = await saveTriggerEvent(params.env, contextSelector, triggerEvent);
125
75
  const triggerEventId = persistedTriggerEvent.id;
126
- await storyEngineInfo("[ekairos/story] story.engine saveTriggerEvent ok");
127
- await storyEngineInfo("[ekairos/story] story.engine saveTriggerEvent triggerEventId", triggerEventId);
128
76
  const { reactionEventId, executionId } = await createReactionEvent({
129
77
  env: params.env,
130
78
  contextIdentifier: contextSelector,
131
79
  triggerEventId,
132
80
  });
133
- await storyEngineInfo("[ekairos/story] story.engine createReactionEvent ok");
134
- await storyEngineInfo("[ekairos/story] story.engine createReactionEvent reactionEventId", reactionEventId);
135
- await storyEngineInfo("[ekairos/story] story.engine createReactionEvent executionId", executionId);
136
81
  // Emit a simple ping chunk early so clients can validate that streaming works end-to-end.
137
82
  // This should be ignored safely by clients that don't care about it.
138
83
  if (!silent) {
@@ -159,22 +104,14 @@ export class Story {
159
104
  };
160
105
  try {
161
106
  for (let iter = 0; iter < maxIterations; iter++) {
162
- await storyEngineInfo("[ekairos/story] story.engine === LOOP ITERATION ===", iter);
163
107
  // Hook: Story DSL `context()` (implemented by subclasses via `initialize()`)
164
- await storyEngineInfo("[ekairos/story] >>> HOOK context() BEGIN", iter);
165
108
  const nextContent = await this.initialize(updatedContext, params.env);
166
- await storyEngineInfo("[ekairos/story] <<< HOOK context() END", iter);
167
109
  updatedContext = await updateContextContent(params.env, contextSelector, nextContent);
168
- await storyEngineInfo("[ekairos/story] story.engine updateContextContent ok");
169
110
  await this.opts.onContextUpdated?.({ env: params.env, context: updatedContext });
170
111
  // Hook: Story DSL `narrative()` (implemented by subclasses via `buildSystemPrompt()`)
171
- await storyEngineInfo("[ekairos/story] >>> HOOK narrative() BEGIN", iter);
172
112
  const systemPrompt = await this.buildSystemPrompt(updatedContext, params.env);
173
- await storyEngineInfo("[ekairos/story] <<< HOOK narrative() END", iter);
174
113
  // Hook: Story DSL `actions()` (implemented by subclasses via `buildTools()`)
175
- await storyEngineInfo("[ekairos/story] >>> HOOK actions() BEGIN", iter);
176
114
  const toolsAll = await this.buildTools(updatedContext, params.env);
177
- await storyEngineInfo("[ekairos/story] <<< HOOK actions() END", iter);
178
115
  // IMPORTANT: step args must be serializable.
179
116
  // Match DurableAgent behavior: convert tool input schemas to plain JSON Schema in workflow context.
180
117
  const toolsForModel = toolsToModelTools(toolsAll);
@@ -190,19 +127,12 @@ export class Story {
190
127
  sendStart: !silent && iter === 0 && reactionEvent === null,
191
128
  silent,
192
129
  });
193
- await storyEngineInfo("[ekairos/story] story.engine executeReaction ok");
194
- await storyEngineInfo("[ekairos/story] story.engine executeReaction toolCallsCount", toolCalls.length);
195
- if (toolCalls.length) {
196
- await storyEngineInfo("[ekairos/story] >>> TOOL_CALLS requested", toolCalls.map((tc) => tc?.toolName).filter(Boolean));
197
- await storyEngineDebug("[ekairos/story] >>> TOOL_CALLS payload", toolCalls);
198
- }
199
130
  // Persist/append the assistant event for this iteration
200
131
  if (!reactionEvent) {
201
132
  reactionEvent = await saveReactionEvent(params.env, contextSelector, {
202
133
  ...assistantEvent,
203
134
  status: "pending",
204
135
  });
205
- await storyEngineInfo("[ekairos/story] story.engine saveReactionEvent ok");
206
136
  }
207
137
  else {
208
138
  reactionEvent = await updateEvent(params.env, reactionEvent.id, {
@@ -215,14 +145,11 @@ export class Story {
215
145
  },
216
146
  status: "pending",
217
147
  });
218
- await storyEngineInfo("[ekairos/story] story.engine updateEvent appendAssistantParts ok");
219
148
  }
220
149
  this.opts.onEventCreated?.(assistantEvent);
221
150
  // Done: no tool calls requested by the model
222
151
  if (!toolCalls.length) {
223
- await storyEngineInfo("[ekairos/story] >>> HOOK onEnd() BEGIN", iter);
224
152
  const endResult = await this.callOnEnd(assistantEvent);
225
- await storyEngineInfo("[ekairos/story] <<< HOOK onEnd() END", iter, endResult);
226
153
  if (endResult) {
227
154
  // Mark reaction event completed
228
155
  await updateEvent(params.env, reactionEventId, {
@@ -250,7 +177,6 @@ export class Story {
250
177
  const executionResults = await Promise.all(toolCalls.map(async (tc) => {
251
178
  const toolDef = toolsAll[tc.toolName];
252
179
  if (!toolDef || typeof toolDef.execute !== "function") {
253
- await storyEngineInfo("[ekairos/story] story.engine toolExecution missingTool", tc?.toolName);
254
180
  return {
255
181
  tc,
256
182
  success: false,
@@ -258,8 +184,6 @@ export class Story {
258
184
  errorText: `Tool "${tc.toolName}" not found or has no execute().`,
259
185
  };
260
186
  }
261
- await storyEngineInfo("[ekairos/story] >>> TOOL_EXEC BEGIN", tc?.toolName, tc?.toolCallId);
262
- await storyEngineDebug("[ekairos/story] >>> TOOL_EXEC input", tc?.toolName, tc?.toolCallId, tc?.args);
263
187
  try {
264
188
  const output = await toolDef.execute(tc.args, {
265
189
  toolCallId: tc.toolCallId,
@@ -269,13 +193,9 @@ export class Story {
269
193
  triggerEventId,
270
194
  contextId: currentContext.id,
271
195
  });
272
- await storyEngineInfo("[ekairos/story] <<< TOOL_EXEC OK", tc?.toolName, tc?.toolCallId);
273
- await storyEngineDebug("[ekairos/story] <<< TOOL_EXEC output", tc?.toolName, tc?.toolCallId, output);
274
196
  return { tc, success: true, output };
275
197
  }
276
198
  catch (e) {
277
- await storyEngineInfo("[ekairos/story] <<< TOOL_EXEC FAILED", tc?.toolName, tc?.toolCallId);
278
- await storyEngineDebug("[ekairos/story] <<< TOOL_EXEC error", tc?.toolName, tc?.toolCallId, e instanceof Error ? e.message : String(e));
279
199
  return {
280
200
  tc,
281
201
  success: false,
@@ -284,7 +204,6 @@ export class Story {
284
204
  };
285
205
  }
286
206
  }));
287
- await storyEngineInfo("[ekairos/story] story.engine toolExecution resultsCount", executionResults.length);
288
207
  // Emit tool outputs to the workflow stream (step)
289
208
  if (!silent) {
290
209
  await writeToolOutputs({
@@ -316,7 +235,6 @@ export class Story {
316
235
  content: { parts },
317
236
  status: "pending",
318
237
  });
319
- await storyEngineInfo("[ekairos/story] story.engine updateEvent mergeToolResults ok");
320
238
  }
321
239
  // Callback for observability/integration
322
240
  for (const r of executionResults) {
@@ -332,7 +250,6 @@ export class Story {
332
250
  // Stop/continue boundary: allow the Story to decide if the loop should continue.
333
251
  // IMPORTANT: we call this after tool results have been merged into the persisted `reactionEvent`,
334
252
  // so stories can inspect `reactionEvent.content.parts` deterministically.
335
- await storyEngineInfo("[ekairos/story] >>> HOOK shouldContinue() BEGIN", iter);
336
253
  const continueLoop = await this.shouldContinue({
337
254
  env: params.env,
338
255
  context: updatedContext,
@@ -341,7 +258,6 @@ export class Story {
341
258
  toolCalls,
342
259
  toolExecutionResults: executionResults,
343
260
  });
344
- await storyEngineInfo("[ekairos/story] <<< HOOK shouldContinue() END", iter, continueLoop);
345
261
  if (continueLoop === false) {
346
262
  await updateEvent(params.env, reactionEventId, {
347
263
  ...reactionEvent,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ekairos/story",
3
- "version": "1.21.57-beta.0",
3
+ "version": "1.21.58-beta.0",
4
4
  "description": "Pulzar Story - Workflow-based AI Stories",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -70,7 +70,7 @@
70
70
  },
71
71
  "dependencies": {
72
72
  "@ai-sdk/openai": "^2.0.52",
73
- "@ekairos/domain": "^1.21.57-beta.0",
73
+ "@ekairos/domain": "^1.21.58-beta.0",
74
74
  "@instantdb/admin": "^0.22.13",
75
75
  "@instantdb/core": "^0.22.13",
76
76
  "@vercel/sandbox": "^0.0.23",