@ekairos/story 1.21.30-beta.0 → 1.21.32-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/README.md +174 -0
- package/dist/agent.builder.d.ts +52 -0
- package/dist/agent.builder.d.ts.map +1 -0
- package/dist/agent.builder.js +110 -0
- package/dist/agent.builder.js.map +1 -0
- package/dist/agent.d.ts +2 -119
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.engine.d.ts +75 -0
- package/dist/agent.engine.d.ts.map +1 -0
- package/dist/agent.engine.js +455 -0
- package/dist/agent.engine.js.map +1 -0
- package/dist/agent.js +8 -607
- package/dist/agent.js.map +1 -1
- package/dist/ekairos.config.d.ts +21 -0
- package/dist/ekairos.config.d.ts.map +1 -0
- package/dist/ekairos.config.js +26 -0
- package/dist/ekairos.config.js.map +1 -0
- package/dist/events.d.ts +11 -7
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +37 -210
- package/dist/events.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -25
- package/dist/index.js.map +1 -1
- package/dist/legacy.story.d.ts +5 -0
- package/dist/legacy.story.d.ts.map +1 -0
- package/dist/legacy.story.js +15 -0
- package/dist/legacy.story.js.map +1 -0
- package/dist/runtime.d.ts +12 -0
- package/dist/runtime.js +12 -0
- package/dist/schema-document.d.ts +0 -1
- package/dist/schema-document.js +14 -18
- package/dist/schema-document.js.map +1 -1
- package/dist/schema.d.ts +0 -1
- package/dist/schema.js +22 -26
- package/dist/schema.js.map +1 -1
- package/dist/steps/do-story-stream-step.d.ts +29 -0
- package/dist/steps/do-story-stream-step.d.ts.map +1 -0
- package/dist/steps/do-story-stream-step.js +89 -0
- package/dist/steps/do-story-stream-step.js.map +1 -0
- package/dist/steps/index.d.ts +1 -3
- package/dist/steps/index.d.ts.map +1 -1
- package/dist/steps/index.js +3 -17
- package/dist/steps/index.js.map +1 -1
- package/dist/steps/store.steps.d.ts +43 -0
- package/dist/steps/store.steps.d.ts.map +1 -0
- package/dist/steps/store.steps.js +123 -0
- package/dist/steps/store.steps.js.map +1 -0
- package/dist/steps/story.steps.d.ts +35 -0
- package/dist/steps/story.steps.d.ts.map +1 -0
- package/dist/steps/story.steps.js +59 -0
- package/dist/steps/story.steps.js.map +1 -0
- package/dist/steps/stream.steps.d.ts +28 -0
- package/dist/steps/stream.steps.d.ts.map +1 -0
- package/dist/steps/stream.steps.js +75 -0
- package/dist/steps/stream.steps.js.map +1 -0
- package/dist/stores/instant.document-parser.d.ts +5 -0
- package/dist/stores/instant.document-parser.d.ts.map +1 -0
- package/dist/stores/instant.document-parser.js +116 -0
- package/dist/stores/instant.document-parser.js.map +1 -0
- package/dist/stores/instant.documents.d.ts +16 -0
- package/dist/stores/instant.documents.js +108 -0
- package/dist/stores/instant.store.d.ts +40 -0
- package/dist/stores/instant.store.d.ts.map +1 -0
- package/dist/stores/instant.store.js +207 -0
- package/dist/stores/instant.store.js.map +1 -0
- package/dist/story.builder.d.ts +116 -0
- package/dist/story.builder.d.ts.map +1 -0
- package/dist/story.builder.js +130 -0
- package/dist/story.builder.js.map +1 -0
- package/dist/story.config.d.ts +43 -0
- package/dist/story.config.d.ts.map +1 -0
- package/dist/story.config.js +57 -0
- package/dist/story.config.js.map +1 -0
- package/dist/story.d.ts +2 -50
- package/dist/story.d.ts.map +1 -1
- package/dist/story.engine.d.ts +174 -0
- package/dist/story.engine.d.ts.map +1 -0
- package/dist/story.engine.js +283 -0
- package/dist/story.engine.js.map +1 -0
- package/dist/story.js +6 -55
- package/dist/story.js.map +1 -1
- package/dist/story.legacy.d.ts +12 -0
- package/dist/story.legacy.d.ts.map +1 -0
- package/dist/story.legacy.js +15 -0
- package/dist/story.legacy.js.map +1 -0
- package/dist/story.registry.d.ts +21 -0
- package/dist/story.registry.d.ts.map +1 -0
- package/dist/story.registry.js +30 -0
- package/dist/story.registry.js.map +1 -0
- package/dist/story.store.d.ts +59 -0
- package/dist/story.store.d.ts.map +1 -0
- package/dist/story.store.js +1 -0
- package/dist/story.store.js.map +1 -0
- package/dist/story.streams.d.ts +55 -0
- package/dist/story.streams.d.ts.map +1 -0
- package/dist/story.streams.js +99 -0
- package/dist/story.streams.js.map +1 -0
- package/dist/story.toolcalls.d.ts +60 -0
- package/dist/story.toolcalls.d.ts.map +1 -0
- package/dist/story.toolcalls.js +73 -0
- package/dist/story.toolcalls.js.map +1 -0
- package/dist/tools-to-model-tools.d.ts +19 -0
- package/dist/tools-to-model-tools.js +21 -0
- package/dist/workflow.d.ts +20 -0
- package/dist/workflow.js +27 -0
- package/package.json +15 -4
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Legacy entrypoint.
|
|
3
|
+
*
|
|
4
|
+
* Este archivo existe únicamente para compatibilidad hacia atrás.
|
|
5
|
+
* No exporta nada más que `createAgent`.
|
|
6
|
+
*/
|
|
7
|
+
import { createStory } from "./story.builder";
|
|
8
|
+
/**
|
|
9
|
+
* @deprecated Use `createStory()` from the main entrypoint.
|
|
10
|
+
*/
|
|
11
|
+
export declare const createAgent: typeof createStory;
|
|
12
|
+
//# sourceMappingURL=story.legacy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"story.legacy.d.ts","sourceRoot":"","sources":["../src/story.legacy.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAE7C;;GAEG;AACH,eAAO,MAAM,WAAW,oBAAc,CAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createAgent = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Legacy entrypoint.
|
|
6
|
+
*
|
|
7
|
+
* Este archivo existe únicamente para compatibilidad hacia atrás.
|
|
8
|
+
* No exporta nada más que `createAgent`.
|
|
9
|
+
*/
|
|
10
|
+
const story_builder_1 = require("./story.builder");
|
|
11
|
+
/**
|
|
12
|
+
* @deprecated Use `createStory()` from the main entrypoint.
|
|
13
|
+
*/
|
|
14
|
+
exports.createAgent = story_builder_1.createStory;
|
|
15
|
+
//# sourceMappingURL=story.legacy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"story.legacy.js","sourceRoot":"","sources":["../src/story.legacy.ts"],"names":[],"mappings":";;;AAAA;;;;;GAKG;AACH,mDAA6C;AAE7C;;GAEG;AACU,QAAA,WAAW,GAAG,2BAAW,CAAA","sourcesContent":["/**\n * Legacy entrypoint.\n *\n * Este archivo existe únicamente para compatibilidad hacia atrás.\n * No exporta nada más que `createAgent`.\n */\nimport { createStory } from \"./story.builder\"\n\n/**\n * @deprecated Use `createStory()` from the main entrypoint.\n */\nexport const createAgent = createStory\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { StoryEnvironment } from "./story.config";
|
|
2
|
+
import type { StoryInstance } from "./story.builder";
|
|
3
|
+
/**
|
|
4
|
+
* Global registry for stories, similar to Inngest's function registry.
|
|
5
|
+
*
|
|
6
|
+
* Goals:
|
|
7
|
+
* - `createStory("key")` can be called many times (module reloads, tests, etc.)
|
|
8
|
+
* - Execution resolves a story by key (`getStory("key")`) instead of importing the module directly.
|
|
9
|
+
* - Registration is intentionally **runtime-local** (per process / per serverless instance).
|
|
10
|
+
*/
|
|
11
|
+
export type StoryKey = string;
|
|
12
|
+
type AnyStory = StoryInstance<any, any>;
|
|
13
|
+
export type StoryFactory = () => AnyStory;
|
|
14
|
+
export declare function registerStory(key: StoryKey, factory: StoryFactory): void;
|
|
15
|
+
export declare function hasStory(key: StoryKey): boolean;
|
|
16
|
+
export declare function getStory<Env extends StoryEnvironment = StoryEnvironment>(key: StoryKey): AnyStory & {
|
|
17
|
+
__config: {};
|
|
18
|
+
};
|
|
19
|
+
export declare function getStoryFactory(key: StoryKey): StoryFactory;
|
|
20
|
+
export declare function listStories(): string[];
|
|
21
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"story.registry.d.ts","sourceRoot":"","sources":["../src/story.registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAEpD;;;;;;;GAOG;AAEH,MAAM,MAAM,QAAQ,GAAG,MAAM,CAAA;AAE7B,KAAK,QAAQ,GAAG,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;AAEvC,MAAM,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAA;AAIzC,wBAAgB,aAAa,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,QAQjE;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,QAAQ,WAErC;AAED,wBAAgB,QAAQ,CAAC,GAAG,SAAS,gBAAgB,GAAG,gBAAgB,EAAE,GAAG,EAAE,QAAQ,GAOtD,QAAQ,GAAG;IAAE,QAAQ,EAAE,EAA6B,CAAA;CAAE,CACtF;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,QAAQ,gBAQ5C;AAED,wBAAgB,WAAW,aAE1B"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const registry = new Map();
|
|
2
|
+
export function registerStory(key, factory) {
|
|
3
|
+
if (!key || typeof key !== "string") {
|
|
4
|
+
throw new Error("registerStory: key must be a non-empty string");
|
|
5
|
+
}
|
|
6
|
+
if (typeof factory !== "function") {
|
|
7
|
+
throw new Error("registerStory: factory must be a function");
|
|
8
|
+
}
|
|
9
|
+
registry.set(key, factory);
|
|
10
|
+
}
|
|
11
|
+
export function hasStory(key) {
|
|
12
|
+
return registry.has(key);
|
|
13
|
+
}
|
|
14
|
+
export function getStory(key) {
|
|
15
|
+
const factory = registry.get(key);
|
|
16
|
+
if (!factory) {
|
|
17
|
+
throw new Error(`Story "${key}" is not registered. Ensure the module that calls createStory("${key}") is imported during boot.`);
|
|
18
|
+
}
|
|
19
|
+
return factory();
|
|
20
|
+
}
|
|
21
|
+
export function getStoryFactory(key) {
|
|
22
|
+
const factory = registry.get(key);
|
|
23
|
+
if (!factory) {
|
|
24
|
+
throw new Error(`Story "${key}" is not registered. Ensure the module that calls createStory("${key}") is imported during boot.`);
|
|
25
|
+
}
|
|
26
|
+
return factory;
|
|
27
|
+
}
|
|
28
|
+
export function listStories() {
|
|
29
|
+
return Array.from(registry.keys());
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"story.registry.js","sourceRoot":"","sources":["../src/story.registry.ts"],"names":[],"mappings":"AAkBA,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA0B,CAAA;AAElD,MAAM,UAAU,aAAa,CAAC,GAAa,EAAE,OAAqB;IAChE,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;IAClE,CAAC;IACD,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAA;IAC9D,CAAC;IACD,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;AAC5B,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,GAAa;IACpC,OAAO,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;AAC1B,CAAC;AAED,MAAM,UAAU,QAAQ,CAAkD,GAAa;IACrF,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACjC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,UAAU,GAAG,kEAAkE,GAAG,6BAA6B,CAChH,CAAA;IACH,CAAC;IACD,OAAO,OAAO,EAAuE,CAAA;AACvF,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAa;IAC3C,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IACjC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,UAAU,GAAG,kEAAkE,GAAG,6BAA6B,CAChH,CAAA;IACH,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,OAAO,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;AACpC,CAAC","sourcesContent":["import type { StoryEnvironment } from \"./story.config\"\nimport type { StoryInstance } from \"./story.builder\"\n\n/**\n * Global registry for stories, similar to Inngest's function registry.\n *\n * Goals:\n * - `createStory(\"key\")` can be called many times (module reloads, tests, etc.)\n * - Execution resolves a story by key (`getStory(\"key\")`) instead of importing the module directly.\n * - Registration is intentionally **runtime-local** (per process / per serverless instance).\n */\n\nexport type StoryKey = string\n\ntype AnyStory = StoryInstance<any, any>\n\nexport type StoryFactory = () => AnyStory\n\nconst registry = new Map<StoryKey, StoryFactory>()\n\nexport function registerStory(key: StoryKey, factory: StoryFactory) {\n if (!key || typeof key !== \"string\") {\n throw new Error(\"registerStory: key must be a non-empty string\")\n }\n if (typeof factory !== \"function\") {\n throw new Error(\"registerStory: factory must be a function\")\n }\n registry.set(key, factory)\n}\n\nexport function hasStory(key: StoryKey) {\n return registry.has(key)\n}\n\nexport function getStory<Env extends StoryEnvironment = StoryEnvironment>(key: StoryKey) {\n const factory = registry.get(key)\n if (!factory) {\n throw new Error(\n `Story \"${key}\" is not registered. Ensure the module that calls createStory(\"${key}\") is imported during boot.`,\n )\n }\n return factory() as unknown as AnyStory & { __config: { /* keep typings stable */ } }\n}\n\nexport function getStoryFactory(key: StoryKey) {\n const factory = registry.get(key)\n if (!factory) {\n throw new Error(\n `Story \"${key}\" is not registered. Ensure the module that calls createStory(\"${key}\") is imported during boot.`,\n )\n }\n return factory\n}\n\nexport function listStories() {\n return Array.from(registry.keys())\n}\n\n\n"]}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { ModelMessage } from "ai";
|
|
2
|
+
/**
|
|
3
|
+
* ## story.store.ts
|
|
4
|
+
*
|
|
5
|
+
* A `StoryStore` is the persistence boundary for stories.
|
|
6
|
+
*
|
|
7
|
+
* Workflow DevKit constraints mean **workflows must be deterministic** and all I/O must happen
|
|
8
|
+
* in steps. This library therefore models persistence as a pluggable store that can be
|
|
9
|
+
* instantiated *inside steps* (InstantDB, Postgres, etc.).
|
|
10
|
+
*
|
|
11
|
+
* The core engine should depend only on this interface (not on a specific database).
|
|
12
|
+
*/
|
|
13
|
+
export type ContextIdentifier = {
|
|
14
|
+
id: string;
|
|
15
|
+
key?: never;
|
|
16
|
+
} | {
|
|
17
|
+
key: string;
|
|
18
|
+
id?: never;
|
|
19
|
+
};
|
|
20
|
+
export type ContextStatus = "open" | "streaming" | "closed";
|
|
21
|
+
export type StoredContext<Context> = {
|
|
22
|
+
id: string;
|
|
23
|
+
key: string | null;
|
|
24
|
+
status: ContextStatus;
|
|
25
|
+
createdAt: Date;
|
|
26
|
+
updatedAt?: Date;
|
|
27
|
+
content: Context | null;
|
|
28
|
+
};
|
|
29
|
+
export type ContextEvent = {
|
|
30
|
+
id: string;
|
|
31
|
+
type: string;
|
|
32
|
+
channel: string;
|
|
33
|
+
createdAt: string;
|
|
34
|
+
status?: string;
|
|
35
|
+
content: any;
|
|
36
|
+
};
|
|
37
|
+
export type ExecutionStatus = "executing" | "completed" | "failed";
|
|
38
|
+
export interface StoryStore {
|
|
39
|
+
getOrCreateContext<C>(contextIdentifier: ContextIdentifier | null): Promise<StoredContext<C>>;
|
|
40
|
+
getContext<C>(contextIdentifier: ContextIdentifier): Promise<StoredContext<C> | null>;
|
|
41
|
+
updateContextContent<C>(contextIdentifier: ContextIdentifier, content: C): Promise<StoredContext<C>>;
|
|
42
|
+
updateContextStatus(contextIdentifier: ContextIdentifier, status: ContextStatus): Promise<void>;
|
|
43
|
+
saveEvent(contextIdentifier: ContextIdentifier, event: ContextEvent): Promise<ContextEvent>;
|
|
44
|
+
updateEvent(eventId: string, event: ContextEvent): Promise<ContextEvent>;
|
|
45
|
+
getEvent(eventId: string): Promise<ContextEvent | null>;
|
|
46
|
+
getEvents(contextIdentifier: ContextIdentifier): Promise<ContextEvent[]>;
|
|
47
|
+
createExecution(contextIdentifier: ContextIdentifier, triggerEventId: string, reactionEventId: string): Promise<{
|
|
48
|
+
id: string;
|
|
49
|
+
}>;
|
|
50
|
+
completeExecution(contextIdentifier: ContextIdentifier, executionId: string, status: Exclude<ExecutionStatus, "executing">): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Converts events to model messages for the next LLM call.
|
|
53
|
+
*
|
|
54
|
+
* NOTE:
|
|
55
|
+
* - Attachment/document expansion should happen earlier in the Story loop via `expandEvents(...)`.
|
|
56
|
+
* - This method should stay focused on converting already-normalized event parts into `ModelMessage[]`.
|
|
57
|
+
*/
|
|
58
|
+
eventsToModelMessages(events: ContextEvent[]): Promise<ModelMessage[]>;
|
|
59
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"story.store.d.ts","sourceRoot":"","sources":["../src/story.store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,IAAI,CAAA;AAEtC;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,iBAAiB,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,KAAK,CAAA;CAAE,CAAA;AAEzF,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAA;AAE3D,MAAM,MAAM,aAAa,CAAC,OAAO,IAAI;IACnC,EAAE,EAAE,MAAM,CAAA;IACV,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB,MAAM,EAAE,aAAa,CAAA;IACrB,SAAS,EAAE,IAAI,CAAA;IACf,SAAS,CAAC,EAAE,IAAI,CAAA;IAChB,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,GAAG,CAAA;CACb,CAAA;AAED,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG,WAAW,GAAG,QAAQ,CAAA;AAElE,MAAM,WAAW,UAAU;IACzB,kBAAkB,CAAC,CAAC,EAAE,iBAAiB,EAAE,iBAAiB,GAAG,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;IAC7F,UAAU,CAAC,CAAC,EAAE,iBAAiB,EAAE,iBAAiB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAA;IACrF,oBAAoB,CAAC,CAAC,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;IACpG,mBAAmB,CAAC,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAE/F,SAAS,CAAC,iBAAiB,EAAE,iBAAiB,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;IAC3F,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;IACxE,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAAA;IACvD,SAAS,CAAC,iBAAiB,EAAE,iBAAiB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAA;IAExE,eAAe,CACb,iBAAiB,EAAE,iBAAiB,EACpC,cAAc,EAAE,MAAM,EACtB,eAAe,EAAE,MAAM,GACtB,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAE1B,iBAAiB,CACf,iBAAiB,EAAE,iBAAiB,EACpC,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,OAAO,CAAC,eAAe,EAAE,WAAW,CAAC,GAC5C,OAAO,CAAC,IAAI,CAAC,CAAA;IAEhB;;;;;;OAMG;IACH,qBAAqB,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAA;CACvE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"story.store.js","sourceRoot":"","sources":["../src/story.store.ts"],"names":[],"mappings":"","sourcesContent":["import type { ModelMessage } from \"ai\"\r\n\r\n/**\r\n * ## story.store.ts\r\n *\r\n * A `StoryStore` is the persistence boundary for stories.\r\n *\r\n * Workflow DevKit constraints mean **workflows must be deterministic** and all I/O must happen\r\n * in steps. This library therefore models persistence as a pluggable store that can be\r\n * instantiated *inside steps* (InstantDB, Postgres, etc.).\r\n *\r\n * The core engine should depend only on this interface (not on a specific database).\r\n */\r\n\r\nexport type ContextIdentifier = { id: string; key?: never } | { key: string; id?: never }\r\n\r\nexport type ContextStatus = \"open\" | \"streaming\" | \"closed\"\r\n\r\nexport type StoredContext<Context> = {\r\n id: string\r\n key: string | null\r\n status: ContextStatus\r\n createdAt: Date\r\n updatedAt?: Date\r\n content: Context | null\r\n}\r\n\r\nexport type ContextEvent = {\r\n id: string\r\n type: string\r\n channel: string\r\n createdAt: string\r\n status?: string\r\n content: any\r\n}\r\n\r\nexport type ExecutionStatus = \"executing\" | \"completed\" | \"failed\"\r\n\r\nexport interface StoryStore {\r\n getOrCreateContext<C>(contextIdentifier: ContextIdentifier | null): Promise<StoredContext<C>>\r\n getContext<C>(contextIdentifier: ContextIdentifier): Promise<StoredContext<C> | null>\r\n updateContextContent<C>(contextIdentifier: ContextIdentifier, content: C): Promise<StoredContext<C>>\r\n updateContextStatus(contextIdentifier: ContextIdentifier, status: ContextStatus): Promise<void>\r\n\r\n saveEvent(contextIdentifier: ContextIdentifier, event: ContextEvent): Promise<ContextEvent>\r\n updateEvent(eventId: string, event: ContextEvent): Promise<ContextEvent>\r\n getEvent(eventId: string): Promise<ContextEvent | null>\r\n getEvents(contextIdentifier: ContextIdentifier): Promise<ContextEvent[]>\r\n\r\n createExecution(\r\n contextIdentifier: ContextIdentifier,\r\n triggerEventId: string,\r\n reactionEventId: string,\r\n ): Promise<{ id: string }>\r\n\r\n completeExecution(\r\n contextIdentifier: ContextIdentifier,\r\n executionId: string,\r\n status: Exclude<ExecutionStatus, \"executing\">,\r\n ): Promise<void>\r\n\r\n /**\r\n * Converts events to model messages for the next LLM call.\r\n *\r\n * NOTE:\r\n * - Attachment/document expansion should happen earlier in the Story loop via `expandEvents(...)`.\r\n * - This method should stay focused on converting already-normalized event parts into `ModelMessage[]`.\r\n */\r\n eventsToModelMessages(events: ContextEvent[]): Promise<ModelMessage[]>\r\n}\r\n\r\n\r\n\r\n"]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { DataStreamWriter } from "./story.engine";
|
|
2
|
+
/**
|
|
3
|
+
* Filters internal chunks from the AI SDK stream that we use for loop control.
|
|
4
|
+
*
|
|
5
|
+
* In the engine, when we do `result.toUIMessageStream(...).pipeThrough(...)`,
|
|
6
|
+
* this filter prevents the final consumer from seeing events like:
|
|
7
|
+
* - `start-step` / `finish-step`: iteration control
|
|
8
|
+
* - `start` / `finish`: underlying stream control
|
|
9
|
+
*
|
|
10
|
+
* Note: we *do* keep emitting other custom chunks (e.g. `event-start`,
|
|
11
|
+
* `tool-output-*`, `data-context-id`) because they are useful for UI/observability.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createInternalChunkFilter(): TransformStream<any, any>;
|
|
14
|
+
/**
|
|
15
|
+
* Normalizes the start of the stream so the consumer receives a `start` with a
|
|
16
|
+
* consistent `messageId`.
|
|
17
|
+
*
|
|
18
|
+
* - Filters the original AI SDK `start` chunk (if it appears).
|
|
19
|
+
* - Converts our internal `event-start` chunk into:
|
|
20
|
+
* `{ type: "start", messageId: <eventId> }`
|
|
21
|
+
*
|
|
22
|
+
* This allows the UI to associate the stream to a stable “reaction event” ID
|
|
23
|
+
* (created by the engine) instead of relying on IDs generated by the SDK.
|
|
24
|
+
*/
|
|
25
|
+
export declare function createStreamStartNormalizer(): TransformStream<any, any>;
|
|
26
|
+
/**
|
|
27
|
+
* Helpers for writing control/metadata chunks.
|
|
28
|
+
*
|
|
29
|
+
* These helpers encapsulate the exact chunk shapes so that:
|
|
30
|
+
* - `story.engine.ts` reads like orchestration (“what”) instead of plumbing (“how”),
|
|
31
|
+
* - we can evolve chunk formats in a single place if the SDK/UI changes.
|
|
32
|
+
*/
|
|
33
|
+
export declare const StreamWriter: {
|
|
34
|
+
/**
|
|
35
|
+
* Internal signal: “reaction event started”.
|
|
36
|
+
* Later used by `createStreamStartNormalizer()` to emit `start/messageId`.
|
|
37
|
+
*/
|
|
38
|
+
writeEventStart(dataStream: DataStreamWriter, eventId: string): void;
|
|
39
|
+
/** Internal signal: start of a loop iteration. */
|
|
40
|
+
writeStartStep(dataStream: DataStreamWriter): void;
|
|
41
|
+
/** Internal signal: end of a loop iteration. */
|
|
42
|
+
writeFinishStep(dataStream: DataStreamWriter): void;
|
|
43
|
+
/** Useful metadata for UI/observability: current `contextId`. */
|
|
44
|
+
writeContextId(dataStream: DataStreamWriter, contextId: string): void;
|
|
45
|
+
/** Successful tool result, associated to `toolCallId`. */
|
|
46
|
+
writeToolOutputAvailable(dataStream: DataStreamWriter, toolCallId: string, output: unknown): void;
|
|
47
|
+
/** Failed tool result, associated to `toolCallId`. */
|
|
48
|
+
writeToolOutputError(dataStream: DataStreamWriter, toolCallId: string, errorText: string): void;
|
|
49
|
+
/**
|
|
50
|
+
* Internal signal: terminate the stream/loop.
|
|
51
|
+
* `override=true` is used when we want to cut immediately.
|
|
52
|
+
*/
|
|
53
|
+
writeFinish(dataStream: DataStreamWriter, override?: boolean): void;
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=story.streams.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"story.streams.d.ts","sourceRoot":"","sources":["../src/story.streams.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAyCtD;;;;;;;;;;GAUG;AACH,wBAAgB,yBAAyB,8BAOxC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,8BAW1C;AAED;;;;;;GAMG;AACH,eAAO,MAAM,YAAY;IACvB;;;OAGG;gCACyB,gBAAgB,WAAW,MAAM;IAG7D,kDAAkD;+BACvB,gBAAgB;IAG3C,gDAAgD;gCACpB,gBAAgB;IAG5C,iEAAiE;+BACtC,gBAAgB,aAAa,MAAM;IAG9D,0DAA0D;yCACrB,gBAAgB,cAAc,MAAM,UAAU,OAAO;IAK1F,sDAAsD;qCACrB,gBAAgB,cAAc,MAAM,aAAa,MAAM;IAGxF;;;OAGG;4BACqB,gBAAgB;CAGzC,CAAA"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StreamWriter = void 0;
|
|
4
|
+
exports.createInternalChunkFilter = createInternalChunkFilter;
|
|
5
|
+
exports.createStreamStartNormalizer = createStreamStartNormalizer;
|
|
6
|
+
const INTERNAL_CHUNK_TYPES = [
|
|
7
|
+
"start",
|
|
8
|
+
"finish-step",
|
|
9
|
+
"start-step",
|
|
10
|
+
"finish",
|
|
11
|
+
];
|
|
12
|
+
/**
|
|
13
|
+
* Filters internal chunks from the AI SDK stream that we use for loop control.
|
|
14
|
+
*
|
|
15
|
+
* In the engine, when we do `result.toUIMessageStream(...).pipeThrough(...)`,
|
|
16
|
+
* this filter prevents the final consumer from seeing events like:
|
|
17
|
+
* - `start-step` / `finish-step`: iteration control
|
|
18
|
+
* - `start` / `finish`: underlying stream control
|
|
19
|
+
*
|
|
20
|
+
* Note: we *do* keep emitting other custom chunks (e.g. `event-start`,
|
|
21
|
+
* `tool-output-*`, `data-context-id`) because they are useful for UI/observability.
|
|
22
|
+
*/
|
|
23
|
+
function createInternalChunkFilter() {
|
|
24
|
+
return new TransformStream({
|
|
25
|
+
transform(chunk, controller) {
|
|
26
|
+
if (INTERNAL_CHUNK_TYPES.includes(chunk.type))
|
|
27
|
+
return;
|
|
28
|
+
controller.enqueue(chunk);
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Normalizes the start of the stream so the consumer receives a `start` with a
|
|
34
|
+
* consistent `messageId`.
|
|
35
|
+
*
|
|
36
|
+
* - Filters the original AI SDK `start` chunk (if it appears).
|
|
37
|
+
* - Converts our internal `event-start` chunk into:
|
|
38
|
+
* `{ type: "start", messageId: <eventId> }`
|
|
39
|
+
*
|
|
40
|
+
* This allows the UI to associate the stream to a stable “reaction event” ID
|
|
41
|
+
* (created by the engine) instead of relying on IDs generated by the SDK.
|
|
42
|
+
*/
|
|
43
|
+
function createStreamStartNormalizer() {
|
|
44
|
+
return new TransformStream({
|
|
45
|
+
transform(chunk, controller) {
|
|
46
|
+
if (chunk.type === "start")
|
|
47
|
+
return;
|
|
48
|
+
if (chunk.type === "event-start") {
|
|
49
|
+
controller.enqueue({ type: "start", messageId: chunk.data.eventId });
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
controller.enqueue(chunk);
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Helpers for writing control/metadata chunks.
|
|
58
|
+
*
|
|
59
|
+
* These helpers encapsulate the exact chunk shapes so that:
|
|
60
|
+
* - `story.engine.ts` reads like orchestration (“what”) instead of plumbing (“how”),
|
|
61
|
+
* - we can evolve chunk formats in a single place if the SDK/UI changes.
|
|
62
|
+
*/
|
|
63
|
+
exports.StreamWriter = {
|
|
64
|
+
/**
|
|
65
|
+
* Internal signal: “reaction event started”.
|
|
66
|
+
* Later used by `createStreamStartNormalizer()` to emit `start/messageId`.
|
|
67
|
+
*/
|
|
68
|
+
writeEventStart(dataStream, eventId) {
|
|
69
|
+
dataStream.write({ type: "event-start", data: { eventId } });
|
|
70
|
+
},
|
|
71
|
+
/** Internal signal: start of a loop iteration. */
|
|
72
|
+
writeStartStep(dataStream) {
|
|
73
|
+
dataStream.write({ type: "start-step" });
|
|
74
|
+
},
|
|
75
|
+
/** Internal signal: end of a loop iteration. */
|
|
76
|
+
writeFinishStep(dataStream) {
|
|
77
|
+
dataStream.write({ type: "finish-step" });
|
|
78
|
+
},
|
|
79
|
+
/** Useful metadata for UI/observability: current `contextId`. */
|
|
80
|
+
writeContextId(dataStream, contextId) {
|
|
81
|
+
dataStream.write({ type: "data-context-id", data: { contextId } });
|
|
82
|
+
},
|
|
83
|
+
/** Successful tool result, associated to `toolCallId`. */
|
|
84
|
+
writeToolOutputAvailable(dataStream, toolCallId, output) {
|
|
85
|
+
dataStream.write({ type: "tool-output-available", toolCallId, output });
|
|
86
|
+
},
|
|
87
|
+
/** Failed tool result, associated to `toolCallId`. */
|
|
88
|
+
writeToolOutputError(dataStream, toolCallId, errorText) {
|
|
89
|
+
dataStream.write({ type: "tool-output-error", toolCallId, errorText });
|
|
90
|
+
},
|
|
91
|
+
/**
|
|
92
|
+
* Internal signal: terminate the stream/loop.
|
|
93
|
+
* `override=true` is used when we want to cut immediately.
|
|
94
|
+
*/
|
|
95
|
+
writeFinish(dataStream, override = false) {
|
|
96
|
+
dataStream.write({ type: "finish", override });
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
//# sourceMappingURL=story.streams.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"story.streams.js","sourceRoot":"","sources":["../src/story.streams.ts"],"names":[],"mappings":";;;AAoDA,8DAOC;AAaD,kEAWC;AAjDD,MAAM,oBAAoB,GAAwB;IAChD,OAAO;IACP,aAAa;IACb,YAAY;IACZ,QAAQ;CACT,CAAA;AAED;;;;;;;;;;GAUG;AACH,SAAgB,yBAAyB;IACvC,OAAO,IAAI,eAAe,CAAC;QACzB,SAAS,CAAC,KAAU,EAAE,UAAe;YACnC,IAAI,oBAAoB,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAyB,CAAC;gBAAE,OAAM;YAC1E,UAAU,CAAC,OAAO,CAAC,KAAY,CAAC,CAAA;QAClC,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAgB,2BAA2B;IACzC,OAAO,IAAI,eAAe,CAAC;QACzB,SAAS,CAAC,KAAU,EAAE,UAAe;YACnC,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO;gBAAE,OAAM;YAClC,IAAI,KAAK,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;gBACjC,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAA;gBACpE,OAAM;YACR,CAAC;YACD,UAAU,CAAC,OAAO,CAAC,KAAY,CAAC,CAAA;QAClC,CAAC;KACF,CAAC,CAAA;AACJ,CAAC;AAED;;;;;;GAMG;AACU,QAAA,YAAY,GAAG;IAC1B;;;OAGG;IACH,eAAe,CAAC,UAA4B,EAAE,OAAe;QAC3D,UAAU,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,EAAS,CAAC,CAAA;IACrE,CAAC;IACD,kDAAkD;IAClD,cAAc,CAAC,UAA4B;QACzC,UAAU,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,YAAY,EAAS,CAAC,CAAA;IACjD,CAAC;IACD,gDAAgD;IAChD,eAAe,CAAC,UAA4B;QAC1C,UAAU,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,aAAa,EAAS,CAAC,CAAA;IAClD,CAAC;IACD,iEAAiE;IACjE,cAAc,CAAC,UAA4B,EAAE,SAAiB;QAC5D,UAAU,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,EAAS,CAAC,CAAA;IAC3E,CAAC;IACD,0DAA0D;IAC1D,wBAAwB,CAAC,UAA4B,EAAE,UAAkB,EAAE,MAAe;QACxF,UAAU,CAAC,KAAK,CACd,EAAE,IAAI,EAAE,uBAAuB,EAAE,UAAU,EAAE,MAAM,EAAS,CAC7D,CAAA;IACH,CAAC;IACD,sDAAsD;IACtD,oBAAoB,CAAC,UAA4B,EAAE,UAAkB,EAAE,SAAiB;QACtF,UAAU,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,UAAU,EAAE,SAAS,EAAS,CAAC,CAAA;IAC/E,CAAC;IACD;;;OAGG;IACH,WAAW,CAAC,UAA4B,EAAE,QAAQ,GAAG,KAAK;QACxD,UAAU,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAS,CAAC,CAAA;IACvD,CAAC;CACF,CAAA","sourcesContent":["import type { DataStreamWriter } from \"./story.engine\"\r\n\r\n/**\r\n * ## story.streams.ts\r\n *\r\n * This module exists to **intercept** the stream produced by `ai` (AI SDK)\r\n * (`toUIMessageStream()` / `createUIMessageStream()`) and **extend it** with\r\n * control chunks that allow us to **orchestrate an execution loop**\r\n * (multiple steps with tools) without “polluting” the public stream that clients consume.\r\n *\r\n * ### What problem does it solve?\r\n * In `story.engine.ts` we need to:\r\n * - Keep the output stream “clean” (only user-relevant tokens/messages).\r\n * - While still emitting internal signals to:\r\n * - mark the start of a “reaction event” (a stable messageId),\r\n * - mark the start/end of each loop iteration,\r\n * - publish metadata (e.g. `contextId`),\r\n * - publish tool results (`tool-output-*`),\r\n * - terminate the loop and/or the stream at the right time.\r\n *\r\n * To achieve this, we **write internal chunks** into the `DataStreamWriter` and then:\r\n * - filter control-only chunks before exposing the stream,\r\n * - normalize “start” so the consumer receives a consistent `messageId`.\r\n *\r\n * ### Stream mental model\r\n * - **Internal stream**: AI SDK chunks + our internal chunks mixed together.\r\n * - **Public stream**: internal stream piped through transforms (filter + normalization).\r\n *\r\n * > Important: this is deliberately “thin”. It doesn't decide anything about the loop;\r\n * > it only provides utilities to *instrument* the stream.\r\n */\r\n\r\ntype InternalChunkType = \"start\" | \"finish-step\" | \"start-step\" | \"finish\"\r\n\r\nconst INTERNAL_CHUNK_TYPES: InternalChunkType[] = [\r\n \"start\",\r\n \"finish-step\",\r\n \"start-step\",\r\n \"finish\",\r\n]\r\n\r\n/**\r\n * Filters internal chunks from the AI SDK stream that we use for loop control.\r\n *\r\n * In the engine, when we do `result.toUIMessageStream(...).pipeThrough(...)`,\r\n * this filter prevents the final consumer from seeing events like:\r\n * - `start-step` / `finish-step`: iteration control\r\n * - `start` / `finish`: underlying stream control\r\n *\r\n * Note: we *do* keep emitting other custom chunks (e.g. `event-start`,\r\n * `tool-output-*`, `data-context-id`) because they are useful for UI/observability.\r\n */\r\nexport function createInternalChunkFilter() {\r\n return new TransformStream({\r\n transform(chunk: any, controller: any) {\r\n if (INTERNAL_CHUNK_TYPES.includes(chunk.type as InternalChunkType)) return\r\n controller.enqueue(chunk as any)\r\n },\r\n })\r\n}\r\n\r\n/**\r\n * Normalizes the start of the stream so the consumer receives a `start` with a\r\n * consistent `messageId`.\r\n *\r\n * - Filters the original AI SDK `start` chunk (if it appears).\r\n * - Converts our internal `event-start` chunk into:\r\n * `{ type: \"start\", messageId: <eventId> }`\r\n *\r\n * This allows the UI to associate the stream to a stable “reaction event” ID\r\n * (created by the engine) instead of relying on IDs generated by the SDK.\r\n */\r\nexport function createStreamStartNormalizer() {\r\n return new TransformStream({\r\n transform(chunk: any, controller: any) {\r\n if (chunk.type === \"start\") return\r\n if (chunk.type === \"event-start\") {\r\n controller.enqueue({ type: \"start\", messageId: chunk.data.eventId })\r\n return\r\n }\r\n controller.enqueue(chunk as any)\r\n },\r\n })\r\n}\r\n\r\n/**\r\n * Helpers for writing control/metadata chunks.\r\n *\r\n * These helpers encapsulate the exact chunk shapes so that:\r\n * - `story.engine.ts` reads like orchestration (“what”) instead of plumbing (“how”),\r\n * - we can evolve chunk formats in a single place if the SDK/UI changes.\r\n */\r\nexport const StreamWriter = {\r\n /**\r\n * Internal signal: “reaction event started”.\r\n * Later used by `createStreamStartNormalizer()` to emit `start/messageId`.\r\n */\r\n writeEventStart(dataStream: DataStreamWriter, eventId: string) {\r\n dataStream.write({ type: \"event-start\", data: { eventId } } as any)\r\n },\r\n /** Internal signal: start of a loop iteration. */\r\n writeStartStep(dataStream: DataStreamWriter) {\r\n dataStream.write({ type: \"start-step\" } as any)\r\n },\r\n /** Internal signal: end of a loop iteration. */\r\n writeFinishStep(dataStream: DataStreamWriter) {\r\n dataStream.write({ type: \"finish-step\" } as any)\r\n },\r\n /** Useful metadata for UI/observability: current `contextId`. */\r\n writeContextId(dataStream: DataStreamWriter, contextId: string) {\r\n dataStream.write({ type: \"data-context-id\", data: { contextId } } as any)\r\n },\r\n /** Successful tool result, associated to `toolCallId`. */\r\n writeToolOutputAvailable(dataStream: DataStreamWriter, toolCallId: string, output: unknown) {\r\n dataStream.write(\r\n { type: \"tool-output-available\", toolCallId, output } as any,\r\n )\r\n },\r\n /** Failed tool result, associated to `toolCallId`. */\r\n writeToolOutputError(dataStream: DataStreamWriter, toolCallId: string, errorText: string) {\r\n dataStream.write({ type: \"tool-output-error\", toolCallId, errorText } as any)\r\n },\r\n /**\r\n * Internal signal: terminate the stream/loop.\r\n * `override=true` is used when we want to cut immediately.\r\n */\r\n writeFinish(dataStream: DataStreamWriter, override = false) {\r\n dataStream.write({ type: \"finish\", override } as any)\r\n },\r\n}\r\n\r\n\r\n"]}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ## story.toolcalls.ts
|
|
3
|
+
*
|
|
4
|
+
* This module isolates the **tool-call plumbing** used by `story.engine.ts`.
|
|
5
|
+
*
|
|
6
|
+
* In our runtime, tool calls are represented as **event parts** produced by the AI SDK.
|
|
7
|
+
* The engine needs to:
|
|
8
|
+
* - extract a normalized list of tool calls from `event.content.parts`, and
|
|
9
|
+
* - merge tool execution outcomes back into those parts (so the persisted event reflects
|
|
10
|
+
* `output-available` / `output-error`, etc.).
|
|
11
|
+
*
|
|
12
|
+
* Keeping this logic here helps `story.engine.ts` read like orchestration, and keeps
|
|
13
|
+
* these transformations testable and reusable.
|
|
14
|
+
*/
|
|
15
|
+
import type { ContextEvent } from "./story.store";
|
|
16
|
+
export type ToolCall = {
|
|
17
|
+
toolCallId: string;
|
|
18
|
+
toolName: string;
|
|
19
|
+
args: any;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Extracts tool calls from an event's `parts` array.
|
|
23
|
+
*
|
|
24
|
+
* Expected part shape (loosely):
|
|
25
|
+
* - `type`: string like `"tool-<toolName>"`
|
|
26
|
+
* - `toolCallId`: string
|
|
27
|
+
* - `input`: any (tool args)
|
|
28
|
+
*
|
|
29
|
+
* We intentionally treat the input as `any` because the part schema is produced by the AI SDK.
|
|
30
|
+
*/
|
|
31
|
+
export declare function extractToolCallsFromParts(parts: any[] | undefined | null): ToolCall[];
|
|
32
|
+
/**
|
|
33
|
+
* Applies a tool execution outcome to the matching tool part.
|
|
34
|
+
*
|
|
35
|
+
* This does not mutate `parts` — it returns a new array.
|
|
36
|
+
*
|
|
37
|
+
* We match the tool part by:
|
|
38
|
+
* - `type === "tool-<toolName>"` and
|
|
39
|
+
* - `toolCallId` equality
|
|
40
|
+
*
|
|
41
|
+
* Then we set:
|
|
42
|
+
* - on success: `{ state: "output-available", output: <result> }`
|
|
43
|
+
* - on failure: `{ state: "output-error", errorText: <message> }`
|
|
44
|
+
*/
|
|
45
|
+
export declare function applyToolExecutionResultToParts(parts: any[], toolCall: Pick<ToolCall, "toolCallId" | "toolName">, execution: {
|
|
46
|
+
success: boolean;
|
|
47
|
+
result: any;
|
|
48
|
+
message?: string;
|
|
49
|
+
}): any[];
|
|
50
|
+
/**
|
|
51
|
+
* Returns `true` when a given tool has a **settled** execution result in an event's parts.
|
|
52
|
+
*
|
|
53
|
+
* We treat a tool part as "executed" once it has either:
|
|
54
|
+
* - `state: "output-available"` (success), or
|
|
55
|
+
* - `state: "output-error"` (failure).
|
|
56
|
+
*
|
|
57
|
+
* This is useful for stop/continue logic in `story.shouldContinue(...)` where you want to
|
|
58
|
+
* decide based on the persisted `reactionEvent` (not ephemeral in-memory arrays).
|
|
59
|
+
*/
|
|
60
|
+
export declare function didToolExecute(event: Pick<ContextEvent, "content">, toolName: string): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"story.toolcalls.d.ts","sourceRoot":"","sources":["../src/story.toolcalls.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,MAAM,QAAQ,GAAG;IACrB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,GAAG,CAAA;CACV,CAAA;AAED;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,SAAS,GAAG,IAAI,GAAG,QAAQ,EAAE,CASrF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,+BAA+B,CAC7C,KAAK,EAAE,GAAG,EAAE,EACZ,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,YAAY,GAAG,UAAU,CAAC,EACnD,SAAS,EAAE;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,GAAG,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7D,GAAG,EAAE,CAUP"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ## story.toolcalls.ts
|
|
3
|
+
*
|
|
4
|
+
* This module isolates the **tool-call plumbing** used by `story.engine.ts`.
|
|
5
|
+
*
|
|
6
|
+
* In our runtime, tool calls are represented as **event parts** produced by the AI SDK.
|
|
7
|
+
* The engine needs to:
|
|
8
|
+
* - extract a normalized list of tool calls from `event.content.parts`, and
|
|
9
|
+
* - merge tool execution outcomes back into those parts (so the persisted event reflects
|
|
10
|
+
* `output-available` / `output-error`, etc.).
|
|
11
|
+
*
|
|
12
|
+
* Keeping this logic here helps `story.engine.ts` read like orchestration, and keeps
|
|
13
|
+
* these transformations testable and reusable.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Extracts tool calls from an event's `parts` array.
|
|
17
|
+
*
|
|
18
|
+
* Expected part shape (loosely):
|
|
19
|
+
* - `type`: string like `"tool-<toolName>"`
|
|
20
|
+
* - `toolCallId`: string
|
|
21
|
+
* - `input`: any (tool args)
|
|
22
|
+
*
|
|
23
|
+
* We intentionally treat the input as `any` because the part schema is produced by the AI SDK.
|
|
24
|
+
*/
|
|
25
|
+
export function extractToolCallsFromParts(parts) {
|
|
26
|
+
const safeParts = parts ?? [];
|
|
27
|
+
return safeParts.reduce((acc, p) => {
|
|
28
|
+
if (typeof p?.type === "string" && p.type.startsWith("tool-")) {
|
|
29
|
+
const toolName = p.type.split("-")[1];
|
|
30
|
+
acc.push({ toolCallId: p.toolCallId, toolName, args: p.input });
|
|
31
|
+
}
|
|
32
|
+
return acc;
|
|
33
|
+
}, []);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Applies a tool execution outcome to the matching tool part.
|
|
37
|
+
*
|
|
38
|
+
* This does not mutate `parts` — it returns a new array.
|
|
39
|
+
*
|
|
40
|
+
* We match the tool part by:
|
|
41
|
+
* - `type === "tool-<toolName>"` and
|
|
42
|
+
* - `toolCallId` equality
|
|
43
|
+
*
|
|
44
|
+
* Then we set:
|
|
45
|
+
* - on success: `{ state: "output-available", output: <result> }`
|
|
46
|
+
* - on failure: `{ state: "output-error", errorText: <message> }`
|
|
47
|
+
*/
|
|
48
|
+
export function applyToolExecutionResultToParts(parts, toolCall, execution) {
|
|
49
|
+
return parts.map((p) => {
|
|
50
|
+
if (p?.type === `tool-${toolCall.toolName}` && p.toolCallId === toolCall.toolCallId) {
|
|
51
|
+
if (execution.success) {
|
|
52
|
+
return { ...p, state: "output-available", output: execution.result };
|
|
53
|
+
}
|
|
54
|
+
return { ...p, state: "output-error", errorText: String(execution.message || "Error") };
|
|
55
|
+
}
|
|
56
|
+
return p;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Returns `true` when a given tool has a **settled** execution result in an event's parts.
|
|
61
|
+
*
|
|
62
|
+
* We treat a tool part as "executed" once it has either:
|
|
63
|
+
* - `state: "output-available"` (success), or
|
|
64
|
+
* - `state: "output-error"` (failure).
|
|
65
|
+
*
|
|
66
|
+
* This is useful for stop/continue logic in `story.shouldContinue(...)` where you want to
|
|
67
|
+
* decide based on the persisted `reactionEvent` (not ephemeral in-memory arrays).
|
|
68
|
+
*/
|
|
69
|
+
export function didToolExecute(event, toolName) {
|
|
70
|
+
const parts = event.content.parts;
|
|
71
|
+
return parts.some((p) => p.type === `tool-${toolName}` &&
|
|
72
|
+
(p.state === "output-available" || p.state === "output-error"));
|
|
73
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"story.toolcalls.js","sourceRoot":"","sources":["../src/story.toolcalls.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAQH;;;;;;;;;GASG;AACH,MAAM,UAAU,yBAAyB,CAAC,KAA+B;IACvE,MAAM,SAAS,GAAG,KAAK,IAAI,EAAE,CAAA;IAC7B,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,GAAe,EAAE,CAAM,EAAE,EAAE;QAClD,IAAI,OAAO,CAAC,EAAE,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC9D,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;YACrC,GAAG,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAA;QACjE,CAAC;QACD,OAAO,GAAG,CAAA;IACZ,CAAC,EAAE,EAAE,CAAC,CAAA;AACR,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,+BAA+B,CAC7C,KAAY,EACZ,QAAmD,EACnD,SAA8D;IAE9D,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE;QAC1B,IAAI,CAAC,EAAE,IAAI,KAAK,QAAQ,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,UAAU,KAAK,QAAQ,CAAC,UAAU,EAAE,CAAC;YACpF,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;gBACtB,OAAO,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,CAAA;YACtE,CAAC;YACD,OAAO,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,OAAO,IAAI,OAAO,CAAC,EAAE,CAAA;QACzF,CAAC;QACD,OAAO,CAAC,CAAA;IACV,CAAC,CAAC,CAAA;AACJ,CAAC","sourcesContent":["/**\n * ## story.toolcalls.ts\n *\n * This module isolates the **tool-call plumbing** used by `story.engine.ts`.\n *\n * In our runtime, tool calls are represented as **event parts** produced by the AI SDK.\n * The engine needs to:\n * - extract a normalized list of tool calls from `event.content.parts`, and\n * - merge tool execution outcomes back into those parts (so the persisted event reflects\n * `output-available` / `output-error`, etc.).\n *\n * Keeping this logic here helps `story.engine.ts` read like orchestration, and keeps\n * these transformations testable and reusable.\n */\n\nexport type ToolCall = {\n toolCallId: string\n toolName: string\n args: any\n}\n\n/**\n * Extracts tool calls from an event's `parts` array.\n *\n * Expected part shape (loosely):\n * - `type`: string like `\"tool-<toolName>\"`\n * - `toolCallId`: string\n * - `input`: any (tool args)\n *\n * We intentionally treat the input as `any` because the part schema is produced by the AI SDK.\n */\nexport function extractToolCallsFromParts(parts: any[] | undefined | null): ToolCall[] {\n const safeParts = parts ?? []\n return safeParts.reduce((acc: ToolCall[], p: any) => {\n if (typeof p?.type === \"string\" && p.type.startsWith(\"tool-\")) {\n const toolName = p.type.split(\"-\")[1]\n acc.push({ toolCallId: p.toolCallId, toolName, args: p.input })\n }\n return acc\n }, [])\n}\n\n/**\n * Applies a tool execution outcome to the matching tool part.\n *\n * This does not mutate `parts` — it returns a new array.\n *\n * We match the tool part by:\n * - `type === \"tool-<toolName>\"` and\n * - `toolCallId` equality\n *\n * Then we set:\n * - on success: `{ state: \"output-available\", output: <result> }`\n * - on failure: `{ state: \"output-error\", errorText: <message> }`\n */\nexport function applyToolExecutionResultToParts(\n parts: any[],\n toolCall: Pick<ToolCall, \"toolCallId\" | \"toolName\">,\n execution: { success: boolean; result: any; message?: string },\n): any[] {\n return parts.map((p: any) => {\n if (p?.type === `tool-${toolCall.toolName}` && p.toolCallId === toolCall.toolCallId) {\n if (execution.success) {\n return { ...p, state: \"output-available\", output: execution.result }\n }\n return { ...p, state: \"output-error\", errorText: String(execution.message || \"Error\") }\n }\n return p\n })\n}\n\n\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type Tool } from "ai";
|
|
2
|
+
/**
|
|
3
|
+
* Serializable "tool" shape to pass across the Workflow step boundary.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors Workflow DevKit's DurableAgent strategy:
|
|
6
|
+
* - Keep Zod/function values out of step arguments
|
|
7
|
+
* - Convert tool input schemas to plain JSON Schema in workflow context
|
|
8
|
+
*/
|
|
9
|
+
export type SerializableToolForModel = {
|
|
10
|
+
description?: string;
|
|
11
|
+
inputSchema: unknown;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Convert AI SDK tools to a serializable representation that can be passed to `"use step"` functions.
|
|
15
|
+
*
|
|
16
|
+
* This matches DurableAgent's internal `toolsToModelTools` behavior:
|
|
17
|
+
* `inputSchema: asSchema(tool.inputSchema).jsonSchema`
|
|
18
|
+
*/
|
|
19
|
+
export declare function toolsToModelTools(tools: Record<string, Tool>): Record<string, SerializableToolForModel>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { asSchema } from "ai";
|
|
2
|
+
/**
|
|
3
|
+
* Convert AI SDK tools to a serializable representation that can be passed to `"use step"` functions.
|
|
4
|
+
*
|
|
5
|
+
* This matches DurableAgent's internal `toolsToModelTools` behavior:
|
|
6
|
+
* `inputSchema: asSchema(tool.inputSchema).jsonSchema`
|
|
7
|
+
*/
|
|
8
|
+
export function toolsToModelTools(tools) {
|
|
9
|
+
const out = {};
|
|
10
|
+
for (const [name, tool] of Object.entries(tools)) {
|
|
11
|
+
const inputSchema = tool?.inputSchema;
|
|
12
|
+
if (!inputSchema) {
|
|
13
|
+
throw new Error(`Story: tool "${name}" is missing inputSchema (required for model tool calls)`);
|
|
14
|
+
}
|
|
15
|
+
out[name] = {
|
|
16
|
+
description: tool?.description,
|
|
17
|
+
inputSchema: asSchema(inputSchema).jsonSchema,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
return out;
|
|
21
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workflow DevKit interop helper.
|
|
3
|
+
*
|
|
4
|
+
* In some environments / TS setups, the `workflow` package is typed/exported as a default export,
|
|
5
|
+
* even though runtime usage expects `getWritable()` to exist.
|
|
6
|
+
*
|
|
7
|
+
* We centralize that interop here so the rest of the codebase can just do:
|
|
8
|
+
* `import { getWritable } from "./workflow"`.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getWritable<W = any>(): WritableStream<W>;
|
|
11
|
+
/**
|
|
12
|
+
* Typed wrapper around Workflow DevKit's `getWritable()`.
|
|
13
|
+
*
|
|
14
|
+
* Why:
|
|
15
|
+
* - The `workflow` package typing in some environments is surfaced as a default export,
|
|
16
|
+
* which makes `import { getWritable } from "workflow"` fail typechecking.
|
|
17
|
+
* - `@ekairos/story` wants to call `getWritable()` inside `"use step"` functions without
|
|
18
|
+
* leaking import quirks across the codebase.
|
|
19
|
+
*/
|
|
20
|
+
export declare const getWritable: <W = any>() => WritableStream<W>;
|
package/dist/workflow.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import workflow from "workflow";
|
|
2
|
+
/**
|
|
3
|
+
* Workflow DevKit interop helper.
|
|
4
|
+
*
|
|
5
|
+
* In some environments / TS setups, the `workflow` package is typed/exported as a default export,
|
|
6
|
+
* even though runtime usage expects `getWritable()` to exist.
|
|
7
|
+
*
|
|
8
|
+
* We centralize that interop here so the rest of the codebase can just do:
|
|
9
|
+
* `import { getWritable } from "./workflow"`.
|
|
10
|
+
*/
|
|
11
|
+
export function getWritable() {
|
|
12
|
+
const fn = workflow.getWritable ?? workflow.default?.getWritable;
|
|
13
|
+
if (typeof fn !== "function") {
|
|
14
|
+
throw new Error("workflow.getWritable is not available in this runtime");
|
|
15
|
+
}
|
|
16
|
+
return fn();
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Typed wrapper around Workflow DevKit's `getWritable()`.
|
|
20
|
+
*
|
|
21
|
+
* Why:
|
|
22
|
+
* - The `workflow` package typing in some environments is surfaced as a default export,
|
|
23
|
+
* which makes `import { getWritable } from "workflow"` fail typechecking.
|
|
24
|
+
* - `@ekairos/story` wants to call `getWritable()` inside `"use step"` functions without
|
|
25
|
+
* leaking import quirks across the codebase.
|
|
26
|
+
*/
|
|
27
|
+
export const getWritable = workflow.getWritable;
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ekairos/story",
|
|
3
|
-
"version": "1.21.
|
|
3
|
+
"version": "1.21.32-beta.0",
|
|
4
4
|
"description": "Pulzar Story - Workflow-based AI Stories",
|
|
5
|
-
"type": "
|
|
5
|
+
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"files": [
|
|
@@ -20,8 +20,18 @@
|
|
|
20
20
|
"exports": {
|
|
21
21
|
".": {
|
|
22
22
|
"types": "./dist/index.d.ts",
|
|
23
|
-
"
|
|
23
|
+
"import": "./dist/index.js",
|
|
24
24
|
"default": "./dist/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./runtime": {
|
|
27
|
+
"types": "./dist/runtime.d.ts",
|
|
28
|
+
"import": "./dist/runtime.js",
|
|
29
|
+
"default": "./dist/runtime.js"
|
|
30
|
+
},
|
|
31
|
+
"./instant": {
|
|
32
|
+
"types": "./dist/stores/instant.store.d.ts",
|
|
33
|
+
"import": "./dist/stores/instant.store.js",
|
|
34
|
+
"default": "./dist/stores/instant.store.js"
|
|
25
35
|
}
|
|
26
36
|
},
|
|
27
37
|
"scripts": {
|
|
@@ -33,7 +43,7 @@
|
|
|
33
43
|
},
|
|
34
44
|
"dependencies": {
|
|
35
45
|
"@ai-sdk/openai": "^2.0.52",
|
|
36
|
-
"@ekairos/domain": "^1.21.
|
|
46
|
+
"@ekairos/domain": "^1.21.32-beta.0",
|
|
37
47
|
"@instantdb/admin": "^0.22.13",
|
|
38
48
|
"@instantdb/core": "^0.22.13",
|
|
39
49
|
"@vercel/sandbox": "^0.0.23",
|
|
@@ -41,6 +51,7 @@
|
|
|
41
51
|
"ajv": "^8.17.1",
|
|
42
52
|
"braintrust": "^0.3.7",
|
|
43
53
|
"llamaindex": "^0.12.0",
|
|
54
|
+
"workflow": "4.0.1-beta.13",
|
|
44
55
|
"xmlbuilder2": "^3.1.1",
|
|
45
56
|
"zod": "^4.1.8"
|
|
46
57
|
},
|