@ekairos/story 1.21.43-beta.0 → 1.21.52-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.
- package/dist/steps/reaction.steps.d.ts +1 -0
- package/dist/steps/reaction.steps.js +12 -10
- package/dist/steps/store.steps.d.ts +3 -1
- package/dist/steps/store.steps.js +16 -12
- package/dist/stores/instant.store.js +3 -1
- package/dist/story.config.d.ts +1 -0
- package/dist/story.config.js +0 -15
- package/dist/story.engine.d.ts +8 -0
- package/dist/story.engine.js +82 -14
- package/package.json +16 -2
|
@@ -42,28 +42,30 @@ function safeErrorJson(error) {
|
|
|
42
42
|
export async function executeReaction(params) {
|
|
43
43
|
"use step";
|
|
44
44
|
const { store } = await resolveStoryRuntime(params.env);
|
|
45
|
-
console.log("executeReaction
|
|
45
|
+
console.log("[ekairos/story] reaction.step executeReaction begin");
|
|
46
46
|
let events;
|
|
47
47
|
try {
|
|
48
|
-
console.log("
|
|
48
|
+
console.log("[ekairos/story] reaction.step store.getEvents begin");
|
|
49
49
|
events = await store.getEvents(params.contextIdentifier);
|
|
50
|
-
console.log("
|
|
50
|
+
console.log("[ekairos/story] reaction.step store.getEvents ok");
|
|
51
51
|
}
|
|
52
52
|
catch (error) {
|
|
53
|
-
console.error("
|
|
53
|
+
console.error("[ekairos/story] reaction.step store.getEvents failed");
|
|
54
54
|
throw error;
|
|
55
55
|
}
|
|
56
56
|
let messagesForModel;
|
|
57
57
|
try {
|
|
58
|
-
console.log("
|
|
58
|
+
console.log("[ekairos/story] reaction.step store.eventsToModelMessages begin");
|
|
59
59
|
messagesForModel = (await store.eventsToModelMessages(events));
|
|
60
|
-
console.log("
|
|
60
|
+
console.log("[ekairos/story] reaction.step store.eventsToModelMessages ok");
|
|
61
61
|
}
|
|
62
62
|
catch (error) {
|
|
63
|
-
console.error("
|
|
63
|
+
console.error("[ekairos/story] reaction.step store.eventsToModelMessages failed", safeErrorJson(error));
|
|
64
64
|
throw error;
|
|
65
65
|
}
|
|
66
|
-
const writable =
|
|
66
|
+
const writable = params.silent
|
|
67
|
+
? new WritableStream({ write() { } })
|
|
68
|
+
: getWritable();
|
|
67
69
|
// Match DurableAgent-style model init behavior:
|
|
68
70
|
const resolvedModel = typeof params.model === "string"
|
|
69
71
|
? gateway(params.model)
|
|
@@ -78,7 +80,7 @@ export async function executeReaction(params) {
|
|
|
78
80
|
inputSchema: jsonSchema(t.inputSchema),
|
|
79
81
|
};
|
|
80
82
|
}
|
|
81
|
-
console.log("
|
|
83
|
+
console.log("[ekairos/story] reaction.step streamText begin");
|
|
82
84
|
const result = streamText({
|
|
83
85
|
model: resolvedModel,
|
|
84
86
|
system: params.system,
|
|
@@ -88,7 +90,7 @@ export async function executeReaction(params) {
|
|
|
88
90
|
stopWhen: stepCountIs(params.maxSteps),
|
|
89
91
|
experimental_transform: smoothStream({ delayInMs: 30, chunking: "word" }),
|
|
90
92
|
});
|
|
91
|
-
console.log("
|
|
93
|
+
console.log("[ekairos/story] reaction.step streamText ok");
|
|
92
94
|
// Ensure the underlying stream is consumed (AI SDK requirement)
|
|
93
95
|
result.consumeStream();
|
|
94
96
|
let resolveFinish;
|
|
@@ -5,7 +5,9 @@ import type { ContextEvent, ContextIdentifier, StoredContext } from "../story.st
|
|
|
5
5
|
*
|
|
6
6
|
* This is the "context init" boundary for the story engine.
|
|
7
7
|
*/
|
|
8
|
-
export declare function initializeContext<C>(env: StoryEnvironment, contextIdentifier: ContextIdentifier | null
|
|
8
|
+
export declare function initializeContext<C>(env: StoryEnvironment, contextIdentifier: ContextIdentifier | null, opts?: {
|
|
9
|
+
silent?: boolean;
|
|
10
|
+
}): Promise<{
|
|
9
11
|
context: StoredContext<C>;
|
|
10
12
|
isNew: boolean;
|
|
11
13
|
}>;
|
|
@@ -5,7 +5,7 @@ import { resolveStoryRuntime } from "../story.config";
|
|
|
5
5
|
*
|
|
6
6
|
* This is the "context init" boundary for the story engine.
|
|
7
7
|
*/
|
|
8
|
-
export async function initializeContext(env, contextIdentifier) {
|
|
8
|
+
export async function initializeContext(env, contextIdentifier, opts) {
|
|
9
9
|
"use step";
|
|
10
10
|
const { store } = await resolveStoryRuntime(env);
|
|
11
11
|
// Detect creation explicitly so the engine can run onContextCreated hooks.
|
|
@@ -24,17 +24,21 @@ export async function initializeContext(env, contextIdentifier) {
|
|
|
24
24
|
result = { context: created, isNew: true };
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
27
|
+
// If we're running in a non-streaming context (e.g. tests or headless usage),
|
|
28
|
+
// we skip writing stream chunks entirely.
|
|
29
|
+
if (!opts?.silent) {
|
|
30
|
+
const writable = getWritable();
|
|
31
|
+
const writer = writable.getWriter();
|
|
32
|
+
try {
|
|
33
|
+
await writer.write({
|
|
34
|
+
type: "data-context-id",
|
|
35
|
+
id: String(result.context.id),
|
|
36
|
+
data: { contextId: String(result.context.id) },
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
finally {
|
|
40
|
+
writer.releaseLock();
|
|
41
|
+
}
|
|
38
42
|
}
|
|
39
43
|
return result;
|
|
40
44
|
}
|
|
@@ -135,7 +135,9 @@ export class InstantStore {
|
|
|
135
135
|
async getEvents(contextIdentifier) {
|
|
136
136
|
const contextWhere = contextIdentifier.id
|
|
137
137
|
? { context: contextIdentifier.id }
|
|
138
|
-
:
|
|
138
|
+
: // IMPORTANT: `lookup("key", ...)` is valid in transactions, but not in query filters for links.
|
|
139
|
+
// Use nested where on the linked context's indexed `key` instead.
|
|
140
|
+
{ "context.key": contextIdentifier.key };
|
|
139
141
|
const res = await this.db.query({
|
|
140
142
|
context_events: {
|
|
141
143
|
$: {
|
package/dist/story.config.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ import type { StoryStore } from "./story.store";
|
|
|
14
14
|
export type StoryEnvironment = Record<string, unknown>;
|
|
15
15
|
export type StoryRuntime = {
|
|
16
16
|
store: StoryStore;
|
|
17
|
+
db: any;
|
|
17
18
|
};
|
|
18
19
|
export type StoryRuntimeResolver<Env extends StoryEnvironment = StoryEnvironment> = (env: Env) => Promise<StoryRuntime> | StoryRuntime;
|
|
19
20
|
/**
|
package/dist/story.config.js
CHANGED
|
@@ -48,21 +48,6 @@ export async function resolveStoryRuntime(env) {
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
-
// Convention bootstrap (Next.js / monorepo apps):
|
|
52
|
-
// If the app exposes `src/ekairos.ts` and uses the `@/` alias, loading that module will
|
|
53
|
-
// run `ekairosConfig.setup()` which configures the resolver + bootstrap hook.
|
|
54
|
-
//
|
|
55
|
-
// This is intentionally ONLY attempted when runtime is missing, and is safe as long as
|
|
56
|
-
// `story.config` is not part of client bundles (see `@ekairos/story/runtime`).
|
|
57
|
-
if (!getRuntimeResolver()) {
|
|
58
|
-
try {
|
|
59
|
-
// @ts-expect-error - optional, app-provided convention module
|
|
60
|
-
await import("@/ekairos");
|
|
61
|
-
}
|
|
62
|
-
catch {
|
|
63
|
-
// ignore: module missing / alias not configured
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
51
|
// If bootstrap succeeded, proceed.
|
|
67
52
|
const resolver = getRuntimeResolver();
|
|
68
53
|
if (resolver)
|
package/dist/story.engine.d.ts
CHANGED
|
@@ -39,6 +39,14 @@ export interface StoryStreamOptions {
|
|
|
39
39
|
* Default: true.
|
|
40
40
|
*/
|
|
41
41
|
sendFinish?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* If true, the story loop runs silently (no UI streaming output).
|
|
44
|
+
*
|
|
45
|
+
* Persistence (contexts/events/executions) still happens normally.
|
|
46
|
+
*
|
|
47
|
+
* Default: false.
|
|
48
|
+
*/
|
|
49
|
+
silent?: boolean;
|
|
42
50
|
}
|
|
43
51
|
/**
|
|
44
52
|
* Model initializer (DurableAgent-style).
|
package/dist/story.engine.js
CHANGED
|
@@ -3,6 +3,14 @@ import { executeReaction } from "./steps/reaction.steps.js";
|
|
|
3
3
|
import { toolsToModelTools } from "./tools-to-model-tools.js";
|
|
4
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 storyEngineInfo(message, ...args) {
|
|
7
|
+
// CRITICAL: static string log messages only. Dynamic values go in args.
|
|
8
|
+
console.log(message, ...args);
|
|
9
|
+
}
|
|
10
|
+
function storyEngineDebug(message, ...args) {
|
|
11
|
+
// CRITICAL: static string log messages only. Dynamic values go in args.
|
|
12
|
+
console.debug(message, ...args);
|
|
13
|
+
}
|
|
6
14
|
export class Story {
|
|
7
15
|
constructor(opts = {}) {
|
|
8
16
|
this.opts = opts;
|
|
@@ -58,9 +66,18 @@ export class Story {
|
|
|
58
66
|
const maxModelSteps = params.options?.maxModelSteps ?? 1;
|
|
59
67
|
const preventClose = params.options?.preventClose ?? false;
|
|
60
68
|
const sendFinish = params.options?.sendFinish ?? true;
|
|
69
|
+
const silent = params.options?.silent ?? false;
|
|
70
|
+
storyEngineInfo("[ekairos/story] story.engine react begin");
|
|
71
|
+
storyEngineInfo("[ekairos/story] story.engine react contextIdentifier", params.contextIdentifier);
|
|
72
|
+
storyEngineInfo("[ekairos/story] story.engine react maxIterations", maxIterations);
|
|
73
|
+
storyEngineInfo("[ekairos/story] story.engine react maxModelSteps", maxModelSteps);
|
|
74
|
+
storyEngineInfo("[ekairos/story] story.engine react silent", silent);
|
|
61
75
|
// 1) Ensure context exists (step)
|
|
62
|
-
const ctxResult = await initializeContext(params.env, params.contextIdentifier);
|
|
76
|
+
const ctxResult = await initializeContext(params.env, params.contextIdentifier, { silent });
|
|
63
77
|
const currentContext = ctxResult.context;
|
|
78
|
+
storyEngineInfo("[ekairos/story] story.engine initializeContext ok");
|
|
79
|
+
storyEngineInfo("[ekairos/story] story.engine initializeContext contextId", currentContext.id);
|
|
80
|
+
storyEngineInfo("[ekairos/story] story.engine initializeContext isNew", ctxResult.isNew);
|
|
64
81
|
const contextSelector = params.contextIdentifier?.id
|
|
65
82
|
? { id: String(params.contextIdentifier.id) }
|
|
66
83
|
: params.contextIdentifier?.key
|
|
@@ -72,14 +89,21 @@ export class Story {
|
|
|
72
89
|
// 2) Persist trigger event + create execution shell (steps)
|
|
73
90
|
const persistedTriggerEvent = await saveTriggerEvent(params.env, contextSelector, triggerEvent);
|
|
74
91
|
const triggerEventId = persistedTriggerEvent.id;
|
|
92
|
+
storyEngineInfo("[ekairos/story] story.engine saveTriggerEvent ok");
|
|
93
|
+
storyEngineInfo("[ekairos/story] story.engine saveTriggerEvent triggerEventId", triggerEventId);
|
|
75
94
|
const { reactionEventId, executionId } = await createReactionEvent({
|
|
76
95
|
env: params.env,
|
|
77
96
|
contextIdentifier: contextSelector,
|
|
78
97
|
triggerEventId,
|
|
79
98
|
});
|
|
99
|
+
storyEngineInfo("[ekairos/story] story.engine createReactionEvent ok");
|
|
100
|
+
storyEngineInfo("[ekairos/story] story.engine createReactionEvent reactionEventId", reactionEventId);
|
|
101
|
+
storyEngineInfo("[ekairos/story] story.engine createReactionEvent executionId", executionId);
|
|
80
102
|
// Emit a simple ping chunk early so clients can validate that streaming works end-to-end.
|
|
81
103
|
// This should be ignored safely by clients that don't care about it.
|
|
82
|
-
|
|
104
|
+
if (!silent) {
|
|
105
|
+
await writeStoryPing({ label: "story-start" });
|
|
106
|
+
}
|
|
83
107
|
let reactionEvent = null;
|
|
84
108
|
// Latest persisted context state for this run (we keep it in memory; store is updated via steps).
|
|
85
109
|
let updatedContext = currentContext;
|
|
@@ -91,7 +115,9 @@ export class Story {
|
|
|
91
115
|
// noop
|
|
92
116
|
}
|
|
93
117
|
try {
|
|
94
|
-
|
|
118
|
+
if (!silent) {
|
|
119
|
+
await closeStoryStream({ preventClose, sendFinish });
|
|
120
|
+
}
|
|
95
121
|
}
|
|
96
122
|
catch {
|
|
97
123
|
// noop
|
|
@@ -99,12 +125,22 @@ export class Story {
|
|
|
99
125
|
};
|
|
100
126
|
try {
|
|
101
127
|
for (let iter = 0; iter < maxIterations; iter++) {
|
|
102
|
-
|
|
128
|
+
storyEngineInfo("[ekairos/story] story.engine === LOOP ITERATION ===", iter);
|
|
129
|
+
// Hook: Story DSL `context()` (implemented by subclasses via `initialize()`)
|
|
130
|
+
storyEngineInfo("[ekairos/story] >>> HOOK context() BEGIN", iter);
|
|
103
131
|
const nextContent = await this.initialize(updatedContext, params.env);
|
|
132
|
+
storyEngineInfo("[ekairos/story] <<< HOOK context() END", iter);
|
|
104
133
|
updatedContext = await updateContextContent(params.env, contextSelector, nextContent);
|
|
134
|
+
storyEngineInfo("[ekairos/story] story.engine updateContextContent ok");
|
|
105
135
|
await this.opts.onContextUpdated?.({ env: params.env, context: updatedContext });
|
|
136
|
+
// Hook: Story DSL `narrative()` (implemented by subclasses via `buildSystemPrompt()`)
|
|
137
|
+
storyEngineInfo("[ekairos/story] >>> HOOK narrative() BEGIN", iter);
|
|
106
138
|
const systemPrompt = await this.buildSystemPrompt(updatedContext, params.env);
|
|
139
|
+
storyEngineInfo("[ekairos/story] <<< HOOK narrative() END", iter);
|
|
140
|
+
// Hook: Story DSL `actions()` (implemented by subclasses via `buildTools()`)
|
|
141
|
+
storyEngineInfo("[ekairos/story] >>> HOOK actions() BEGIN", iter);
|
|
107
142
|
const toolsAll = await this.buildTools(updatedContext, params.env);
|
|
143
|
+
storyEngineInfo("[ekairos/story] <<< HOOK actions() END", iter);
|
|
108
144
|
// IMPORTANT: step args must be serializable.
|
|
109
145
|
// Match DurableAgent behavior: convert tool input schemas to plain JSON Schema in workflow context.
|
|
110
146
|
const toolsForModel = toolsToModelTools(toolsAll);
|
|
@@ -117,14 +153,22 @@ export class Story {
|
|
|
117
153
|
eventId: reactionEventId,
|
|
118
154
|
maxSteps: maxModelSteps,
|
|
119
155
|
// Only emit a `start` chunk once per story turn.
|
|
120
|
-
sendStart: iter === 0 && reactionEvent === null,
|
|
156
|
+
sendStart: !silent && iter === 0 && reactionEvent === null,
|
|
157
|
+
silent,
|
|
121
158
|
});
|
|
159
|
+
storyEngineInfo("[ekairos/story] story.engine executeReaction ok");
|
|
160
|
+
storyEngineInfo("[ekairos/story] story.engine executeReaction toolCallsCount", toolCalls.length);
|
|
161
|
+
if (toolCalls.length) {
|
|
162
|
+
storyEngineInfo("[ekairos/story] >>> TOOL_CALLS requested", toolCalls.map((tc) => tc?.toolName).filter(Boolean));
|
|
163
|
+
storyEngineDebug("[ekairos/story] >>> TOOL_CALLS payload", toolCalls);
|
|
164
|
+
}
|
|
122
165
|
// Persist/append the assistant event for this iteration
|
|
123
166
|
if (!reactionEvent) {
|
|
124
167
|
reactionEvent = await saveReactionEvent(params.env, contextSelector, {
|
|
125
168
|
...assistantEvent,
|
|
126
169
|
status: "pending",
|
|
127
170
|
});
|
|
171
|
+
storyEngineInfo("[ekairos/story] story.engine saveReactionEvent ok");
|
|
128
172
|
}
|
|
129
173
|
else {
|
|
130
174
|
reactionEvent = await updateEvent(params.env, reactionEvent.id, {
|
|
@@ -137,11 +181,14 @@ export class Story {
|
|
|
137
181
|
},
|
|
138
182
|
status: "pending",
|
|
139
183
|
});
|
|
184
|
+
storyEngineInfo("[ekairos/story] story.engine updateEvent appendAssistantParts ok");
|
|
140
185
|
}
|
|
141
186
|
this.opts.onEventCreated?.(assistantEvent);
|
|
142
187
|
// Done: no tool calls requested by the model
|
|
143
188
|
if (!toolCalls.length) {
|
|
189
|
+
storyEngineInfo("[ekairos/story] >>> HOOK onEnd() BEGIN", iter);
|
|
144
190
|
const endResult = await this.callOnEnd(assistantEvent);
|
|
191
|
+
storyEngineInfo("[ekairos/story] <<< HOOK onEnd() END", iter, endResult);
|
|
145
192
|
if (endResult) {
|
|
146
193
|
// Mark reaction event completed
|
|
147
194
|
await updateEvent(params.env, reactionEventId, {
|
|
@@ -150,7 +197,9 @@ export class Story {
|
|
|
150
197
|
});
|
|
151
198
|
await updateContextStatus(params.env, contextSelector, "open");
|
|
152
199
|
await completeExecution(params.env, contextSelector, executionId, "completed");
|
|
153
|
-
|
|
200
|
+
if (!silent) {
|
|
201
|
+
await closeStoryStream({ preventClose, sendFinish });
|
|
202
|
+
}
|
|
154
203
|
return {
|
|
155
204
|
contextId: currentContext.id,
|
|
156
205
|
context: updatedContext,
|
|
@@ -161,12 +210,13 @@ export class Story {
|
|
|
161
210
|
}
|
|
162
211
|
}
|
|
163
212
|
// Execute tool calls (workflow context; tool implementations decide step vs workflow)
|
|
164
|
-
if (toolCalls.length) {
|
|
213
|
+
if (!silent && toolCalls.length) {
|
|
165
214
|
await writeContextSubstate({ key: "actions", transient: true });
|
|
166
215
|
}
|
|
167
216
|
const executionResults = await Promise.all(toolCalls.map(async (tc) => {
|
|
168
217
|
const toolDef = toolsAll[tc.toolName];
|
|
169
218
|
if (!toolDef || typeof toolDef.execute !== "function") {
|
|
219
|
+
storyEngineInfo("[ekairos/story] story.engine toolExecution missingTool", tc?.toolName);
|
|
170
220
|
return {
|
|
171
221
|
tc,
|
|
172
222
|
success: false,
|
|
@@ -174,6 +224,8 @@ export class Story {
|
|
|
174
224
|
errorText: `Tool "${tc.toolName}" not found or has no execute().`,
|
|
175
225
|
};
|
|
176
226
|
}
|
|
227
|
+
storyEngineInfo("[ekairos/story] >>> TOOL_EXEC BEGIN", tc?.toolName, tc?.toolCallId);
|
|
228
|
+
storyEngineDebug("[ekairos/story] >>> TOOL_EXEC input", tc?.toolName, tc?.toolCallId, tc?.args);
|
|
177
229
|
try {
|
|
178
230
|
const output = await toolDef.execute(tc.args, {
|
|
179
231
|
toolCallId: tc.toolCallId,
|
|
@@ -183,9 +235,13 @@ export class Story {
|
|
|
183
235
|
triggerEventId,
|
|
184
236
|
contextId: currentContext.id,
|
|
185
237
|
});
|
|
238
|
+
storyEngineInfo("[ekairos/story] <<< TOOL_EXEC OK", tc?.toolName, tc?.toolCallId);
|
|
239
|
+
storyEngineDebug("[ekairos/story] <<< TOOL_EXEC output", tc?.toolName, tc?.toolCallId, output);
|
|
186
240
|
return { tc, success: true, output };
|
|
187
241
|
}
|
|
188
242
|
catch (e) {
|
|
243
|
+
storyEngineInfo("[ekairos/story] <<< TOOL_EXEC FAILED", tc?.toolName, tc?.toolCallId);
|
|
244
|
+
storyEngineDebug("[ekairos/story] <<< TOOL_EXEC error", tc?.toolName, tc?.toolCallId, e instanceof Error ? e.message : String(e));
|
|
189
245
|
return {
|
|
190
246
|
tc,
|
|
191
247
|
success: false,
|
|
@@ -194,14 +250,21 @@ export class Story {
|
|
|
194
250
|
};
|
|
195
251
|
}
|
|
196
252
|
}));
|
|
253
|
+
storyEngineInfo("[ekairos/story] story.engine toolExecution resultsCount", executionResults.length);
|
|
197
254
|
// Emit tool outputs to the workflow stream (step)
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
255
|
+
if (!silent) {
|
|
256
|
+
await writeToolOutputs({
|
|
257
|
+
results: executionResults.map((r) => r.success
|
|
258
|
+
? { toolCallId: r.tc.toolCallId, success: true, output: r.output }
|
|
259
|
+
: {
|
|
260
|
+
toolCallId: r.tc.toolCallId,
|
|
261
|
+
success: false,
|
|
262
|
+
errorText: r.errorText,
|
|
263
|
+
}),
|
|
264
|
+
});
|
|
265
|
+
}
|
|
203
266
|
// Clear action status once tool execution results have been emitted.
|
|
204
|
-
if (toolCalls.length) {
|
|
267
|
+
if (!silent && toolCalls.length) {
|
|
205
268
|
await writeContextSubstate({ key: null, transient: true });
|
|
206
269
|
}
|
|
207
270
|
// Merge tool results into persisted parts (so next LLM call can see them)
|
|
@@ -219,6 +282,7 @@ export class Story {
|
|
|
219
282
|
content: { parts },
|
|
220
283
|
status: "pending",
|
|
221
284
|
});
|
|
285
|
+
storyEngineInfo("[ekairos/story] story.engine updateEvent mergeToolResults ok");
|
|
222
286
|
}
|
|
223
287
|
// Callback for observability/integration
|
|
224
288
|
for (const r of executionResults) {
|
|
@@ -234,6 +298,7 @@ export class Story {
|
|
|
234
298
|
// Stop/continue boundary: allow the Story to decide if the loop should continue.
|
|
235
299
|
// IMPORTANT: we call this after tool results have been merged into the persisted `reactionEvent`,
|
|
236
300
|
// so stories can inspect `reactionEvent.content.parts` deterministically.
|
|
301
|
+
storyEngineInfo("[ekairos/story] >>> HOOK shouldContinue() BEGIN", iter);
|
|
237
302
|
const continueLoop = await this.shouldContinue({
|
|
238
303
|
env: params.env,
|
|
239
304
|
context: updatedContext,
|
|
@@ -242,6 +307,7 @@ export class Story {
|
|
|
242
307
|
toolCalls,
|
|
243
308
|
toolExecutionResults: executionResults,
|
|
244
309
|
});
|
|
310
|
+
storyEngineInfo("[ekairos/story] <<< HOOK shouldContinue() END", iter, continueLoop);
|
|
245
311
|
if (continueLoop === false) {
|
|
246
312
|
await updateEvent(params.env, reactionEventId, {
|
|
247
313
|
...reactionEvent,
|
|
@@ -249,7 +315,9 @@ export class Story {
|
|
|
249
315
|
});
|
|
250
316
|
await updateContextStatus(params.env, contextSelector, "open");
|
|
251
317
|
await completeExecution(params.env, contextSelector, executionId, "completed");
|
|
252
|
-
|
|
318
|
+
if (!silent) {
|
|
319
|
+
await closeStoryStream({ preventClose, sendFinish });
|
|
320
|
+
}
|
|
253
321
|
return {
|
|
254
322
|
contextId: currentContext.id,
|
|
255
323
|
context: updatedContext,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ekairos/story",
|
|
3
|
-
"version": "1.21.
|
|
3
|
+
"version": "1.21.52-beta.0",
|
|
4
4
|
"description": "Pulzar Story - Workflow-based AI Stories",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
".": {
|
|
22
22
|
"types": "./dist/index.d.ts",
|
|
23
23
|
"import": "./dist/index.js",
|
|
24
|
+
"require": "./dist/index.js",
|
|
24
25
|
"default": "./dist/index.js"
|
|
25
26
|
},
|
|
26
27
|
"./runtime": {
|
|
@@ -39,6 +40,19 @@
|
|
|
39
40
|
"default": "./dist/stores/instant.store.js"
|
|
40
41
|
}
|
|
41
42
|
},
|
|
43
|
+
"typesVersions": {
|
|
44
|
+
"*": {
|
|
45
|
+
"runtime": [
|
|
46
|
+
"dist/runtime.d.ts"
|
|
47
|
+
],
|
|
48
|
+
"next": [
|
|
49
|
+
"dist/next.d.ts"
|
|
50
|
+
],
|
|
51
|
+
"instant": [
|
|
52
|
+
"dist/stores/instant.store.d.ts"
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
},
|
|
42
56
|
"scripts": {
|
|
43
57
|
"build": "tsc -p tsconfig.json",
|
|
44
58
|
"dev": "tsc -p tsconfig.json --watch",
|
|
@@ -48,7 +62,7 @@
|
|
|
48
62
|
},
|
|
49
63
|
"dependencies": {
|
|
50
64
|
"@ai-sdk/openai": "^2.0.52",
|
|
51
|
-
"@ekairos/domain": "^1.21.
|
|
65
|
+
"@ekairos/domain": "^1.21.52-beta.0",
|
|
52
66
|
"@instantdb/admin": "^0.22.13",
|
|
53
67
|
"@instantdb/core": "^0.22.13",
|
|
54
68
|
"@vercel/sandbox": "^0.0.23",
|