@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.
Files changed (108) hide show
  1. package/README.md +174 -0
  2. package/dist/agent.builder.d.ts +52 -0
  3. package/dist/agent.builder.d.ts.map +1 -0
  4. package/dist/agent.builder.js +110 -0
  5. package/dist/agent.builder.js.map +1 -0
  6. package/dist/agent.d.ts +2 -119
  7. package/dist/agent.d.ts.map +1 -1
  8. package/dist/agent.engine.d.ts +75 -0
  9. package/dist/agent.engine.d.ts.map +1 -0
  10. package/dist/agent.engine.js +455 -0
  11. package/dist/agent.engine.js.map +1 -0
  12. package/dist/agent.js +8 -607
  13. package/dist/agent.js.map +1 -1
  14. package/dist/ekairos.config.d.ts +21 -0
  15. package/dist/ekairos.config.d.ts.map +1 -0
  16. package/dist/ekairos.config.js +26 -0
  17. package/dist/ekairos.config.js.map +1 -0
  18. package/dist/events.d.ts +11 -7
  19. package/dist/events.d.ts.map +1 -1
  20. package/dist/events.js +37 -210
  21. package/dist/events.js.map +1 -1
  22. package/dist/index.d.ts +4 -4
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +7 -25
  25. package/dist/index.js.map +1 -1
  26. package/dist/legacy.story.d.ts +5 -0
  27. package/dist/legacy.story.d.ts.map +1 -0
  28. package/dist/legacy.story.js +15 -0
  29. package/dist/legacy.story.js.map +1 -0
  30. package/dist/runtime.d.ts +12 -0
  31. package/dist/runtime.js +12 -0
  32. package/dist/schema-document.d.ts +0 -1
  33. package/dist/schema-document.js +14 -18
  34. package/dist/schema-document.js.map +1 -1
  35. package/dist/schema.d.ts +0 -1
  36. package/dist/schema.js +22 -26
  37. package/dist/schema.js.map +1 -1
  38. package/dist/steps/do-story-stream-step.d.ts +29 -0
  39. package/dist/steps/do-story-stream-step.d.ts.map +1 -0
  40. package/dist/steps/do-story-stream-step.js +89 -0
  41. package/dist/steps/do-story-stream-step.js.map +1 -0
  42. package/dist/steps/index.d.ts +1 -3
  43. package/dist/steps/index.d.ts.map +1 -1
  44. package/dist/steps/index.js +3 -17
  45. package/dist/steps/index.js.map +1 -1
  46. package/dist/steps/store.steps.d.ts +43 -0
  47. package/dist/steps/store.steps.d.ts.map +1 -0
  48. package/dist/steps/store.steps.js +123 -0
  49. package/dist/steps/store.steps.js.map +1 -0
  50. package/dist/steps/story.steps.d.ts +35 -0
  51. package/dist/steps/story.steps.d.ts.map +1 -0
  52. package/dist/steps/story.steps.js +59 -0
  53. package/dist/steps/story.steps.js.map +1 -0
  54. package/dist/steps/stream.steps.d.ts +28 -0
  55. package/dist/steps/stream.steps.d.ts.map +1 -0
  56. package/dist/steps/stream.steps.js +75 -0
  57. package/dist/steps/stream.steps.js.map +1 -0
  58. package/dist/stores/instant.document-parser.d.ts +5 -0
  59. package/dist/stores/instant.document-parser.d.ts.map +1 -0
  60. package/dist/stores/instant.document-parser.js +116 -0
  61. package/dist/stores/instant.document-parser.js.map +1 -0
  62. package/dist/stores/instant.documents.d.ts +16 -0
  63. package/dist/stores/instant.documents.js +108 -0
  64. package/dist/stores/instant.store.d.ts +40 -0
  65. package/dist/stores/instant.store.d.ts.map +1 -0
  66. package/dist/stores/instant.store.js +207 -0
  67. package/dist/stores/instant.store.js.map +1 -0
  68. package/dist/story.builder.d.ts +116 -0
  69. package/dist/story.builder.d.ts.map +1 -0
  70. package/dist/story.builder.js +130 -0
  71. package/dist/story.builder.js.map +1 -0
  72. package/dist/story.config.d.ts +43 -0
  73. package/dist/story.config.d.ts.map +1 -0
  74. package/dist/story.config.js +57 -0
  75. package/dist/story.config.js.map +1 -0
  76. package/dist/story.d.ts +2 -50
  77. package/dist/story.d.ts.map +1 -1
  78. package/dist/story.engine.d.ts +174 -0
  79. package/dist/story.engine.d.ts.map +1 -0
  80. package/dist/story.engine.js +283 -0
  81. package/dist/story.engine.js.map +1 -0
  82. package/dist/story.js +6 -55
  83. package/dist/story.js.map +1 -1
  84. package/dist/story.legacy.d.ts +12 -0
  85. package/dist/story.legacy.d.ts.map +1 -0
  86. package/dist/story.legacy.js +15 -0
  87. package/dist/story.legacy.js.map +1 -0
  88. package/dist/story.registry.d.ts +21 -0
  89. package/dist/story.registry.d.ts.map +1 -0
  90. package/dist/story.registry.js +30 -0
  91. package/dist/story.registry.js.map +1 -0
  92. package/dist/story.store.d.ts +59 -0
  93. package/dist/story.store.d.ts.map +1 -0
  94. package/dist/story.store.js +1 -0
  95. package/dist/story.store.js.map +1 -0
  96. package/dist/story.streams.d.ts +55 -0
  97. package/dist/story.streams.d.ts.map +1 -0
  98. package/dist/story.streams.js +99 -0
  99. package/dist/story.streams.js.map +1 -0
  100. package/dist/story.toolcalls.d.ts +60 -0
  101. package/dist/story.toolcalls.d.ts.map +1 -0
  102. package/dist/story.toolcalls.js +73 -0
  103. package/dist/story.toolcalls.js.map +1 -0
  104. package/dist/tools-to-model-tools.d.ts +19 -0
  105. package/dist/tools-to-model-tools.js +21 -0
  106. package/dist/workflow.d.ts +20 -0
  107. package/dist/workflow.js +27 -0
  108. package/package.json +15 -4
@@ -0,0 +1,207 @@
1
+ import { id, lookup } from "@instantdb/admin";
2
+ import { convertEventsToModelMessages } from "../events";
3
+ export { parseAndStoreDocument } from "./instant.document-parser";
4
+ import { expandEventsWithInstantDocuments } from "./instant.documents";
5
+ export { coerceDocumentTextPages, expandEventsWithInstantDocuments, } from "./instant.documents";
6
+ export class InstantStore {
7
+ constructor(db) {
8
+ this.db = db;
9
+ }
10
+ async getOrCreateContext(contextIdentifier) {
11
+ if (!contextIdentifier) {
12
+ return this.createContext();
13
+ }
14
+ const context = await this.getContext(contextIdentifier);
15
+ if (!context) {
16
+ return this.createContext(contextIdentifier.key ? { key: contextIdentifier.key } : null, contextIdentifier.id);
17
+ }
18
+ return context;
19
+ }
20
+ async createContext(contextKey, contextId) {
21
+ let contextData = {
22
+ createdAt: new Date(),
23
+ content: {},
24
+ key: null,
25
+ status: "open",
26
+ };
27
+ const newContextId = contextId ?? id();
28
+ if (contextKey?.key) {
29
+ contextData = { ...contextData, key: contextKey.key };
30
+ }
31
+ await this.db.transact([
32
+ this.db.tx.context_contexts[newContextId].create(contextData),
33
+ ]);
34
+ const ctx = await this.getContext({ id: newContextId });
35
+ if (!ctx)
36
+ throw new Error("InstantStore: failed to create context");
37
+ return ctx;
38
+ }
39
+ async getContext(contextIdentifier) {
40
+ try {
41
+ if (contextIdentifier.id) {
42
+ const res = await this.db.query({
43
+ context_contexts: {
44
+ $: { where: { id: contextIdentifier.id }, limit: 1 },
45
+ },
46
+ });
47
+ return res.context_contexts?.[0] ?? null;
48
+ }
49
+ if (contextIdentifier.key) {
50
+ const res = await this.db.query({
51
+ context_contexts: {
52
+ $: { where: { key: contextIdentifier.key } },
53
+ },
54
+ });
55
+ return res.context_contexts?.[0] ?? null;
56
+ }
57
+ return null;
58
+ }
59
+ catch (error) {
60
+ throw new Error("InstantStore: Error getting context: " + error.message);
61
+ }
62
+ }
63
+ async updateContextContent(contextIdentifier, content) {
64
+ const contextDBIdentifier = contextIdentifier.id ?? lookup("key", contextIdentifier.key);
65
+ await this.db.transact([
66
+ this.db.tx.context_contexts[contextDBIdentifier].update({
67
+ content: content,
68
+ updatedAt: new Date(),
69
+ }),
70
+ ]);
71
+ const ctx = await this.getContext(contextIdentifier);
72
+ if (!ctx)
73
+ throw new Error("InstantStore: context not found after update");
74
+ return ctx;
75
+ }
76
+ async updateContextStatus(contextIdentifier, status) {
77
+ const txs = [];
78
+ if (contextIdentifier.id) {
79
+ txs.push(this.db.tx.context_contexts[contextIdentifier.id].update({
80
+ status,
81
+ updatedAt: new Date(),
82
+ }));
83
+ }
84
+ else {
85
+ txs.push(this.db.tx.context_contexts[lookup("key", contextIdentifier.key)].update({
86
+ status,
87
+ updatedAt: new Date(),
88
+ }));
89
+ }
90
+ await this.db.transact(txs);
91
+ }
92
+ async saveEvent(contextIdentifier, event) {
93
+ const txs = [
94
+ this.db.tx.context_events[event.id].update({
95
+ ...event,
96
+ status: "stored",
97
+ }),
98
+ ];
99
+ if (contextIdentifier.id) {
100
+ txs.push(this.db.tx.context_events[event.id].link({ context: contextIdentifier.id }));
101
+ }
102
+ else {
103
+ txs.push(this.db.tx.context_events[event.id].link({ context: lookup("key", contextIdentifier.key) }));
104
+ }
105
+ await this.db.transact(txs);
106
+ const persisted = await this.getEvent(event.id);
107
+ if (!persisted)
108
+ throw new Error("InstantStore: failed to read event after save");
109
+ return persisted;
110
+ }
111
+ async updateEvent(eventId, event) {
112
+ await this.db.transact([this.db.tx.context_events[eventId].update(event)]);
113
+ const persisted = await this.getEvent(eventId);
114
+ if (!persisted)
115
+ throw new Error("InstantStore: event not found after update");
116
+ return persisted;
117
+ }
118
+ async getEvent(eventId) {
119
+ const res = await this.db.query({
120
+ context_events: {
121
+ $: { where: { id: eventId } },
122
+ },
123
+ });
124
+ return res.context_events?.[0] ?? null;
125
+ }
126
+ async getEvents(contextIdentifier) {
127
+ const contextWhere = contextIdentifier.id
128
+ ? { context: contextIdentifier.id }
129
+ : { context: lookup("key", contextIdentifier.key) };
130
+ const res = await this.db.query({
131
+ context_events: {
132
+ $: {
133
+ where: contextWhere,
134
+ limit: 30,
135
+ order: { createdAt: "asc" },
136
+ },
137
+ },
138
+ });
139
+ return res.context_events ?? [];
140
+ }
141
+ async createExecution(contextIdentifier, triggerEventId, reactionEventId) {
142
+ const executionId = id();
143
+ const execCreate = this.db.tx.story_executions[executionId].create({
144
+ createdAt: new Date(),
145
+ status: "executing",
146
+ });
147
+ const txs = [execCreate];
148
+ if (contextIdentifier.id) {
149
+ txs.push(this.db.tx.story_executions[executionId].link({ context: contextIdentifier.id }));
150
+ txs.push(this.db.tx.context_contexts[contextIdentifier.id].link({ currentExecution: executionId }));
151
+ }
152
+ else {
153
+ const ctxLookup = lookup("key", contextIdentifier.key);
154
+ txs.push(this.db.tx.story_executions[executionId].link({ context: ctxLookup }));
155
+ txs.push(this.db.tx.context_contexts[ctxLookup].link({ currentExecution: executionId }));
156
+ }
157
+ txs.push(this.db.tx.story_executions[executionId].link({ trigger: triggerEventId }));
158
+ txs.push(this.db.tx.story_executions[executionId].link({ reaction: reactionEventId }));
159
+ await this.db.transact(txs);
160
+ return { id: executionId };
161
+ }
162
+ async completeExecution(contextIdentifier, executionId, status) {
163
+ const txs = [];
164
+ txs.push(this.db.tx.story_executions[executionId].update({ status, updatedAt: new Date() }));
165
+ // Update context status back to "open" when execution completes
166
+ if (contextIdentifier.id) {
167
+ txs.push(this.db.tx.context_contexts[contextIdentifier.id].update({ status: "open", updatedAt: new Date() }));
168
+ }
169
+ else {
170
+ txs.push(this.db.tx.context_contexts[lookup("key", contextIdentifier.key)].update({ status: "open", updatedAt: new Date() }));
171
+ }
172
+ await this.db.transact(txs);
173
+ }
174
+ async eventsToModelMessages(events) {
175
+ // Default behavior for Instant-backed stories:
176
+ // - Expand file parts into derived `document.parsed` events (persisting parsed content into document_documents)
177
+ // - Then convert expanded events to model messages
178
+ const expanded = await expandEventsWithInstantDocuments({
179
+ db: this.db,
180
+ events,
181
+ derivedEventType: "document.parsed",
182
+ });
183
+ return await convertEventsToModelMessages(expanded);
184
+ }
185
+ }
186
+ /**
187
+ * Helper to create a StoryRuntimeResolver that returns an InstantStore.
188
+ *
189
+ * This keeps the app-level `ekairos.ts` extremely small.
190
+ */
191
+ export function createInstantStoreRuntime(params) {
192
+ const storesByOrg = new Map();
193
+ return async (env) => {
194
+ const orgId = params.getOrgId?.(env) ??
195
+ (typeof env?.orgId === "string" ? String(env.orgId) : "");
196
+ if (!orgId) {
197
+ throw new Error('[instant] Missing orgId in env. Provide env.orgId (or customize getOrgId).');
198
+ }
199
+ const cached = storesByOrg.get(orgId);
200
+ if (cached)
201
+ return { store: cached };
202
+ const db = await params.getDb(orgId);
203
+ const store = new InstantStore(db);
204
+ storesByOrg.set(orgId, store);
205
+ return { store };
206
+ };
207
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instant.store.js","sourceRoot":"","sources":["../../src/stores/instant.store.ts"],"names":[],"mappings":"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","sourcesContent":["import { id, lookup } from \"@instantdb/admin\"\r\n\r\nimport { storyDomain } from \"../schema\"\r\nimport { convertEventsToModelMessages } from \"../events\"\r\nimport type { ModelMessage } from \"ai\"\r\nimport type {\r\n ContextEvent,\r\n ContextIdentifier,\r\n ContextStatus,\r\n StoredContext,\r\n StoryStore,\r\n} from \"../story.store\"\r\nexport { parseAndStoreDocument } from \"./instant.document-parser\"\r\n\r\n/**\r\n * InstantDB-backed StoryStore.\r\n *\r\n * This is intentionally kept behind the store boundary so the core story engine\r\n * can remain database-agnostic.\r\n */\r\nexport type InstantStoreDb = any\r\n\r\nexport class InstantStore implements StoryStore {\r\n private db: any\r\n\r\n constructor(db: InstantStoreDb) {\r\n this.db = db\r\n }\r\n\r\n async getOrCreateContext<C>(\r\n contextIdentifier: ContextIdentifier | null,\r\n ): Promise<StoredContext<C>> {\r\n if (!contextIdentifier) {\r\n return this.createContext<C>()\r\n }\r\n\r\n const context = await this.getContext<C>(contextIdentifier)\r\n if (!context) {\r\n return this.createContext<C>(\r\n contextIdentifier.key ? { key: contextIdentifier.key } : null,\r\n contextIdentifier.id,\r\n )\r\n }\r\n\r\n return context\r\n }\r\n\r\n private async createContext<C>(\r\n contextKey?: { key: string } | null,\r\n contextId?: string,\r\n ): Promise<StoredContext<C>> {\r\n let contextData: {\r\n createdAt: Date\r\n content: Record<string, unknown>\r\n key: string | null\r\n status: \"open\"\r\n } = {\r\n createdAt: new Date(),\r\n content: {},\r\n key: null,\r\n status: \"open\",\r\n }\r\n\r\n const newContextId = contextId ?? id()\r\n if (contextKey?.key) {\r\n contextData = { ...contextData, key: contextKey.key }\r\n }\r\n\r\n await this.db.transact([\r\n this.db.tx.context_contexts[newContextId].create(contextData),\r\n ])\r\n\r\n const ctx = await this.getContext<C>({ id: newContextId })\r\n if (!ctx) throw new Error(\"InstantStore: failed to create context\")\r\n return ctx\r\n }\r\n\r\n async getContext<C>(\r\n contextIdentifier: ContextIdentifier,\r\n ): Promise<StoredContext<C> | null> {\r\n try {\r\n if (contextIdentifier.id) {\r\n const res = await this.db.query({\r\n context_contexts: {\r\n $: { where: { id: contextIdentifier.id as any }, limit: 1 },\r\n },\r\n })\r\n return (res.context_contexts?.[0] as any) ?? null\r\n }\r\n\r\n if (contextIdentifier.key) {\r\n const res = await this.db.query({\r\n context_contexts: {\r\n $: { where: { key: contextIdentifier.key } },\r\n },\r\n })\r\n return (res.context_contexts?.[0] as any) ?? null\r\n }\r\n\r\n return null\r\n } catch (error: any) {\r\n throw new Error(\"InstantStore: Error getting context: \" + error.message)\r\n }\r\n }\r\n\r\n async updateContextContent<C>(\r\n contextIdentifier: ContextIdentifier,\r\n content: C,\r\n ): Promise<StoredContext<C>> {\r\n const contextDBIdentifier =\r\n contextIdentifier.id ?? lookup(\"key\", contextIdentifier.key)\r\n\r\n await this.db.transact([\r\n this.db.tx.context_contexts[contextDBIdentifier].update({\r\n content: content as any,\r\n updatedAt: new Date(),\r\n }),\r\n ])\r\n\r\n const ctx = await this.getContext<C>(contextIdentifier)\r\n if (!ctx) throw new Error(\"InstantStore: context not found after update\")\r\n return ctx\r\n }\r\n\r\n async updateContextStatus(\r\n contextIdentifier: ContextIdentifier,\r\n status: ContextStatus,\r\n ): Promise<void> {\r\n const txs: any[] = []\r\n if (contextIdentifier.id) {\r\n txs.push(\r\n this.db.tx.context_contexts[contextIdentifier.id].update({\r\n status,\r\n updatedAt: new Date(),\r\n }),\r\n )\r\n } else {\r\n txs.push(\r\n this.db.tx.context_contexts[lookup(\"key\", contextIdentifier.key)].update({\r\n status,\r\n updatedAt: new Date(),\r\n }),\r\n )\r\n }\r\n\r\n await this.db.transact(txs)\r\n }\r\n\r\n async saveEvent(\r\n contextIdentifier: ContextIdentifier,\r\n event: ContextEvent,\r\n ): Promise<ContextEvent> {\r\n const txs = [\r\n this.db.tx.context_events[event.id].update({\r\n ...(event as any),\r\n status: \"stored\",\r\n }),\r\n ]\r\n\r\n if (contextIdentifier.id) {\r\n txs.push(this.db.tx.context_events[event.id].link({ context: contextIdentifier.id }))\r\n } else {\r\n txs.push(this.db.tx.context_events[event.id].link({ context: lookup(\"key\", contextIdentifier.key) }))\r\n }\r\n\r\n await this.db.transact(txs as any)\r\n\r\n const persisted = await this.getEvent(event.id)\r\n if (!persisted) throw new Error(\"InstantStore: failed to read event after save\")\r\n return persisted\r\n }\r\n\r\n async updateEvent(eventId: string, event: ContextEvent): Promise<ContextEvent> {\r\n await this.db.transact([this.db.tx.context_events[eventId].update(event as any)])\r\n const persisted = await this.getEvent(eventId)\r\n if (!persisted) throw new Error(\"InstantStore: event not found after update\")\r\n return persisted\r\n }\r\n\r\n async getEvent(eventId: string): Promise<ContextEvent | null> {\r\n const res = await this.db.query({\r\n context_events: {\r\n $: { where: { id: eventId as any } },\r\n },\r\n })\r\n return (res.context_events?.[0] as any) ?? null\r\n }\r\n\r\n async getEvents(contextIdentifier: ContextIdentifier): Promise<ContextEvent[]> {\r\n const contextWhere: any = contextIdentifier.id\r\n ? { context: contextIdentifier.id }\r\n : { context: lookup(\"key\", contextIdentifier.key) }\r\n\r\n const res = await this.db.query({\r\n context_events: {\r\n $: {\r\n where: contextWhere,\r\n limit: 30,\r\n order: { createdAt: \"asc\" },\r\n },\r\n },\r\n })\r\n return (res.context_events as any) ?? []\r\n }\r\n\r\n async createExecution(\r\n contextIdentifier: ContextIdentifier,\r\n triggerEventId: string,\r\n reactionEventId: string,\r\n ): Promise<{ id: string }> {\r\n const executionId = id()\r\n const execCreate = this.db.tx.story_executions[executionId].create({\r\n createdAt: new Date(),\r\n status: \"executing\",\r\n })\r\n\r\n const txs: any[] = [execCreate]\r\n\r\n if (contextIdentifier.id) {\r\n txs.push(this.db.tx.story_executions[executionId].link({ context: contextIdentifier.id }))\r\n txs.push(this.db.tx.context_contexts[contextIdentifier.id].link({ currentExecution: executionId }))\r\n } else {\r\n const ctxLookup = lookup(\"key\", contextIdentifier.key)\r\n txs.push(this.db.tx.story_executions[executionId].link({ context: ctxLookup }))\r\n txs.push(this.db.tx.context_contexts[ctxLookup].link({ currentExecution: executionId }))\r\n }\r\n\r\n txs.push(this.db.tx.story_executions[executionId].link({ trigger: triggerEventId }))\r\n txs.push(this.db.tx.story_executions[executionId].link({ reaction: reactionEventId }))\r\n\r\n await this.db.transact(txs)\r\n\r\n return { id: executionId }\r\n }\r\n\r\n async completeExecution(\r\n contextIdentifier: ContextIdentifier,\r\n executionId: string,\r\n status: \"completed\" | \"failed\",\r\n ): Promise<void> {\r\n const txs: any[] = []\r\n txs.push(this.db.tx.story_executions[executionId].update({ status, updatedAt: new Date() }))\r\n\r\n // Update context status back to \"open\" when execution completes\r\n if (contextIdentifier.id) {\r\n txs.push(this.db.tx.context_contexts[contextIdentifier.id].update({ status: \"open\", updatedAt: new Date() }))\r\n } else {\r\n txs.push(this.db.tx.context_contexts[lookup(\"key\", contextIdentifier.key)].update({ status: \"open\", updatedAt: new Date() }))\r\n }\r\n\r\n await this.db.transact(txs)\r\n }\r\n\r\n async eventsToModelMessages(events: ContextEvent[]): Promise<ModelMessage[]> {\r\n return await convertEventsToModelMessages(events)\r\n }\r\n}\r\n\r\n/**\r\n * Helper to create a StoryRuntimeResolver that returns an InstantStore.\r\n *\r\n * This keeps the app-level `ekairos.ts` extremely small.\r\n */\r\nexport function createInstantStoreRuntime(params: {\r\n getDb: (orgId: string) => Promise<InstantStoreDb> | InstantStoreDb\r\n getOrgId?: (env: Record<string, unknown>) => string\r\n}) {\r\n const storesByOrg = new Map<string, InstantStore>()\r\n\r\n return async (env: Record<string, unknown>) => {\r\n const orgId =\r\n params.getOrgId?.(env) ??\r\n (typeof (env as any)?.orgId === \"string\" ? String((env as any).orgId) : \"\")\r\n if (!orgId) {\r\n throw new Error('[instant] Missing orgId in env. Provide env.orgId (or customize getOrgId).')\r\n }\r\n\r\n const cached = storesByOrg.get(orgId)\r\n if (cached) return { store: cached }\r\n\r\n const db = await params.getDb(orgId)\r\n const store = new InstantStore(db)\r\n storesByOrg.set(orgId, store)\r\n return { store }\r\n }\r\n}\r\n\r\n\r\n\r\n"]}
@@ -0,0 +1,116 @@
1
+ import type { Tool } from "ai";
2
+ import type { StoryEnvironment } from "./story.config";
3
+ import { Story, type StoryModelInit, type StoryOptions, type ShouldContinue, type StoryShouldContinueArgs, type StoryReactParams } from "./story.engine";
4
+ import type { ContextEvent, StoredContext } from "./story.store";
5
+ import { type StoryKey } from "./story.registry";
6
+ export interface StoryConfig<Context, Env extends StoryEnvironment = StoryEnvironment> {
7
+ context: (context: StoredContext<Context>, env: Env) => Promise<Context> | Context;
8
+ /**
9
+ * Event expansion stage (first-class; executed by the engine on every loop iteration).
10
+ *
11
+ * Runs inside the Story loop after events are loaded from the store and before
12
+ * they are converted into model messages.
13
+ *
14
+ * This is the intended place to do "document expansion" (turn file references
15
+ * into text parts) using LlamaCloud/Reducto/etc.
16
+ *
17
+ * If you do not provide an implementation, the default is an identity transform
18
+ * (events pass through unchanged).
19
+ *
20
+ * If you do I/O here, implement it as a `"use step"` function.
21
+ */
22
+ expandEvents?: (events: ContextEvent[], context: StoredContext<Context>, env: Env) => Promise<ContextEvent[]> | ContextEvent[];
23
+ /**
24
+ * Story-first "system" message for the model for this story run.
25
+ */
26
+ narrative: (context: StoredContext<Context>, env: Env) => Promise<string> | string;
27
+ /**
28
+ * Actions available to the model (aka "tools" in AI SDK terminology).
29
+ */
30
+ actions: (context: StoredContext<Context>, env: Env) => Promise<Record<string, Tool>> | Record<string, Tool>;
31
+ /**
32
+ * @deprecated Use `actions()` instead.
33
+ */
34
+ tools?: (context: StoredContext<Context>, env: Env) => Promise<Record<string, Tool>> | Record<string, Tool>;
35
+ /**
36
+ * Model configuration (DurableAgent-style).
37
+ *
38
+ * - `string`: AI Gateway model id, resolved in the LLM step (e.g. `"openai/gpt-5.1-thinking"`).
39
+ * - `() => Promise<model>`: model factory. For Workflow compatibility, provide a `"use step"` function
40
+ * so it can be serialized by reference.
41
+ * - `(context, env) => ...`: dynamic selection based on current context/env (runs in workflow context).
42
+ */
43
+ model?: StoryModelInit | ((context: StoredContext<Context>, env: Env) => StoryModelInit);
44
+ /**
45
+ * Called after each streamed model "reaction" and subsequent tool executions.
46
+ *
47
+ * Use this to decide whether the story loop should continue.
48
+ *
49
+ * - `true` => continue looping
50
+ * - `false` => finalize the story run
51
+ */
52
+ shouldContinue?: (args: StoryShouldContinueArgs<Context, Env>) => Promise<ShouldContinue> | ShouldContinue;
53
+ opts?: StoryOptions<Context, Env>;
54
+ }
55
+ export type StoryInstance<Context, Env extends StoryEnvironment = StoryEnvironment> = Story<Context, Env> & {
56
+ readonly __config: StoryConfig<Context, Env>;
57
+ };
58
+ export declare function story<Context, Env extends StoryEnvironment = StoryEnvironment>(config: StoryConfig<Context, Env>): StoryInstance<Context, Env>;
59
+ type AnyContextInitializer<Env extends StoryEnvironment> = (context: StoredContext<any>, env: Env) => Promise<any> | any;
60
+ type InferContextFromInitializer<I extends AnyContextInitializer<any>> = Awaited<ReturnType<I>>;
61
+ type BuilderSystemPrompt<Context, Env extends StoryEnvironment> = (context: StoredContext<Context>, env: Env) => Promise<string> | string;
62
+ type BuilderTools<Context, Env extends StoryEnvironment> = (context: StoredContext<Context>, env: Env) => Promise<Record<string, Tool>> | Record<string, Tool>;
63
+ type BuilderExpandEvents<Context, Env extends StoryEnvironment> = (events: ContextEvent[], context: StoredContext<Context>, env: Env) => Promise<ContextEvent[]> | ContextEvent[];
64
+ type BuilderShouldContinue<Context, Env extends StoryEnvironment> = (args: StoryShouldContinueArgs<Context, Env>) => Promise<ShouldContinue> | ShouldContinue;
65
+ type BuilderModel<Context, Env extends StoryEnvironment> = StoryModelInit | ((context: StoredContext<Context>, env: Env) => StoryModelInit);
66
+ export type RegistrableStoryBuilder = {
67
+ key: StoryKey;
68
+ register: () => void;
69
+ };
70
+ type FluentStoryBuilder<Context, Env extends StoryEnvironment> = {
71
+ key: StoryKey;
72
+ expandEvents(fn: BuilderExpandEvents<Context, Env>): FluentStoryBuilder<Context, Env>;
73
+ narrative(fn: BuilderSystemPrompt<Context, Env>): FluentStoryBuilder<Context, Env>;
74
+ /**
75
+ * "System" facade (AI SDK terminology).
76
+ */
77
+ system(fn: BuilderSystemPrompt<Context, Env>): FluentStoryBuilder<Context, Env>;
78
+ actions(fn: BuilderTools<Context, Env>): FluentStoryBuilder<Context, Env>;
79
+ /**
80
+ * @deprecated Use `actions()` instead.
81
+ */
82
+ tools(fn: BuilderTools<Context, Env>): FluentStoryBuilder<Context, Env>;
83
+ model(model: BuilderModel<Context, Env>): FluentStoryBuilder<Context, Env>;
84
+ /**
85
+ * Stop/continue hook (DurableAgent-like stop condition).
86
+ */
87
+ shouldContinue(fn: BuilderShouldContinue<Context, Env>): FluentStoryBuilder<Context, Env>;
88
+ opts(opts: StoryOptions<Context, Env>): FluentStoryBuilder<Context, Env>;
89
+ /**
90
+ * Convenience: react to an incoming event without requiring an explicit `.build()`.
91
+ *
92
+ * This still validates the config is complete (same as `.build()`), then delegates to the
93
+ * underlying `Story.react(...)`.
94
+ */
95
+ react(triggerEvent: ContextEvent, params: StoryReactParams<Env>): ReturnType<Story<Context, Env>["react"]>;
96
+ /**
97
+ * @deprecated Use `react()` instead. Kept for backwards compatibility.
98
+ */
99
+ stream(triggerEvent: ContextEvent, params: StoryReactParams<Env>): ReturnType<Story<Context, Env>["react"]>;
100
+ /**
101
+ * Registers this story definition in the global registry under `key`.
102
+ *
103
+ * This is intended to be called at module load / boot time so durable workflows
104
+ * can resume and still resolve the story by key without requiring an endpoint
105
+ * to call `.build()` again.
106
+ */
107
+ register(): void;
108
+ config(): StoryConfig<Context, Env>;
109
+ build(): StoryInstance<Context, Env>;
110
+ };
111
+ type CreateStoryEntry<Env extends StoryEnvironment> = {
112
+ context<Initializer extends AnyContextInitializer<Env>>(initializer: Initializer): FluentStoryBuilder<InferContextFromInitializer<Initializer>, Env>;
113
+ initialize<Initializer extends AnyContextInitializer<Env>>(initializer: Initializer): FluentStoryBuilder<InferContextFromInitializer<Initializer>, Env>;
114
+ };
115
+ export declare function createStory<Env extends StoryEnvironment = StoryEnvironment>(key: StoryKey): CreateStoryEntry<Env>;
116
+ export {};
@@ -0,0 +1 @@
1
+ {"version":3,"file":"story.builder.d.ts","sourceRoot":"","sources":["../src/story.builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,130 @@
1
+ import { Story, } from "./story.engine";
2
+ import { registerStory } from "./story.registry";
3
+ export function story(config) {
4
+ class FunctionalStory extends Story {
5
+ constructor() {
6
+ super(config.opts);
7
+ this.__config = config;
8
+ }
9
+ async initialize(context, env) {
10
+ return config.context(context, env);
11
+ }
12
+ async expandEvents(events, context, env) {
13
+ if (config.expandEvents)
14
+ return config.expandEvents(events, context, env);
15
+ return super.expandEvents(events, context, env);
16
+ }
17
+ async buildSystemPrompt(context, env) {
18
+ if (config.narrative)
19
+ return config.narrative(context, env);
20
+ throw new Error("Story config is missing narrative()");
21
+ }
22
+ async buildTools(context, env) {
23
+ // Back-compat: accept `tools` in old configs.
24
+ if (config.actions)
25
+ return config.actions(context, env);
26
+ if (config.tools)
27
+ return config.tools(context, env);
28
+ throw new Error("Story config is missing actions()");
29
+ }
30
+ getModel(context, env) {
31
+ if (typeof config.model === "function")
32
+ return config.model(context, env);
33
+ return config.model ?? super.getModel(context, env);
34
+ }
35
+ async shouldContinue(args) {
36
+ if (config.shouldContinue)
37
+ return config.shouldContinue(args);
38
+ return true;
39
+ }
40
+ }
41
+ const instance = new FunctionalStory();
42
+ return Object.assign(instance, { __config: config });
43
+ }
44
+ function assertConfigComplete(config) {
45
+ if (!config.context) {
46
+ throw new Error("createStory: you must define context() before building the story.");
47
+ }
48
+ if (!config.narrative) {
49
+ throw new Error("createStory: you must define narrative() before building the story.");
50
+ }
51
+ if (!config.actions && !config.tools) {
52
+ throw new Error("createStory: you must define actions() before building the story.");
53
+ }
54
+ }
55
+ export function createStory(key) {
56
+ const initializeBuilder = (initializer) => {
57
+ const typedInitializer = (ctx, env) => initializer(ctx, env);
58
+ const fluentState = {
59
+ context: typedInitializer,
60
+ };
61
+ let cached = null;
62
+ const builder = {
63
+ key,
64
+ expandEvents(fn) {
65
+ fluentState.expandEvents = fn;
66
+ return builder;
67
+ },
68
+ narrative(narrative) {
69
+ fluentState.narrative = narrative;
70
+ return builder;
71
+ },
72
+ system(system) {
73
+ // Facade alias.
74
+ fluentState.narrative = system;
75
+ return builder;
76
+ },
77
+ actions(actionsFactory) {
78
+ fluentState.actions = actionsFactory;
79
+ return builder;
80
+ },
81
+ tools(toolsFactory) {
82
+ // Back-compat alias.
83
+ fluentState.actions = toolsFactory;
84
+ return builder;
85
+ },
86
+ model(model) {
87
+ fluentState.model = model;
88
+ return builder;
89
+ },
90
+ shouldContinue(fn) {
91
+ fluentState.shouldContinue = fn;
92
+ return builder;
93
+ },
94
+ opts(options) {
95
+ fluentState.opts = options;
96
+ return builder;
97
+ },
98
+ react(triggerEvent, params) {
99
+ assertConfigComplete(fluentState);
100
+ if (!cached) {
101
+ const config = fluentState;
102
+ cached = story(config);
103
+ }
104
+ return cached.react(triggerEvent, params);
105
+ },
106
+ stream(triggerEvent, params) {
107
+ return builder.react(triggerEvent, params);
108
+ },
109
+ register() {
110
+ assertConfigComplete(fluentState);
111
+ const config = fluentState;
112
+ registerStory(key, () => story(config));
113
+ },
114
+ config() {
115
+ assertConfigComplete(fluentState);
116
+ return fluentState;
117
+ },
118
+ build() {
119
+ assertConfigComplete(fluentState);
120
+ const config = fluentState;
121
+ return story(config);
122
+ },
123
+ };
124
+ return builder;
125
+ };
126
+ return {
127
+ context: initializeBuilder,
128
+ initialize: initializeBuilder,
129
+ };
130
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"story.builder.js","sourceRoot":"","sources":["../src/story.builder.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Tool } from \"ai\"\n\nimport type { StoryEnvironment } from \"./story.config\"\nimport { Story, type StoryOptions } from \"./story.engine\"\nimport type { ContextEvent, StoredContext } from \"./story.store\"\nimport { registerStory, type StoryKey } from \"./story.registry\"\n\nexport interface StoryConfig<\n Context,\n Env extends StoryEnvironment = StoryEnvironment,\n> {\n context: (context: StoredContext<Context>, env: Env) => Promise<Context> | Context\n /**\n * Event expansion stage (first-class; executed by the engine on every loop iteration).\n *\n * Runs inside the Story loop after events are loaded from the store and before\n * they are converted into model messages.\n *\n * This is the intended place to do \"document expansion\" (turn file references\n * into text parts) using LlamaCloud/Reducto/etc.\n *\n * If you do not provide an implementation, the default is an identity transform\n * (events pass through unchanged).\n *\n * If you do I/O here, implement it as a `\"use step\"` function.\n */\n expandEvents?: (\n events: ContextEvent[],\n context: StoredContext<Context>,\n env: Env,\n ) => Promise<ContextEvent[]> | ContextEvent[]\n systemPrompt: (\n context: StoredContext<Context>,\n env: Env,\n ) => Promise<string> | string\n tools: (\n context: StoredContext<Context>,\n env: Env,\n ) => Promise<Record<string, Tool>> | Record<string, Tool>\n model?: any | ((context: StoredContext<Context>, env: Env) => any)\n opts?: StoryOptions<Context, Env>\n}\n\nexport type StoryInstance<\n Context,\n Env extends StoryEnvironment = StoryEnvironment,\n> = Story<Context, Env> & {\n readonly __config: StoryConfig<Context, Env>\n}\n\nexport function story<\n Context,\n Env extends StoryEnvironment = StoryEnvironment,\n>(config: StoryConfig<Context, Env>): StoryInstance<Context, Env> {\n class FunctionalStory extends Story<Context, Env> {\n public readonly __config = config\n\n constructor() {\n super(config.opts)\n }\n\n protected async initialize(context: StoredContext<Context>, env: Env) {\n return config.context(context, env)\n }\n\n protected async expandEvents(\n events: ContextEvent[],\n context: StoredContext<Context>,\n env: Env,\n ) {\n if (config.expandEvents) return config.expandEvents(events, context, env)\n return super.expandEvents(events, context, env)\n }\n\n protected async buildSystemPrompt(context: StoredContext<Context>, env: Env) {\n return config.systemPrompt(context, env)\n }\n\n protected async buildTools(context: StoredContext<Context>, env: Env) {\n return config.tools(context, env)\n }\n\n protected getModel(context: StoredContext<Context>, env: Env) {\n if (typeof config.model === \"function\") return config.model(context, env)\n return config.model ?? super.getModel(context, env)\n }\n }\n\n const instance = new FunctionalStory()\n return Object.assign(instance, { __config: config })\n}\n\ntype AnyContextInitializer<Env extends StoryEnvironment> = (\n context: StoredContext<any>,\n env: Env,\n) => Promise<any> | any\n\ntype InferContextFromInitializer<I extends AnyContextInitializer<any>> = Awaited<\n ReturnType<I>\n>\n\ntype BuilderSystemPrompt<Context, Env extends StoryEnvironment> = (\n context: StoredContext<Context>,\n env: Env,\n) => Promise<string> | string\n\ntype BuilderTools<Context, Env extends StoryEnvironment> = (\n context: StoredContext<Context>,\n env: Env,\n) => Promise<Record<string, Tool>> | Record<string, Tool>\n\ntype BuilderExpandEvents<Context, Env extends StoryEnvironment> = (\n events: ContextEvent[],\n context: StoredContext<Context>,\n env: Env,\n) => Promise<ContextEvent[]> | ContextEvent[]\n\ntype BuilderModel<Context, Env extends StoryEnvironment> =\n | any\n | ((context: StoredContext<Context>, env: Env) => any)\n\nexport type RegistrableStoryBuilder = {\n key: StoryKey\n register: () => void\n}\n\ntype FluentStoryBuilder<Context, Env extends StoryEnvironment> = {\n key: StoryKey\n expandEvents(fn: BuilderExpandEvents<Context, Env>): FluentStoryBuilder<Context, Env>\n systemPrompt(fn: BuilderSystemPrompt<Context, Env>): FluentStoryBuilder<Context, Env>\n tools(fn: BuilderTools<Context, Env>): FluentStoryBuilder<Context, Env>\n model(model: BuilderModel<Context, Env>): FluentStoryBuilder<Context, Env>\n opts(opts: StoryOptions<Context, Env>): FluentStoryBuilder<Context, Env>\n /**\n * Registers this story definition in the global registry under `key`.\n *\n * This is intended to be called at module load / boot time so durable workflows\n * can resume and still resolve the story by key without requiring an endpoint\n * to call `.build()` again.\n */\n register(): void\n config(): StoryConfig<Context, Env>\n build(): StoryInstance<Context, Env>\n}\n\ntype CreateStoryEntry<Env extends StoryEnvironment> = {\n context<Initializer extends AnyContextInitializer<Env>>(\n initializer: Initializer,\n ): FluentStoryBuilder<InferContextFromInitializer<Initializer>, Env>\n initialize<Initializer extends AnyContextInitializer<Env>>(\n initializer: Initializer,\n ): FluentStoryBuilder<InferContextFromInitializer<Initializer>, Env>\n}\n\nfunction assertConfigComplete<Context, Env extends StoryEnvironment>(\n config: Partial<StoryConfig<Context, Env>>,\n): asserts config is StoryConfig<Context, Env> {\n if (!config.context) {\n throw new Error(\"createStory: you must define context() before building the story.\")\n }\n if (!config.systemPrompt) {\n throw new Error(\"createStory: you must define systemPrompt() before building the story.\")\n }\n if (!config.tools) {\n throw new Error(\"createStory: you must define tools() before building the story.\")\n }\n}\n\nexport function createStory<Env extends StoryEnvironment = StoryEnvironment>(\n key: StoryKey,\n): CreateStoryEntry<Env>\n\nexport function createStory<Env extends StoryEnvironment = StoryEnvironment>(\n key: StoryKey,\n): CreateStoryEntry<Env> {\n const initializeBuilder = <Initializer extends AnyContextInitializer<Env>>(\n initializer: Initializer,\n ) => {\n type Context = InferContextFromInitializer<Initializer>\n\n const typedInitializer: StoryConfig<Context, Env>[\"context\"] = (ctx, env) =>\n initializer(ctx as StoredContext<Context>, env)\n\n const fluentState: Partial<StoryConfig<Context, Env>> = {\n context: typedInitializer,\n }\n\n const builder: FluentStoryBuilder<Context, Env> = {\n key,\n expandEvents(fn) {\n fluentState.expandEvents = fn\n return builder\n },\n systemPrompt(systemPrompt) {\n fluentState.systemPrompt = systemPrompt\n return builder\n },\n tools(toolsFactory) {\n fluentState.tools = toolsFactory\n return builder\n },\n model(model) {\n fluentState.model = model as any\n return builder\n },\n opts(options) {\n fluentState.opts = options\n return builder\n },\n register() {\n assertConfigComplete(fluentState)\n const config = fluentState as StoryConfig<Context, Env>\n registerStory(key, () => story(config) as any)\n },\n config() {\n assertConfigComplete(fluentState)\n return fluentState\n },\n build() {\n assertConfigComplete(fluentState)\n const config = fluentState as StoryConfig<Context, Env>\n return story(config)\n },\n }\n\n return builder\n }\n\n return {\n context: initializeBuilder,\n initialize: initializeBuilder,\n }\n}\n\n\n\n"]}
@@ -0,0 +1,43 @@
1
+ import type { StoryStore } from "./story.store";
2
+ /**
3
+ * ## story.config.ts
4
+ *
5
+ * Workflow-first story execution means we **cannot** keep non-serializable runtime objects
6
+ * (database clients, network handles, SDK instances) inside workflow state.
7
+ *
8
+ * Instead, we centralize runtime construction behind a global resolver:
9
+ * - The workflow passes a **serializable** `StoryEnvironment` into steps.
10
+ * - Steps call `resolveStoryRuntime(env)` to instantiate the right store (Instant/Postgres/etc).
11
+ *
12
+ * This keeps `createStory(...)` purely declarative while still allowing per-tenant/per-org routing.
13
+ */
14
+ export type StoryEnvironment = Record<string, unknown>;
15
+ export type StoryRuntime = {
16
+ store: StoryStore;
17
+ };
18
+ export type StoryRuntimeResolver<Env extends StoryEnvironment = StoryEnvironment> = (env: Env) => Promise<StoryRuntime> | StoryRuntime;
19
+ /**
20
+ * Optional global bootstrap hook for step runtimes.
21
+ *
22
+ * Motivation:
23
+ * - Workflow step runtimes may execute in a separate process/bundle.
24
+ * - If the app's `ekairos.ts` was not evaluated in that runtime yet, the story runtime
25
+ * resolver won't be configured and store steps will fail.
26
+ *
27
+ * Convention:
28
+ * - Apps should have a single `ekairos.ts` that creates `ekairosConfig` and calls `ekairosConfig.setup()`.
29
+ * - That module (or `createEkairosConfig().setup()`) can register this bootstrap function,
30
+ * so library steps can "pull" initialization on-demand before first store access.
31
+ */
32
+ type RuntimeBootstrap = () => void | Promise<void>;
33
+ export declare function configureStoryRuntimeBootstrap(bootstrap: RuntimeBootstrap): void;
34
+ /**
35
+ * Configure the story runtime resolver (global).
36
+ *
37
+ * This should be called once during initialization (module load) in your app.
38
+ * The resolver itself will be invoked inside steps, where it can safely create DB clients.
39
+ */
40
+ export declare function configureStoryRuntime<Env extends StoryEnvironment>(resolver: StoryRuntimeResolver<Env>): void;
41
+ export declare function isStoryRuntimeConfigured(): boolean;
42
+ export declare function resolveStoryRuntime(env: StoryEnvironment): Promise<StoryRuntime>;
43
+ export {};
@@ -0,0 +1 @@
1
+ {"version":3,"file":"story.config.d.ts","sourceRoot":"","sources":["../src/story.config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAE/C;;;;;;;;;;;GAWG;AAEH,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAEtD,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,UAAU,CAAA;CAClB,CAAA;AAED,MAAM,MAAM,oBAAoB,CAAC,GAAG,SAAS,gBAAgB,GAAG,gBAAgB,IAAI,CAClF,GAAG,EAAE,GAAG,KACL,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAAA;AAIzC;;;;;;;;;;;;GAYG;AACH,KAAK,gBAAgB,GAAG,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAIlD,wBAAgB,8BAA8B,CAAC,SAAS,EAAE,gBAAgB,QAEzE;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,SAAS,gBAAgB,EAChE,QAAQ,EAAE,oBAAoB,CAAC,GAAG,CAAC,QAGpC;AAED,wBAAgB,wBAAwB,YAEvC;AAED,wBAAsB,mBAAmB,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC,CAmBtF"}
@@ -0,0 +1,57 @@
1
+ let runtimeResolver = null;
2
+ function getRuntimeResolver() {
3
+ return runtimeResolver;
4
+ }
5
+ let runtimeBootstrap = null;
6
+ export function configureStoryRuntimeBootstrap(bootstrap) {
7
+ runtimeBootstrap = bootstrap;
8
+ }
9
+ /**
10
+ * Configure the story runtime resolver (global).
11
+ *
12
+ * This should be called once during initialization (module load) in your app.
13
+ * The resolver itself will be invoked inside steps, where it can safely create DB clients.
14
+ */
15
+ export function configureStoryRuntime(resolver) {
16
+ runtimeResolver = resolver;
17
+ }
18
+ export function isStoryRuntimeConfigured() {
19
+ return Boolean(runtimeResolver);
20
+ }
21
+ export async function resolveStoryRuntime(env) {
22
+ if (!getRuntimeResolver()) {
23
+ // Best-effort: allow the step runtime to self-bootstrap once.
24
+ if (runtimeBootstrap) {
25
+ await runtimeBootstrap();
26
+ }
27
+ // Convention bootstrap (Next.js / monorepo apps):
28
+ // If the app exposes `src/ekairos.ts` and uses the `@/` alias, loading that module will
29
+ // run `ekairosConfig.setup()` which configures the resolver + bootstrap hook.
30
+ //
31
+ // This is intentionally ONLY attempted when runtime is missing, and is safe as long as
32
+ // `story.config` is not part of client bundles (see `@ekairos/story/runtime`).
33
+ if (!getRuntimeResolver()) {
34
+ try {
35
+ // @ts-expect-error - optional, app-provided convention module
36
+ await import("@/ekairos");
37
+ }
38
+ catch {
39
+ // ignore: module missing / alias not configured
40
+ }
41
+ }
42
+ // If bootstrap succeeded, proceed.
43
+ const resolver = getRuntimeResolver();
44
+ if (resolver)
45
+ return await resolver(env);
46
+ throw new Error([
47
+ "Story runtime is not configured.",
48
+ "",
49
+ "Convention:",
50
+ "- Create an app-level `ekairos.ts` that exports `ekairosConfig = createEkairosConfig({ runtime })`",
51
+ "- Ensure `ekairosConfig.setup()` runs in the step runtime (module load / worker boot).",
52
+ "",
53
+ "If you already have that file, ensure it is evaluated in the step runtime before calling story store steps.",
54
+ ].join("\n"));
55
+ }
56
+ return await getRuntimeResolver()(env);
57
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"story.config.js","sourceRoot":"","sources":["../src/story.config.ts"],"names":[],"mappings":"AAyBA,IAAI,eAAe,GAAqC,IAAI,CAAA;AAiB5D,IAAI,gBAAgB,GAA4B,IAAI,CAAA;AAEpD,MAAM,UAAU,8BAA8B,CAAC,SAA2B;IACxE,gBAAgB,GAAG,SAAS,CAAA;AAC9B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CACnC,QAAmC;IAEnC,eAAe,GAAG,QAAe,CAAA;AACnC,CAAC;AAED,MAAM,UAAU,wBAAwB;IACtC,OAAO,OAAO,CAAC,eAAe,CAAC,CAAA;AACjC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,GAAqB;IAC7D,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,8DAA8D;QAC9D,IAAI,gBAAgB,EAAE,CAAC;YACrB,MAAM,gBAAgB,EAAE,CAAA;QAC1B,CAAC;QACD,MAAM,IAAI,KAAK,CACb;YACE,kCAAkC;YAClC,EAAE;YACF,aAAa;YACb,oGAAoG;YACpG,wFAAwF;YACxF,EAAE;YACF,6GAA6G;SAC9G,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAA;IACH,CAAC;IACD,OAAO,MAAM,eAAe,CAAC,GAAG,CAAC,CAAA;AACnC,CAAC","sourcesContent":["import type { StoryStore } from \"./story.store\"\r\n\r\n/**\r\n * ## story.config.ts\r\n *\r\n * Workflow-first story execution means we **cannot** keep non-serializable runtime objects\r\n * (database clients, network handles, SDK instances) inside workflow state.\r\n *\r\n * Instead, we centralize runtime construction behind a global resolver:\r\n * - The workflow passes a **serializable** `StoryEnvironment` into steps.\r\n * - Steps call `resolveStoryRuntime(env)` to instantiate the right store (Instant/Postgres/etc).\r\n *\r\n * This keeps `createStory(...)` purely declarative while still allowing per-tenant/per-org routing.\r\n */\r\n\r\nexport type StoryEnvironment = Record<string, unknown>\r\n\r\nexport type StoryRuntime = {\r\n store: StoryStore\r\n}\r\n\r\nexport type StoryRuntimeResolver<Env extends StoryEnvironment = StoryEnvironment> = (\r\n env: Env\r\n) => Promise<StoryRuntime> | StoryRuntime\r\n\r\nlet runtimeResolver: StoryRuntimeResolver<any> | null = null\r\n\r\n/**\r\n * Optional global bootstrap hook for step runtimes.\r\n *\r\n * Motivation:\r\n * - Workflow step runtimes may execute in a separate process/bundle.\r\n * - If the app's `ekairos.ts` was not evaluated in that runtime yet, the story runtime\r\n * resolver won't be configured and store steps will fail.\r\n *\r\n * Convention:\r\n * - Apps should have a single `ekairos.ts` that creates `ekairosConfig` and calls `ekairosConfig.setup()`.\r\n * - That module (or `createEkairosConfig().setup()`) can register this bootstrap function,\r\n * so library steps can \"pull\" initialization on-demand before first store access.\r\n */\r\ntype RuntimeBootstrap = () => void | Promise<void>\r\n\r\nlet runtimeBootstrap: RuntimeBootstrap | null = null\r\n\r\nexport function configureStoryRuntimeBootstrap(bootstrap: RuntimeBootstrap) {\r\n runtimeBootstrap = bootstrap\r\n}\r\n\r\n/**\r\n * Configure the story runtime resolver (global).\r\n *\r\n * This should be called once during initialization (module load) in your app.\r\n * The resolver itself will be invoked inside steps, where it can safely create DB clients.\r\n */\r\nexport function configureStoryRuntime<Env extends StoryEnvironment>(\r\n resolver: StoryRuntimeResolver<Env>,\r\n) {\r\n runtimeResolver = resolver as any\r\n}\r\n\r\nexport function isStoryRuntimeConfigured() {\r\n return Boolean(runtimeResolver)\r\n}\r\n\r\nexport async function resolveStoryRuntime(env: StoryEnvironment): Promise<StoryRuntime> {\r\n if (!runtimeResolver) {\r\n // Best-effort: allow the step runtime to self-bootstrap once.\r\n if (runtimeBootstrap) {\r\n await runtimeBootstrap()\r\n }\r\n throw new Error(\r\n [\r\n \"Story runtime is not configured.\",\r\n \"\",\r\n \"Convention:\",\r\n \"- Create an app-level `ekairos.ts` that exports `ekairosConfig = createEkairosConfig({ runtime })`\",\r\n \"- Ensure `ekairosConfig.setup()` runs in the step runtime (module load / worker boot).\",\r\n \"\",\r\n \"If you already have that file, ensure it is evaluated in the step runtime before calling story store steps.\",\r\n ].join(\"\\n\"),\r\n )\r\n }\r\n return await runtimeResolver(env)\r\n}\r\n\r\n\r\n\r\n"]}