@ekairos/events 1.22.33-beta.development.0 → 1.22.35-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 +24 -3
- package/dist/context.engine.js +73 -46
- package/dist/context.events.js +2 -13
- 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,7 @@ 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>;
|
|
72
73
|
/**
|
|
73
74
|
* Context selector (exclusive: `{ id }` OR `{ key }`).
|
|
74
75
|
* - `{ id }` resolves a concrete context id.
|
|
@@ -95,16 +96,36 @@ export type ContextReactResult<Context = any> = {
|
|
|
95
96
|
trigger: ContextItem;
|
|
96
97
|
reaction: ContextItem;
|
|
97
98
|
execution: ContextExecution;
|
|
99
|
+
run?: ContextWorkflowRun<Context>;
|
|
100
|
+
};
|
|
101
|
+
export type ContextWorkflowRun<Context = any> = {
|
|
102
|
+
runId: string;
|
|
103
|
+
status: Promise<"pending" | "running" | "completed" | "failed" | "cancelled">;
|
|
104
|
+
returnValue: Promise<ContextReactResult<Context>>;
|
|
98
105
|
};
|
|
99
106
|
export type ContextDurableWorkflowPayload<Env extends ContextEnvironment = ContextEnvironment> = {
|
|
100
107
|
contextKey: string;
|
|
101
|
-
|
|
108
|
+
runtime: ContextRuntime<Env>;
|
|
102
109
|
context?: ContextIdentifier | null;
|
|
103
110
|
triggerEvent: ContextItem;
|
|
104
111
|
options?: Omit<ContextStreamOptions, "writable">;
|
|
105
112
|
bootstrap: NonNullable<ContextReactParams<Env>["__bootstrap"]>;
|
|
106
113
|
};
|
|
107
114
|
export type ContextDurableWorkflowFunction<Context = any, Env extends ContextEnvironment = ContextEnvironment> = (payload: ContextDurableWorkflowPayload<Env>) => Promise<ContextReactResult<Context>>;
|
|
115
|
+
export type ContextToolExecuteContext<Context = any, Env extends ContextEnvironment = ContextEnvironment> = {
|
|
116
|
+
runtime: ContextRuntime<Env>;
|
|
117
|
+
env: Env;
|
|
118
|
+
context: StoredContext<Context>;
|
|
119
|
+
contextIdentifier: ContextIdentifier;
|
|
120
|
+
toolCallId: string;
|
|
121
|
+
messages: ModelMessage[];
|
|
122
|
+
eventId: string;
|
|
123
|
+
executionId: string;
|
|
124
|
+
triggerEventId: string;
|
|
125
|
+
contextId: string;
|
|
126
|
+
stepId: string;
|
|
127
|
+
iteration: number;
|
|
128
|
+
};
|
|
108
129
|
export { toolApprovalHookToken, toolApprovalWebhookToken, getClientResumeHookUrl };
|
|
109
130
|
/**
|
|
110
131
|
* Context-level tool type.
|
package/dist/context.engine.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
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) {
|
|
@@ -89,9 +89,8 @@ async function readActiveWorkflowRunId() {
|
|
|
89
89
|
return null;
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
|
-
async function createRuntimeOps(
|
|
93
|
-
const
|
|
94
|
-
const runtime = await getContextRuntime(env);
|
|
92
|
+
async function createRuntimeOps(runtimeHandle, benchmark) {
|
|
93
|
+
const runtime = await getContextRuntimeServices(runtimeHandle);
|
|
95
94
|
const { db } = runtime;
|
|
96
95
|
const { InstantStore } = await import("./stores/instant.store.js");
|
|
97
96
|
const requireContextId = (contextIdentifier) => {
|
|
@@ -145,6 +144,7 @@ async function createRuntimeOps(env, benchmark) {
|
|
|
145
144
|
return { context, isNew: true };
|
|
146
145
|
},
|
|
147
146
|
updateContextContent: async (contextIdentifier, content) => await store.updateContextContent(contextIdentifier, content),
|
|
147
|
+
updateContextReactor: async (contextIdentifier, reactor) => await store.updateContextReactor(contextIdentifier, reactor),
|
|
148
148
|
updateContextStatus: async (contextIdentifier, status) => await instrumentedDb.transact([
|
|
149
149
|
instrumentedDb.tx.event_contexts[requireContextId(contextIdentifier)].update({
|
|
150
150
|
status,
|
|
@@ -255,27 +255,28 @@ async function createRuntimeOps(env, benchmark) {
|
|
|
255
255
|
},
|
|
256
256
|
};
|
|
257
257
|
}
|
|
258
|
-
async function createWorkflowOps(
|
|
258
|
+
async function createWorkflowOps(runtime) {
|
|
259
|
+
const env = runtime.env;
|
|
259
260
|
return {
|
|
260
|
-
initializeContext: async (contextIdentifier, opts) => await initializeContext(
|
|
261
|
-
updateContextContent: async (contextIdentifier, content) => await updateContextContent(
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
261
|
+
initializeContext: async (contextIdentifier, opts) => await initializeContext({ runtime, contextIdentifier, opts }),
|
|
262
|
+
updateContextContent: async (contextIdentifier, content) => await updateContextContent({ runtime, contextIdentifier, content }),
|
|
263
|
+
updateContextReactor: async (contextIdentifier, reactor) => await updateContextReactor({ runtime, contextIdentifier, reactor }),
|
|
264
|
+
updateContextStatus: async (contextIdentifier, status) => await updateContextStatus({ runtime, contextIdentifier, status }),
|
|
265
|
+
saveTriggerAndCreateExecution: async ({ contextIdentifier, triggerEvent }) => await saveTriggerAndCreateExecution({ runtime, contextIdentifier, triggerEvent }),
|
|
266
|
+
createContextStep: async ({ executionId, iteration }) => await createContextStep({ runtime, executionId, iteration }),
|
|
267
|
+
updateContextStep: async (params) => await updateContextStep({ runtime, ...params }),
|
|
268
|
+
saveContextPartsStep: async (params) => await saveContextPartsStep({ runtime, ...params }),
|
|
269
|
+
updateItem: async (itemId, item, opts) => await updateItem({ runtime, eventId: itemId, event: item, opts }),
|
|
270
|
+
completeExecution: async (contextIdentifier, executionId, status) => await completeExecution({ runtime, contextIdentifier, executionId, status }),
|
|
269
271
|
};
|
|
270
272
|
}
|
|
271
|
-
async function getContextEngineOps(
|
|
273
|
+
async function getContextEngineOps(runtime, benchmark) {
|
|
274
|
+
const env = runtime.env;
|
|
272
275
|
const workflowRunId = await readActiveWorkflowRunId();
|
|
273
276
|
if (workflowRunId) {
|
|
274
|
-
|
|
275
|
-
return await createWorkflowOps(env);
|
|
277
|
+
return await createWorkflowOps(runtime);
|
|
276
278
|
}
|
|
277
|
-
|
|
278
|
-
return await createRuntimeOps(env, benchmark);
|
|
279
|
+
return await createRuntimeOps(runtime, benchmark);
|
|
279
280
|
}
|
|
280
281
|
export class ContextEngine {
|
|
281
282
|
constructor(opts = {}, reactor) {
|
|
@@ -329,13 +330,14 @@ export class ContextEngine {
|
|
|
329
330
|
return await ContextEngine.runDirect(this, triggerEvent, params);
|
|
330
331
|
}
|
|
331
332
|
static async prepareExecutionShell(story, triggerEvent, params) {
|
|
332
|
-
const
|
|
333
|
+
const env = params.runtime.env;
|
|
334
|
+
const ops = await measureBenchmark(params.__benchmark, "react.resolveOpsMs", async () => await getContextEngineOps(params.runtime, params.__benchmark));
|
|
333
335
|
const silent = params.options?.silent ?? false;
|
|
334
336
|
const ctxResult = await measureBenchmark(params.__benchmark, "react.initializeContextMs", async () => await ops.initializeContext(params.context ?? null, { silent }));
|
|
335
337
|
let currentContext = ctxResult.context;
|
|
336
338
|
const contextSelector = { id: String(currentContext.id) };
|
|
337
339
|
if (ctxResult.isNew) {
|
|
338
|
-
await story.opts.onContextCreated?.({ env
|
|
340
|
+
await story.opts.onContextCreated?.({ env, context: currentContext });
|
|
339
341
|
}
|
|
340
342
|
if (currentContext.status === "closed") {
|
|
341
343
|
await measureBenchmark(params.__benchmark, "react.reopenClosedContextMs", async () => await ops.updateContextStatus(contextSelector, "open_idle"));
|
|
@@ -355,6 +357,7 @@ export class ContextEngine {
|
|
|
355
357
|
};
|
|
356
358
|
}
|
|
357
359
|
static async startDurable(story, triggerEvent, params) {
|
|
360
|
+
const env = params.runtime.env;
|
|
358
361
|
if (params.options?.writable) {
|
|
359
362
|
throw new Error("ContextEngine.react: durable runs manage their own workflow stream");
|
|
360
363
|
}
|
|
@@ -367,14 +370,15 @@ export class ContextEngine {
|
|
|
367
370
|
throw new Error("ContextEngine.react: durable workflow is not configured. Call configureContextDurableWorkflow(...) in runtime bootstrap.");
|
|
368
371
|
}
|
|
369
372
|
const shell = await ContextEngine.prepareExecutionShell(story, triggerEvent, params);
|
|
373
|
+
let run;
|
|
370
374
|
try {
|
|
371
375
|
const [{ start }] = await Promise.all([
|
|
372
376
|
import("workflow/api"),
|
|
373
377
|
]);
|
|
374
|
-
const
|
|
378
|
+
const startedRun = await start(workflow, [
|
|
375
379
|
{
|
|
376
380
|
contextKey,
|
|
377
|
-
|
|
381
|
+
runtime: params.runtime,
|
|
378
382
|
context: params.context ?? null,
|
|
379
383
|
triggerEvent,
|
|
380
384
|
options: {
|
|
@@ -392,16 +396,21 @@ export class ContextEngine {
|
|
|
392
396
|
},
|
|
393
397
|
},
|
|
394
398
|
]);
|
|
395
|
-
|
|
399
|
+
run = {
|
|
400
|
+
runId: String(startedRun.runId),
|
|
401
|
+
status: startedRun.status,
|
|
402
|
+
returnValue: startedRun.returnValue,
|
|
403
|
+
};
|
|
404
|
+
const runtime = await createRuntimeOps(params.runtime);
|
|
396
405
|
await runtime.db.transact([
|
|
397
406
|
runtime.db.tx.event_executions[shell.execution.id].update({
|
|
398
|
-
workflowRunId:
|
|
407
|
+
workflowRunId: startedRun.runId,
|
|
399
408
|
updatedAt: new Date(),
|
|
400
409
|
}),
|
|
401
410
|
]);
|
|
402
411
|
}
|
|
403
412
|
catch (error) {
|
|
404
|
-
const ops = await getContextEngineOps(params.
|
|
413
|
+
const ops = await getContextEngineOps(params.runtime, params.__benchmark);
|
|
405
414
|
await ops.completeExecution(shell.contextSelector, shell.execution.id, "failed").catch(() => null);
|
|
406
415
|
throw error;
|
|
407
416
|
}
|
|
@@ -410,10 +419,12 @@ export class ContextEngine {
|
|
|
410
419
|
trigger: shell.trigger,
|
|
411
420
|
reaction: shell.reaction,
|
|
412
421
|
execution: shell.execution,
|
|
422
|
+
run,
|
|
413
423
|
};
|
|
414
424
|
}
|
|
415
425
|
static async runDirect(story, triggerEvent, params) {
|
|
416
|
-
const
|
|
426
|
+
const env = params.runtime.env;
|
|
427
|
+
const ops = await measureBenchmark(params.__benchmark, "react.resolveOpsMs", async () => await getContextEngineOps(params.runtime, params.__benchmark));
|
|
417
428
|
const maxIterations = params.options?.maxIterations ?? 20;
|
|
418
429
|
const maxModelSteps = params.options?.maxModelSteps ?? 1;
|
|
419
430
|
const preventClose = params.options?.preventClose ?? false;
|
|
@@ -488,7 +499,7 @@ export class ContextEngine {
|
|
|
488
499
|
}));
|
|
489
500
|
currentStepId = stepCreate.stepId;
|
|
490
501
|
currentStepStream = await createPersistedContextStepStream({
|
|
491
|
-
|
|
502
|
+
runtime: params.runtime,
|
|
492
503
|
executionId,
|
|
493
504
|
stepId: stepCreate.stepId,
|
|
494
505
|
});
|
|
@@ -507,7 +518,7 @@ export class ContextEngine {
|
|
|
507
518
|
],
|
|
508
519
|
});
|
|
509
520
|
// Hook: Context DSL `context()` (implemented by subclasses via `initialize()`)
|
|
510
|
-
const nextContent = await measureBenchmark(params.__benchmark, `${stagePrefix}.contextMs`, async () => await story.initialize(updatedContext,
|
|
521
|
+
const nextContent = await measureBenchmark(params.__benchmark, `${stagePrefix}.contextMs`, async () => await story.initialize(updatedContext, env));
|
|
511
522
|
updatedContext = await measureBenchmark(params.__benchmark, `${stagePrefix}.persistContextMs`, async () => await ops.updateContextContent(activeContextSelector, nextContent));
|
|
512
523
|
await emitContextEvents({
|
|
513
524
|
silent,
|
|
@@ -520,15 +531,15 @@ export class ContextEngine {
|
|
|
520
531
|
},
|
|
521
532
|
],
|
|
522
533
|
});
|
|
523
|
-
await story.opts.onContextUpdated?.({ env
|
|
534
|
+
await story.opts.onContextUpdated?.({ env, context: updatedContext });
|
|
524
535
|
// Hook: Context DSL `narrative()` (implemented by subclasses via `buildSystemPrompt()`)
|
|
525
|
-
const systemPrompt = await measureBenchmark(params.__benchmark, `${stagePrefix}.narrativeMs`, async () => await story.buildSystemPrompt(updatedContext,
|
|
536
|
+
const systemPrompt = await measureBenchmark(params.__benchmark, `${stagePrefix}.narrativeMs`, async () => await story.buildSystemPrompt(updatedContext, env));
|
|
526
537
|
// 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,
|
|
538
|
+
const toolsAll = await measureBenchmark(params.__benchmark, `${stagePrefix}.actionsMs`, async () => await story.buildTools(updatedContext, env));
|
|
539
|
+
const skillsAll = await measureBenchmark(params.__benchmark, `${stagePrefix}.skillsMs`, async () => await story.buildSkills(updatedContext, env));
|
|
529
540
|
// IMPORTANT: step args must be serializable.
|
|
530
541
|
// Match DurableAgent behavior: convert tool input schemas to plain JSON Schema in workflow context.
|
|
531
|
-
const
|
|
542
|
+
const actionSpecs = actionsToActionSpecs(toolsAll);
|
|
532
543
|
// Execute model reaction for this iteration using the stable reaction event id.
|
|
533
544
|
//
|
|
534
545
|
// IMPORTANT:
|
|
@@ -536,7 +547,7 @@ export class ContextEngine {
|
|
|
536
547
|
// If we stream with a per-step id, the UI will render an optimistic assistant message
|
|
537
548
|
// (step id) and then a second persisted assistant message (reaction id) with the same
|
|
538
549
|
// content once InstantDB updates.
|
|
539
|
-
const reactor = story.getReactor(updatedContext,
|
|
550
|
+
const reactor = story.getReactor(updatedContext, env);
|
|
540
551
|
const reactionPartsBeforeStep = Array.isArray(reactionEvent.content?.parts)
|
|
541
552
|
? [...reactionEvent.content.parts]
|
|
542
553
|
: [];
|
|
@@ -563,15 +574,16 @@ export class ContextEngine {
|
|
|
563
574
|
status: "pending",
|
|
564
575
|
}, { executionId, contextId: String(currentContext.id) });
|
|
565
576
|
};
|
|
566
|
-
const
|
|
567
|
-
|
|
577
|
+
const reactionResult = await measureBenchmark(params.__benchmark, `${stagePrefix}.reactorMs`, async () => await reactor({
|
|
578
|
+
runtime: params.runtime,
|
|
579
|
+
env,
|
|
568
580
|
context: updatedContext,
|
|
569
581
|
contextIdentifier: activeContextSelector,
|
|
570
582
|
triggerEvent,
|
|
571
|
-
model: story.getModel(updatedContext,
|
|
583
|
+
model: story.getModel(updatedContext, env),
|
|
572
584
|
systemPrompt,
|
|
573
585
|
actions: toolsAll,
|
|
574
|
-
|
|
586
|
+
actionSpecs,
|
|
575
587
|
skills: skillsAll,
|
|
576
588
|
eventId: reactionEventId,
|
|
577
589
|
executionId,
|
|
@@ -586,6 +598,7 @@ export class ContextEngine {
|
|
|
586
598
|
writable,
|
|
587
599
|
persistReactionParts,
|
|
588
600
|
}));
|
|
601
|
+
const { assistantEvent, actionRequests, messagesForModel } = reactionResult;
|
|
589
602
|
const reviewRequests = actionRequests.length > 0
|
|
590
603
|
? actionRequests.flatMap((actionRequest) => {
|
|
591
604
|
const toolDef = toolsAll[actionRequest.actionName];
|
|
@@ -649,9 +662,18 @@ export class ContextEngine {
|
|
|
649
662
|
status: "pending",
|
|
650
663
|
};
|
|
651
664
|
reactionEvent = await measureBenchmark(params.__benchmark, `${stagePrefix}.persistAssistantReactionMs`, async () => await ops.updateItem(reactionEvent.id, nextReactionEvent, { executionId, contextId: String(currentContext.id) }));
|
|
665
|
+
if (reactionResult.reactor?.kind) {
|
|
666
|
+
updatedContext = await measureBenchmark(params.__benchmark, `${stagePrefix}.persistReactorStateMs`, async () => await ops.updateContextReactor(activeContextSelector, {
|
|
667
|
+
kind: reactionResult.reactor.kind,
|
|
668
|
+
state: {
|
|
669
|
+
...(reactionResult.reactor.state ?? {}),
|
|
670
|
+
updatedAt: nowIso(),
|
|
671
|
+
},
|
|
672
|
+
}));
|
|
673
|
+
}
|
|
652
674
|
if (currentStepStream) {
|
|
653
675
|
await closePersistedContextStepStream({
|
|
654
|
-
|
|
676
|
+
runtime: params.runtime,
|
|
655
677
|
session: currentStepStream,
|
|
656
678
|
});
|
|
657
679
|
currentStepStream = null;
|
|
@@ -807,9 +829,8 @@ export class ContextEngine {
|
|
|
807
829
|
const { createHook, createWebhook } = await import("workflow");
|
|
808
830
|
const toolCallId = String(actionRequest.actionRef);
|
|
809
831
|
const hookToken = toolApprovalHookToken({ executionId, toolCallId });
|
|
810
|
-
const webhookToken = toolApprovalWebhookToken({ executionId, toolCallId });
|
|
811
832
|
const hook = createHook({ token: hookToken });
|
|
812
|
-
const webhook = createWebhook(
|
|
833
|
+
const webhook = createWebhook();
|
|
813
834
|
const approvalOrRequest = await Promise.race([
|
|
814
835
|
hook.then((approval) => ({ source: "hook", approval })),
|
|
815
836
|
webhook.then((request) => ({ source: "webhook", request })),
|
|
@@ -832,12 +853,18 @@ export class ContextEngine {
|
|
|
832
853
|
}
|
|
833
854
|
}
|
|
834
855
|
const output = await toolDef.execute(actionInput, {
|
|
856
|
+
runtime: params.runtime,
|
|
857
|
+
env,
|
|
858
|
+
context: updatedContext,
|
|
859
|
+
contextIdentifier: activeContextSelector,
|
|
835
860
|
toolCallId: actionRequest.actionRef,
|
|
836
861
|
messages: messagesForModel,
|
|
837
862
|
eventId: reactionEventId,
|
|
838
863
|
executionId,
|
|
839
864
|
triggerEventId,
|
|
840
865
|
contextId: currentContext.id,
|
|
866
|
+
stepId: String(stepCreate.stepId),
|
|
867
|
+
iteration: iter,
|
|
841
868
|
});
|
|
842
869
|
return { actionRequest, success: true, output };
|
|
843
870
|
}
|
|
@@ -894,7 +921,7 @@ export class ContextEngine {
|
|
|
894
921
|
// IMPORTANT: we call this after tool results have been merged into the persisted `reactionEvent`,
|
|
895
922
|
// so stories can inspect `reactionEvent.content.parts` deterministically.
|
|
896
923
|
const continueLoop = await measureBenchmark(params.__benchmark, `${stagePrefix}.shouldContinueMs`, async () => await story.shouldContinue({
|
|
897
|
-
env
|
|
924
|
+
env,
|
|
898
925
|
context: updatedContext,
|
|
899
926
|
reactionEvent,
|
|
900
927
|
assistantEvent: assistantEventEffective,
|
|
@@ -1033,7 +1060,7 @@ export class ContextEngine {
|
|
|
1033
1060
|
if (currentStepStream) {
|
|
1034
1061
|
try {
|
|
1035
1062
|
await abortPersistedContextStepStream({
|
|
1036
|
-
|
|
1063
|
+
runtime: params.runtime,
|
|
1037
1064
|
session: currentStepStream,
|
|
1038
1065
|
reason: error instanceof Error ? error.message : String(error),
|
|
1039
1066
|
});
|
package/dist/context.events.js
CHANGED
|
@@ -173,22 +173,11 @@ function canonicalToolResultContentToOutput(content) {
|
|
|
173
173
|
};
|
|
174
174
|
}
|
|
175
175
|
if (block.type === "file") {
|
|
176
|
-
if (block.mediaType.startsWith("image/") &&
|
|
177
|
-
typeof block.data === "string" &&
|
|
178
|
-
block.data.length > 0) {
|
|
179
|
-
return {
|
|
180
|
-
type: "image-data",
|
|
181
|
-
data: stripDataUrlPrefix(block.data),
|
|
182
|
-
mediaType: block.mediaType,
|
|
183
|
-
filename: block.filename,
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
176
|
return {
|
|
187
|
-
type: "
|
|
177
|
+
type: "media",
|
|
188
178
|
mediaType: block.mediaType,
|
|
189
|
-
filename: block.filename,
|
|
190
179
|
data: typeof block.data === "string" && block.data.length > 0
|
|
191
|
-
? block.data
|
|
180
|
+
? stripDataUrlPrefix(block.data)
|
|
192
181
|
: typeof block.url === "string" && block.url.length > 0
|
|
193
182
|
? block.url
|
|
194
183
|
: block.fileId,
|
|
@@ -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";
|