@ekairos/events 1.22.34-beta.development.0 → 1.22.36-beta.development.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 +56 -83
- package/dist/context.d.ts +1 -1
- package/dist/context.engine.d.ts +28 -3
- package/dist/context.engine.js +100 -46
- package/dist/context.runtime.d.ts +11 -0
- package/dist/context.runtime.js +21 -0
- package/dist/context.store.d.ts +8 -0
- package/dist/index.d.ts +1 -1
- package/dist/reactors/ai-sdk.reactor.d.ts +4 -0
- package/dist/reactors/ai-sdk.reactor.js +5 -1
- package/dist/reactors/ai-sdk.step.d.ts +3 -2
- package/dist/reactors/ai-sdk.step.js +8 -7
- package/dist/reactors/types.d.ts +8 -2
- package/dist/runtime.step.js +1 -1
- package/dist/schema.js +1 -0
- package/dist/steps/do-context-stream-step.d.ts +2 -2
- package/dist/steps/do-context-stream-step.js +2 -4
- package/dist/steps/store.steps.d.ts +62 -22
- package/dist/steps/store.steps.js +76 -78
- package/dist/steps/stream.steps.d.ts +4 -3
- package/dist/steps/stream.steps.js +14 -9
- package/dist/steps/trace.steps.d.ts +2 -0
- package/dist/steps/trace.steps.js +5 -2
- package/dist/stores/instant.store.d.ts +4 -0
- package/dist/stores/instant.store.js +19 -0
- package/dist/tools-to-model-tools.d.ts +36 -2
- package/dist/tools-to-model-tools.js +39 -1
- package/package.json +7 -4
package/README.md
CHANGED
|
@@ -2,114 +2,87 @@
|
|
|
2
2
|
|
|
3
3
|
Context-first durable execution runtime for Ekairos.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## What this package does
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
- `
|
|
7
|
+
- creates durable contexts with `createContext(...)`
|
|
8
|
+
- persists executions, steps, parts, and items
|
|
9
|
+
- runs direct or durable `react(...)` loops
|
|
10
|
+
- adapts model/tool output into canonical `event_parts`
|
|
11
|
+
|
|
12
|
+
## Main APIs
|
|
13
|
+
|
|
14
|
+
- `createContext`
|
|
15
|
+
- `ContextEngine`
|
|
16
|
+
- `createAiSdkReactor`
|
|
17
|
+
- `createScriptedReactor`
|
|
18
|
+
- `runContextReactionDirect`
|
|
10
19
|
- `eventsDomain`
|
|
11
|
-
- `getContextRuntime`, `getContextEnv`, `registerContextEnv`
|
|
12
20
|
|
|
13
21
|
## Runtime model
|
|
14
22
|
|
|
23
|
+
Canonical entities:
|
|
24
|
+
|
|
15
25
|
- `event_contexts`
|
|
16
26
|
- `event_items`
|
|
17
27
|
- `event_executions`
|
|
18
28
|
- `event_steps`
|
|
19
29
|
- `event_parts`
|
|
20
|
-
- `
|
|
21
|
-
- `event_trace_runs`
|
|
22
|
-
- `event_trace_spans`
|
|
23
|
-
|
|
24
|
-
The aggregate is `context`. Executions, steps, parts, and items are scoped to a context.
|
|
25
|
-
|
|
26
|
-
## Canonical Parts
|
|
30
|
+
- `event_trace_*`
|
|
27
31
|
|
|
28
|
-
`event_parts` is the
|
|
32
|
+
`event_parts` is the source of truth for replay.
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
- `event_parts.part` is the source of truth for replay and inspection.
|
|
33
|
-
- `event_items.content.parts` on output items is maintained as a compatibility mirror and is deprecated as a replay source.
|
|
34
|
-
- Provider/model-specific values must live under `metadata`, never as first-class semantic fields.
|
|
35
|
-
|
|
36
|
-
Canonical part kinds:
|
|
37
|
-
|
|
38
|
-
- `content`
|
|
39
|
-
- `reasoning`
|
|
40
|
-
- `source`
|
|
41
|
-
- `tool-call`
|
|
42
|
-
- `tool-result`
|
|
34
|
+
## Example
|
|
43
35
|
|
|
44
|
-
|
|
36
|
+
```ts
|
|
37
|
+
import { createContext } from "@ekairos/events";
|
|
45
38
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
39
|
+
const supportContext = createContext<{ orgId: string }>("support.agent")
|
|
40
|
+
.context((stored, env) => ({
|
|
41
|
+
...stored.content,
|
|
42
|
+
orgId: env.orgId,
|
|
43
|
+
}))
|
|
44
|
+
.narrative(() => "You are a precise assistant.")
|
|
45
|
+
.actions(() => ({}))
|
|
46
|
+
.build();
|
|
47
|
+
```
|
|
51
48
|
|
|
52
|
-
|
|
49
|
+
Run directly:
|
|
53
50
|
|
|
54
51
|
```ts
|
|
55
|
-
{
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
state: "output-available",
|
|
60
|
-
content: [
|
|
61
|
-
{
|
|
62
|
-
type: "text",
|
|
63
|
-
text: "Zoomed crop of the requested region.",
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
type: "file",
|
|
67
|
-
mediaType: "image/png",
|
|
68
|
-
filename: "inspect-region.png",
|
|
69
|
-
data: "iVBORw0KGgoAAAANSUhEUgAA...",
|
|
70
|
-
},
|
|
71
|
-
],
|
|
72
|
-
metadata: {
|
|
73
|
-
provider: {
|
|
74
|
-
itemId: "fc_041cb...",
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
|
-
}
|
|
52
|
+
await supportContext.react(triggerEvent, {
|
|
53
|
+
runtime,
|
|
54
|
+
context: { key: "support:org_123" },
|
|
55
|
+
});
|
|
78
56
|
```
|
|
79
57
|
|
|
80
|
-
|
|
58
|
+
Run durably:
|
|
81
59
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
60
|
+
```ts
|
|
61
|
+
const shell = await supportContext.react(triggerEvent, {
|
|
62
|
+
runtime,
|
|
63
|
+
context: { key: "support:org_123" },
|
|
64
|
+
durable: true,
|
|
65
|
+
});
|
|
88
66
|
|
|
89
|
-
|
|
90
|
-
pnpm add @ekairos/events
|
|
67
|
+
const final = await shell.run?.returnValue;
|
|
91
68
|
```
|
|
92
69
|
|
|
93
|
-
##
|
|
70
|
+
## Tool execution model
|
|
94
71
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
type Env = { orgId: string };
|
|
72
|
+
Context tools now receive runtime-aware execution context.
|
|
73
|
+
That lets a tool do this inside `"use step"`:
|
|
99
74
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
.actions(() => ({}))
|
|
107
|
-
.reactor(createAiSdkReactor())
|
|
108
|
-
.build();
|
|
75
|
+
```ts
|
|
76
|
+
async function execute(input, ctx) {
|
|
77
|
+
"use step";
|
|
78
|
+
const domain = await ctx.runtime.use(myDomain);
|
|
79
|
+
return await domain.actions.doSomething(input);
|
|
80
|
+
}
|
|
109
81
|
```
|
|
110
82
|
|
|
111
|
-
##
|
|
83
|
+
## Tests
|
|
112
84
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
85
|
+
```bash
|
|
86
|
+
pnpm --filter @ekairos/events test
|
|
87
|
+
pnpm --filter @ekairos/events test:workflow
|
|
88
|
+
```
|
package/dist/context.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { ContextEngine, type ContextOptions, type ContextStreamOptions, type ShouldContinue, type ContextShouldContinueArgs, type ContextReactParams, type ContextReactResult, type ContextDurableWorkflowPayload, type ContextDurableWorkflowFunction, type ContextModelInit, type ContextTool, runContextReactionDirect, } from "./context.engine.js";
|
|
1
|
+
export { ContextEngine, type ContextOptions, type ContextStreamOptions, type ShouldContinue, type ContextShouldContinueArgs, type ContextReactParams, type ContextReactResult, type ContextWorkflowRun, type ContextDurableWorkflowPayload, type ContextDurableWorkflowFunction, type ContextModelInit, type ContextTool, type ContextToolExecuteContext, runContextReactionDirect, } from "./context.engine.js";
|
|
2
2
|
export { context, createContext, type ContextConfig, type ContextInstance, type RegistrableContextBuilder, } from "./context.builder.js";
|
|
3
3
|
export { createAiSdkReactor, createScriptedReactor, type CreateAiSdkReactorOptions, type CreateScriptedReactorOptions, type ScriptedReactorStep, type ContextReactor, type ContextReactorParams, type ContextReactionResult, type ContextActionRequest, type ContextReactionLLM, } from "./context.reactor.js";
|
|
4
4
|
export type { ContextSkillPackage, ContextSkillPackageFile, } from "./context.skill.js";
|
package/dist/context.engine.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { Tool, UIMessageChunk } from "ai";
|
|
1
|
+
import type { ModelMessage, Tool, UIMessageChunk } from "ai";
|
|
2
2
|
import type { ContextEnvironment } from "./context.config.js";
|
|
3
|
+
import type { ContextRuntime } from "./context.runtime.js";
|
|
3
4
|
import type { ContextExecution, ContextItem, ContextIdentifier, StoredContext } from "./context.store.js";
|
|
4
5
|
import type { ContextSkillPackage } from "./context.skill.js";
|
|
5
6
|
import { type ContextReactor } from "./context.reactor.js";
|
|
@@ -68,7 +69,11 @@ export interface ContextStreamOptions {
|
|
|
68
69
|
*/
|
|
69
70
|
export type ContextModelInit = string | (() => Promise<any>);
|
|
70
71
|
export type ContextReactParams<Env extends ContextEnvironment = ContextEnvironment> = {
|
|
71
|
-
|
|
72
|
+
runtime?: ContextRuntime<Env>;
|
|
73
|
+
/**
|
|
74
|
+
* Backward-compatible runtime selector. New callers should pass `runtime`.
|
|
75
|
+
*/
|
|
76
|
+
env?: Env;
|
|
72
77
|
/**
|
|
73
78
|
* Context selector (exclusive: `{ id }` OR `{ key }`).
|
|
74
79
|
* - `{ id }` resolves a concrete context id.
|
|
@@ -95,16 +100,36 @@ export type ContextReactResult<Context = any> = {
|
|
|
95
100
|
trigger: ContextItem;
|
|
96
101
|
reaction: ContextItem;
|
|
97
102
|
execution: ContextExecution;
|
|
103
|
+
run?: ContextWorkflowRun<Context>;
|
|
104
|
+
};
|
|
105
|
+
export type ContextWorkflowRun<Context = any> = {
|
|
106
|
+
runId: string;
|
|
107
|
+
status: Promise<"pending" | "running" | "completed" | "failed" | "cancelled">;
|
|
108
|
+
returnValue: Promise<ContextReactResult<Context>>;
|
|
98
109
|
};
|
|
99
110
|
export type ContextDurableWorkflowPayload<Env extends ContextEnvironment = ContextEnvironment> = {
|
|
100
111
|
contextKey: string;
|
|
101
|
-
|
|
112
|
+
runtime: ContextRuntime<Env>;
|
|
102
113
|
context?: ContextIdentifier | null;
|
|
103
114
|
triggerEvent: ContextItem;
|
|
104
115
|
options?: Omit<ContextStreamOptions, "writable">;
|
|
105
116
|
bootstrap: NonNullable<ContextReactParams<Env>["__bootstrap"]>;
|
|
106
117
|
};
|
|
107
118
|
export type ContextDurableWorkflowFunction<Context = any, Env extends ContextEnvironment = ContextEnvironment> = (payload: ContextDurableWorkflowPayload<Env>) => Promise<ContextReactResult<Context>>;
|
|
119
|
+
export type ContextToolExecuteContext<Context = any, Env extends ContextEnvironment = ContextEnvironment> = {
|
|
120
|
+
runtime: ContextRuntime<Env>;
|
|
121
|
+
env: Env;
|
|
122
|
+
context: StoredContext<Context>;
|
|
123
|
+
contextIdentifier: ContextIdentifier;
|
|
124
|
+
toolCallId: string;
|
|
125
|
+
messages: ModelMessage[];
|
|
126
|
+
eventId: string;
|
|
127
|
+
executionId: string;
|
|
128
|
+
triggerEventId: string;
|
|
129
|
+
contextId: string;
|
|
130
|
+
stepId: string;
|
|
131
|
+
iteration: number;
|
|
132
|
+
};
|
|
108
133
|
export { toolApprovalHookToken, toolApprovalWebhookToken, getClientResumeHookUrl };
|
|
109
134
|
/**
|
|
110
135
|
* Context-level tool type.
|
package/dist/context.engine.js
CHANGED
|
@@ -1,16 +1,40 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getContextRuntimeServices } from "./context.runtime.js";
|
|
2
2
|
import { OUTPUT_ITEM_TYPE, WEB_CHANNEL } from "./context.events.js";
|
|
3
3
|
import { applyToolExecutionResultToParts } from "./context.toolcalls.js";
|
|
4
4
|
import { isContextPartEnvelope, normalizePartsForPersistence, } from "./context.parts.js";
|
|
5
|
-
import {
|
|
5
|
+
import { actionsToActionSpecs } from "./tools-to-model-tools.js";
|
|
6
6
|
import { createAiSdkReactor, } from "./context.reactor.js";
|
|
7
7
|
import { abortPersistedContextStepStream, closePersistedContextStepStream, createPersistedContextStepStream, closeContextStream, } from "./steps/stream.steps.js";
|
|
8
|
-
import { completeExecution, createContextStep, initializeContext, saveTriggerAndCreateExecution, saveContextPartsStep, updateContextContent, updateContextStatus, updateItem, updateContextStep, } from "./steps/store.steps.js";
|
|
8
|
+
import { completeExecution, createContextStep, initializeContext, saveTriggerAndCreateExecution, saveContextPartsStep, updateContextContent, updateContextReactor, updateContextStatus, updateItem, updateContextStep, } from "./steps/store.steps.js";
|
|
9
9
|
import { getClientResumeHookUrl, toolApprovalHookToken, toolApprovalWebhookToken, } from "./context.hooks.js";
|
|
10
10
|
import { getContextDurableWorkflow } from "./context.durable.js";
|
|
11
11
|
export async function runContextReactionDirect(context, triggerEvent, params) {
|
|
12
12
|
return await ContextEngine.runDirect(context, triggerEvent, params);
|
|
13
13
|
}
|
|
14
|
+
async function legacyRuntimeFromEnv(env) {
|
|
15
|
+
const { getContextRuntime } = await import("./runtime.step.js");
|
|
16
|
+
const legacy = (await getContextRuntime(env));
|
|
17
|
+
return {
|
|
18
|
+
env,
|
|
19
|
+
db: async () => legacy.db,
|
|
20
|
+
resolve: async () => ({
|
|
21
|
+
db: legacy.db,
|
|
22
|
+
meta: () => ({
|
|
23
|
+
domain: legacy.domain,
|
|
24
|
+
}),
|
|
25
|
+
}),
|
|
26
|
+
meta: () => ({
|
|
27
|
+
domain: legacy.domain,
|
|
28
|
+
}),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
async function resolveReactRuntime(params) {
|
|
32
|
+
if (params.runtime)
|
|
33
|
+
return params.runtime;
|
|
34
|
+
if (params.env)
|
|
35
|
+
return await legacyRuntimeFromEnv(params.env);
|
|
36
|
+
throw new Error("ContextEngine.react requires either runtime or env.");
|
|
37
|
+
}
|
|
14
38
|
export { toolApprovalHookToken, toolApprovalWebhookToken, getClientResumeHookUrl };
|
|
15
39
|
function nowIso() {
|
|
16
40
|
return new Date().toISOString();
|
|
@@ -89,9 +113,8 @@ async function readActiveWorkflowRunId() {
|
|
|
89
113
|
return null;
|
|
90
114
|
}
|
|
91
115
|
}
|
|
92
|
-
async function createRuntimeOps(
|
|
93
|
-
const
|
|
94
|
-
const runtime = await getContextRuntime(env);
|
|
116
|
+
async function createRuntimeOps(runtimeHandle, benchmark) {
|
|
117
|
+
const runtime = await getContextRuntimeServices(runtimeHandle);
|
|
95
118
|
const { db } = runtime;
|
|
96
119
|
const { InstantStore } = await import("./stores/instant.store.js");
|
|
97
120
|
const requireContextId = (contextIdentifier) => {
|
|
@@ -145,6 +168,7 @@ async function createRuntimeOps(env, benchmark) {
|
|
|
145
168
|
return { context, isNew: true };
|
|
146
169
|
},
|
|
147
170
|
updateContextContent: async (contextIdentifier, content) => await store.updateContextContent(contextIdentifier, content),
|
|
171
|
+
updateContextReactor: async (contextIdentifier, reactor) => await store.updateContextReactor(contextIdentifier, reactor),
|
|
148
172
|
updateContextStatus: async (contextIdentifier, status) => await instrumentedDb.transact([
|
|
149
173
|
instrumentedDb.tx.event_contexts[requireContextId(contextIdentifier)].update({
|
|
150
174
|
status,
|
|
@@ -255,27 +279,28 @@ async function createRuntimeOps(env, benchmark) {
|
|
|
255
279
|
},
|
|
256
280
|
};
|
|
257
281
|
}
|
|
258
|
-
async function createWorkflowOps(
|
|
282
|
+
async function createWorkflowOps(runtime) {
|
|
283
|
+
const env = runtime.env;
|
|
259
284
|
return {
|
|
260
|
-
initializeContext: async (contextIdentifier, opts) => await initializeContext(
|
|
261
|
-
updateContextContent: async (contextIdentifier, content) => await updateContextContent(
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
285
|
+
initializeContext: async (contextIdentifier, opts) => await initializeContext({ runtime, contextIdentifier, opts }),
|
|
286
|
+
updateContextContent: async (contextIdentifier, content) => await updateContextContent({ runtime, contextIdentifier, content }),
|
|
287
|
+
updateContextReactor: async (contextIdentifier, reactor) => await updateContextReactor({ runtime, contextIdentifier, reactor }),
|
|
288
|
+
updateContextStatus: async (contextIdentifier, status) => await updateContextStatus({ runtime, contextIdentifier, status }),
|
|
289
|
+
saveTriggerAndCreateExecution: async ({ contextIdentifier, triggerEvent }) => await saveTriggerAndCreateExecution({ runtime, contextIdentifier, triggerEvent }),
|
|
290
|
+
createContextStep: async ({ executionId, iteration }) => await createContextStep({ runtime, executionId, iteration }),
|
|
291
|
+
updateContextStep: async (params) => await updateContextStep({ runtime, ...params }),
|
|
292
|
+
saveContextPartsStep: async (params) => await saveContextPartsStep({ runtime, ...params }),
|
|
293
|
+
updateItem: async (itemId, item, opts) => await updateItem({ runtime, eventId: itemId, event: item, opts }),
|
|
294
|
+
completeExecution: async (contextIdentifier, executionId, status) => await completeExecution({ runtime, contextIdentifier, executionId, status }),
|
|
269
295
|
};
|
|
270
296
|
}
|
|
271
|
-
async function getContextEngineOps(
|
|
297
|
+
async function getContextEngineOps(runtime, benchmark) {
|
|
298
|
+
const env = runtime.env;
|
|
272
299
|
const workflowRunId = await readActiveWorkflowRunId();
|
|
273
300
|
if (workflowRunId) {
|
|
274
|
-
|
|
275
|
-
return await createWorkflowOps(env);
|
|
301
|
+
return await createWorkflowOps(runtime);
|
|
276
302
|
}
|
|
277
|
-
|
|
278
|
-
return await createRuntimeOps(env, benchmark);
|
|
303
|
+
return await createRuntimeOps(runtime, benchmark);
|
|
279
304
|
}
|
|
280
305
|
export class ContextEngine {
|
|
281
306
|
constructor(opts = {}, reactor) {
|
|
@@ -329,13 +354,15 @@ export class ContextEngine {
|
|
|
329
354
|
return await ContextEngine.runDirect(this, triggerEvent, params);
|
|
330
355
|
}
|
|
331
356
|
static async prepareExecutionShell(story, triggerEvent, params) {
|
|
332
|
-
const
|
|
357
|
+
const runtimeHandle = await resolveReactRuntime(params);
|
|
358
|
+
const env = runtimeHandle.env;
|
|
359
|
+
const ops = await measureBenchmark(params.__benchmark, "react.resolveOpsMs", async () => await getContextEngineOps(runtimeHandle, params.__benchmark));
|
|
333
360
|
const silent = params.options?.silent ?? false;
|
|
334
361
|
const ctxResult = await measureBenchmark(params.__benchmark, "react.initializeContextMs", async () => await ops.initializeContext(params.context ?? null, { silent }));
|
|
335
362
|
let currentContext = ctxResult.context;
|
|
336
363
|
const contextSelector = { id: String(currentContext.id) };
|
|
337
364
|
if (ctxResult.isNew) {
|
|
338
|
-
await story.opts.onContextCreated?.({ env
|
|
365
|
+
await story.opts.onContextCreated?.({ env, context: currentContext });
|
|
339
366
|
}
|
|
340
367
|
if (currentContext.status === "closed") {
|
|
341
368
|
await measureBenchmark(params.__benchmark, "react.reopenClosedContextMs", async () => await ops.updateContextStatus(contextSelector, "open_idle"));
|
|
@@ -355,6 +382,8 @@ export class ContextEngine {
|
|
|
355
382
|
};
|
|
356
383
|
}
|
|
357
384
|
static async startDurable(story, triggerEvent, params) {
|
|
385
|
+
const runtimeHandle = await resolveReactRuntime(params);
|
|
386
|
+
const env = runtimeHandle.env;
|
|
358
387
|
if (params.options?.writable) {
|
|
359
388
|
throw new Error("ContextEngine.react: durable runs manage their own workflow stream");
|
|
360
389
|
}
|
|
@@ -367,14 +396,15 @@ export class ContextEngine {
|
|
|
367
396
|
throw new Error("ContextEngine.react: durable workflow is not configured. Call configureContextDurableWorkflow(...) in runtime bootstrap.");
|
|
368
397
|
}
|
|
369
398
|
const shell = await ContextEngine.prepareExecutionShell(story, triggerEvent, params);
|
|
399
|
+
let run;
|
|
370
400
|
try {
|
|
371
401
|
const [{ start }] = await Promise.all([
|
|
372
402
|
import("workflow/api"),
|
|
373
403
|
]);
|
|
374
|
-
const
|
|
404
|
+
const startedRun = await start(workflow, [
|
|
375
405
|
{
|
|
376
406
|
contextKey,
|
|
377
|
-
|
|
407
|
+
runtime: runtimeHandle,
|
|
378
408
|
context: params.context ?? null,
|
|
379
409
|
triggerEvent,
|
|
380
410
|
options: {
|
|
@@ -392,16 +422,21 @@ export class ContextEngine {
|
|
|
392
422
|
},
|
|
393
423
|
},
|
|
394
424
|
]);
|
|
395
|
-
|
|
425
|
+
run = {
|
|
426
|
+
runId: String(startedRun.runId),
|
|
427
|
+
status: startedRun.status,
|
|
428
|
+
returnValue: startedRun.returnValue,
|
|
429
|
+
};
|
|
430
|
+
const runtime = await createRuntimeOps(runtimeHandle);
|
|
396
431
|
await runtime.db.transact([
|
|
397
432
|
runtime.db.tx.event_executions[shell.execution.id].update({
|
|
398
|
-
workflowRunId:
|
|
433
|
+
workflowRunId: startedRun.runId,
|
|
399
434
|
updatedAt: new Date(),
|
|
400
435
|
}),
|
|
401
436
|
]);
|
|
402
437
|
}
|
|
403
438
|
catch (error) {
|
|
404
|
-
const ops = await getContextEngineOps(
|
|
439
|
+
const ops = await getContextEngineOps(runtimeHandle, params.__benchmark);
|
|
405
440
|
await ops.completeExecution(shell.contextSelector, shell.execution.id, "failed").catch(() => null);
|
|
406
441
|
throw error;
|
|
407
442
|
}
|
|
@@ -410,10 +445,13 @@ export class ContextEngine {
|
|
|
410
445
|
trigger: shell.trigger,
|
|
411
446
|
reaction: shell.reaction,
|
|
412
447
|
execution: shell.execution,
|
|
448
|
+
run,
|
|
413
449
|
};
|
|
414
450
|
}
|
|
415
451
|
static async runDirect(story, triggerEvent, params) {
|
|
416
|
-
const
|
|
452
|
+
const runtimeHandle = await resolveReactRuntime(params);
|
|
453
|
+
const env = runtimeHandle.env;
|
|
454
|
+
const ops = await measureBenchmark(params.__benchmark, "react.resolveOpsMs", async () => await getContextEngineOps(runtimeHandle, params.__benchmark));
|
|
417
455
|
const maxIterations = params.options?.maxIterations ?? 20;
|
|
418
456
|
const maxModelSteps = params.options?.maxModelSteps ?? 1;
|
|
419
457
|
const preventClose = params.options?.preventClose ?? false;
|
|
@@ -488,7 +526,7 @@ export class ContextEngine {
|
|
|
488
526
|
}));
|
|
489
527
|
currentStepId = stepCreate.stepId;
|
|
490
528
|
currentStepStream = await createPersistedContextStepStream({
|
|
491
|
-
|
|
529
|
+
runtime: runtimeHandle,
|
|
492
530
|
executionId,
|
|
493
531
|
stepId: stepCreate.stepId,
|
|
494
532
|
});
|
|
@@ -507,7 +545,7 @@ export class ContextEngine {
|
|
|
507
545
|
],
|
|
508
546
|
});
|
|
509
547
|
// Hook: Context DSL `context()` (implemented by subclasses via `initialize()`)
|
|
510
|
-
const nextContent = await measureBenchmark(params.__benchmark, `${stagePrefix}.contextMs`, async () => await story.initialize(updatedContext,
|
|
548
|
+
const nextContent = await measureBenchmark(params.__benchmark, `${stagePrefix}.contextMs`, async () => await story.initialize(updatedContext, env));
|
|
511
549
|
updatedContext = await measureBenchmark(params.__benchmark, `${stagePrefix}.persistContextMs`, async () => await ops.updateContextContent(activeContextSelector, nextContent));
|
|
512
550
|
await emitContextEvents({
|
|
513
551
|
silent,
|
|
@@ -520,15 +558,15 @@ export class ContextEngine {
|
|
|
520
558
|
},
|
|
521
559
|
],
|
|
522
560
|
});
|
|
523
|
-
await story.opts.onContextUpdated?.({ env
|
|
561
|
+
await story.opts.onContextUpdated?.({ env, context: updatedContext });
|
|
524
562
|
// Hook: Context DSL `narrative()` (implemented by subclasses via `buildSystemPrompt()`)
|
|
525
|
-
const systemPrompt = await measureBenchmark(params.__benchmark, `${stagePrefix}.narrativeMs`, async () => await story.buildSystemPrompt(updatedContext,
|
|
563
|
+
const systemPrompt = await measureBenchmark(params.__benchmark, `${stagePrefix}.narrativeMs`, async () => await story.buildSystemPrompt(updatedContext, env));
|
|
526
564
|
// Hook: Context DSL `actions()` (implemented by subclasses via `buildTools()`)
|
|
527
|
-
const toolsAll = await measureBenchmark(params.__benchmark, `${stagePrefix}.actionsMs`, async () => await story.buildTools(updatedContext,
|
|
528
|
-
const skillsAll = await measureBenchmark(params.__benchmark, `${stagePrefix}.skillsMs`, async () => await story.buildSkills(updatedContext,
|
|
565
|
+
const toolsAll = await measureBenchmark(params.__benchmark, `${stagePrefix}.actionsMs`, async () => await story.buildTools(updatedContext, env));
|
|
566
|
+
const skillsAll = await measureBenchmark(params.__benchmark, `${stagePrefix}.skillsMs`, async () => await story.buildSkills(updatedContext, env));
|
|
529
567
|
// IMPORTANT: step args must be serializable.
|
|
530
568
|
// Match DurableAgent behavior: convert tool input schemas to plain JSON Schema in workflow context.
|
|
531
|
-
const
|
|
569
|
+
const actionSpecs = actionsToActionSpecs(toolsAll);
|
|
532
570
|
// Execute model reaction for this iteration using the stable reaction event id.
|
|
533
571
|
//
|
|
534
572
|
// IMPORTANT:
|
|
@@ -536,7 +574,7 @@ export class ContextEngine {
|
|
|
536
574
|
// If we stream with a per-step id, the UI will render an optimistic assistant message
|
|
537
575
|
// (step id) and then a second persisted assistant message (reaction id) with the same
|
|
538
576
|
// content once InstantDB updates.
|
|
539
|
-
const reactor = story.getReactor(updatedContext,
|
|
577
|
+
const reactor = story.getReactor(updatedContext, env);
|
|
540
578
|
const reactionPartsBeforeStep = Array.isArray(reactionEvent.content?.parts)
|
|
541
579
|
? [...reactionEvent.content.parts]
|
|
542
580
|
: [];
|
|
@@ -563,15 +601,16 @@ export class ContextEngine {
|
|
|
563
601
|
status: "pending",
|
|
564
602
|
}, { executionId, contextId: String(currentContext.id) });
|
|
565
603
|
};
|
|
566
|
-
const
|
|
567
|
-
|
|
604
|
+
const reactionResult = await measureBenchmark(params.__benchmark, `${stagePrefix}.reactorMs`, async () => await reactor({
|
|
605
|
+
runtime: runtimeHandle,
|
|
606
|
+
env,
|
|
568
607
|
context: updatedContext,
|
|
569
608
|
contextIdentifier: activeContextSelector,
|
|
570
609
|
triggerEvent,
|
|
571
|
-
model: story.getModel(updatedContext,
|
|
610
|
+
model: story.getModel(updatedContext, env),
|
|
572
611
|
systemPrompt,
|
|
573
612
|
actions: toolsAll,
|
|
574
|
-
|
|
613
|
+
actionSpecs,
|
|
575
614
|
skills: skillsAll,
|
|
576
615
|
eventId: reactionEventId,
|
|
577
616
|
executionId,
|
|
@@ -586,6 +625,7 @@ export class ContextEngine {
|
|
|
586
625
|
writable,
|
|
587
626
|
persistReactionParts,
|
|
588
627
|
}));
|
|
628
|
+
const { assistantEvent, actionRequests, messagesForModel } = reactionResult;
|
|
589
629
|
const reviewRequests = actionRequests.length > 0
|
|
590
630
|
? actionRequests.flatMap((actionRequest) => {
|
|
591
631
|
const toolDef = toolsAll[actionRequest.actionName];
|
|
@@ -649,9 +689,18 @@ export class ContextEngine {
|
|
|
649
689
|
status: "pending",
|
|
650
690
|
};
|
|
651
691
|
reactionEvent = await measureBenchmark(params.__benchmark, `${stagePrefix}.persistAssistantReactionMs`, async () => await ops.updateItem(reactionEvent.id, nextReactionEvent, { executionId, contextId: String(currentContext.id) }));
|
|
692
|
+
if (reactionResult.reactor?.kind) {
|
|
693
|
+
updatedContext = await measureBenchmark(params.__benchmark, `${stagePrefix}.persistReactorStateMs`, async () => await ops.updateContextReactor(activeContextSelector, {
|
|
694
|
+
kind: reactionResult.reactor.kind,
|
|
695
|
+
state: {
|
|
696
|
+
...(reactionResult.reactor.state ?? {}),
|
|
697
|
+
updatedAt: nowIso(),
|
|
698
|
+
},
|
|
699
|
+
}));
|
|
700
|
+
}
|
|
652
701
|
if (currentStepStream) {
|
|
653
702
|
await closePersistedContextStepStream({
|
|
654
|
-
|
|
703
|
+
runtime: runtimeHandle,
|
|
655
704
|
session: currentStepStream,
|
|
656
705
|
});
|
|
657
706
|
currentStepStream = null;
|
|
@@ -807,9 +856,8 @@ export class ContextEngine {
|
|
|
807
856
|
const { createHook, createWebhook } = await import("workflow");
|
|
808
857
|
const toolCallId = String(actionRequest.actionRef);
|
|
809
858
|
const hookToken = toolApprovalHookToken({ executionId, toolCallId });
|
|
810
|
-
const webhookToken = toolApprovalWebhookToken({ executionId, toolCallId });
|
|
811
859
|
const hook = createHook({ token: hookToken });
|
|
812
|
-
const webhook = createWebhook(
|
|
860
|
+
const webhook = createWebhook();
|
|
813
861
|
const approvalOrRequest = await Promise.race([
|
|
814
862
|
hook.then((approval) => ({ source: "hook", approval })),
|
|
815
863
|
webhook.then((request) => ({ source: "webhook", request })),
|
|
@@ -832,12 +880,18 @@ export class ContextEngine {
|
|
|
832
880
|
}
|
|
833
881
|
}
|
|
834
882
|
const output = await toolDef.execute(actionInput, {
|
|
883
|
+
runtime: runtimeHandle,
|
|
884
|
+
env,
|
|
885
|
+
context: updatedContext,
|
|
886
|
+
contextIdentifier: activeContextSelector,
|
|
835
887
|
toolCallId: actionRequest.actionRef,
|
|
836
888
|
messages: messagesForModel,
|
|
837
889
|
eventId: reactionEventId,
|
|
838
890
|
executionId,
|
|
839
891
|
triggerEventId,
|
|
840
892
|
contextId: currentContext.id,
|
|
893
|
+
stepId: String(stepCreate.stepId),
|
|
894
|
+
iteration: iter,
|
|
841
895
|
});
|
|
842
896
|
return { actionRequest, success: true, output };
|
|
843
897
|
}
|
|
@@ -894,7 +948,7 @@ export class ContextEngine {
|
|
|
894
948
|
// IMPORTANT: we call this after tool results have been merged into the persisted `reactionEvent`,
|
|
895
949
|
// so stories can inspect `reactionEvent.content.parts` deterministically.
|
|
896
950
|
const continueLoop = await measureBenchmark(params.__benchmark, `${stagePrefix}.shouldContinueMs`, async () => await story.shouldContinue({
|
|
897
|
-
env
|
|
951
|
+
env,
|
|
898
952
|
context: updatedContext,
|
|
899
953
|
reactionEvent,
|
|
900
954
|
assistantEvent: assistantEventEffective,
|
|
@@ -1033,7 +1087,7 @@ export class ContextEngine {
|
|
|
1033
1087
|
if (currentStepStream) {
|
|
1034
1088
|
try {
|
|
1035
1089
|
await abortPersistedContextStepStream({
|
|
1036
|
-
|
|
1090
|
+
runtime: runtimeHandle,
|
|
1037
1091
|
session: currentStepStream,
|
|
1038
1092
|
reason: error instanceof Error ? error.message : String(error),
|
|
1039
1093
|
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ConcreteDomain } from "@ekairos/domain";
|
|
2
|
+
import type { ExplicitRuntimeLike } from "@ekairos/domain/runtime";
|
|
3
|
+
import type { ContextEnvironment } from "./context.config.js";
|
|
4
|
+
import type { ContextStore } from "./context.store.js";
|
|
5
|
+
export type ContextRuntime<Env extends ContextEnvironment = ContextEnvironment> = ExplicitRuntimeLike<Env, any, any>;
|
|
6
|
+
export type ContextRuntimeServices = {
|
|
7
|
+
db: any;
|
|
8
|
+
store: ContextStore;
|
|
9
|
+
domain?: ConcreteDomain<any, any>;
|
|
10
|
+
};
|
|
11
|
+
export declare function getContextRuntimeServices(runtime: ContextRuntime<any>): Promise<ContextRuntimeServices>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const storeByDb = new WeakMap();
|
|
2
|
+
export async function getContextRuntimeServices(runtime) {
|
|
3
|
+
const db = await runtime.db();
|
|
4
|
+
if (!db) {
|
|
5
|
+
throw new Error("Context runtime did not provide a database instance.");
|
|
6
|
+
}
|
|
7
|
+
let store = typeof db === "object" && db !== null ? storeByDb.get(db) : undefined;
|
|
8
|
+
if (!store) {
|
|
9
|
+
const { InstantStore } = await import("./stores/instant.store.js");
|
|
10
|
+
store = new InstantStore(db);
|
|
11
|
+
if (typeof db === "object" && db !== null) {
|
|
12
|
+
storeByDb.set(db, store);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const resolved = await runtime.resolve();
|
|
16
|
+
return {
|
|
17
|
+
db,
|
|
18
|
+
store,
|
|
19
|
+
domain: typeof resolved === "object" && resolved !== null ? resolved.meta?.()?.domain : undefined,
|
|
20
|
+
};
|
|
21
|
+
}
|
package/dist/context.store.d.ts
CHANGED
|
@@ -16,6 +16,10 @@ export type StoredContext<Context> = {
|
|
|
16
16
|
createdAt: Date;
|
|
17
17
|
updatedAt?: Date;
|
|
18
18
|
content: Context | null;
|
|
19
|
+
reactor?: {
|
|
20
|
+
kind: string;
|
|
21
|
+
state?: Record<string, unknown> | null;
|
|
22
|
+
} | null;
|
|
19
23
|
};
|
|
20
24
|
export type ContextItem = {
|
|
21
25
|
id: string;
|
|
@@ -57,6 +61,10 @@ export interface ContextStore {
|
|
|
57
61
|
getOrCreateContext<C>(contextIdentifier: ContextIdentifier | null): Promise<StoredContext<C>>;
|
|
58
62
|
getContext<C>(contextIdentifier: ContextIdentifier): Promise<StoredContext<C> | null>;
|
|
59
63
|
updateContextContent<C>(contextIdentifier: ContextIdentifier, content: C): Promise<StoredContext<C>>;
|
|
64
|
+
updateContextReactor<C>(contextIdentifier: ContextIdentifier, reactor: {
|
|
65
|
+
kind: string;
|
|
66
|
+
state?: Record<string, unknown> | null;
|
|
67
|
+
}): Promise<StoredContext<C>>;
|
|
60
68
|
updateContextStatus(contextIdentifier: ContextIdentifier, status: ContextStatus): Promise<void>;
|
|
61
69
|
saveItem(contextIdentifier: ContextIdentifier, item: ContextItem): Promise<ContextItem>;
|
|
62
70
|
updateItem(itemId: string, item: ContextItem): Promise<ContextItem>;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { context, createContext, createAiSdkReactor, createScriptedReactor, type CreateAiSdkReactorOptions, type CreateScriptedReactorOptions, type ScriptedReactorStep, type ContextConfig, type ContextInstance, type ContextOptions, type ContextStreamOptions, type ContextReactor, type ContextReactorParams, type ContextReactionResult, type ContextActionRequest, type ContextReactionLLM, ContextEngine, type RegistrableContextBuilder, type ContextReactParams, type ContextReactResult, type ContextDurableWorkflowPayload, type ContextDurableWorkflowFunction, type ContextModelInit, type ContextTool, runContextReactionDirect, } from "./context.js";
|
|
1
|
+
export { context, createContext, createAiSdkReactor, createScriptedReactor, type CreateAiSdkReactorOptions, type CreateScriptedReactorOptions, type ScriptedReactorStep, type ContextConfig, type ContextInstance, type ContextOptions, type ContextStreamOptions, type ContextReactor, type ContextReactorParams, type ContextReactionResult, type ContextActionRequest, type ContextReactionLLM, ContextEngine, type RegistrableContextBuilder, type ContextReactParams, type ContextReactResult, type ContextWorkflowRun, type ContextDurableWorkflowPayload, type ContextDurableWorkflowFunction, type ContextModelInit, type ContextTool, type ContextToolExecuteContext, runContextReactionDirect, } from "./context.js";
|
|
2
2
|
export type { ContextStore, ContextIdentifier, StoredContext, ContextItem, ContextExecution, } from "./context.store.js";
|
|
3
3
|
export type { WireDate, ContextMirrorContext, ContextMirrorExecution, ContextMirrorWrite, ContextMirrorRequest, } from "./mirror.js";
|
|
4
4
|
export { registerContext, getContext, getContextFactory, hasContext, listContexts, type ContextKey, } from "./context.registry.js";
|