@ekairos/events 1.22.34-beta.development.0 → 1.22.35
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 +58 -83
- package/dist/codex.d.ts +11 -2
- package/dist/codex.js +16 -8
- package/dist/context.action-calls.d.ts +48 -0
- package/dist/context.action-calls.js +123 -0
- package/dist/context.action.d.ts +55 -0
- package/dist/context.action.js +25 -0
- package/dist/context.builder.d.ts +71 -43
- package/dist/context.builder.js +123 -28
- package/dist/context.config.d.ts +2 -1
- package/dist/context.config.js +8 -3
- package/dist/context.contract.d.ts +2 -4
- package/dist/context.contract.js +3 -9
- package/dist/context.d.ts +3 -2
- package/dist/context.engine.d.ts +75 -46
- package/dist/context.engine.js +538 -302
- package/dist/context.events.js +28 -87
- package/dist/context.js +1 -0
- package/dist/context.part-identity.d.ts +40 -0
- package/dist/context.part-identity.js +270 -0
- package/dist/context.parts.d.ts +389 -164
- package/dist/context.parts.js +343 -218
- package/dist/context.registry.d.ts +1 -1
- package/dist/context.runtime.d.ts +21 -0
- package/dist/context.runtime.js +39 -0
- package/dist/context.step-stream.d.ts +16 -2
- package/dist/context.step-stream.js +58 -16
- package/dist/context.store.d.ts +63 -10
- package/dist/context.stream.d.ts +14 -4
- package/dist/context.stream.js +31 -3
- package/dist/domain.d.ts +1 -0
- package/dist/domain.js +1 -0
- package/dist/index.d.ts +13 -10
- package/dist/index.js +7 -6
- package/dist/react.context-event-parts.d.ts +18 -0
- package/dist/react.context-event-parts.js +509 -0
- package/dist/react.d.ts +7 -42
- package/dist/react.js +4 -87
- package/dist/react.step-stream.d.ts +39 -0
- package/dist/react.step-stream.js +625 -0
- package/dist/react.types.d.ts +121 -0
- package/dist/react.types.js +2 -0
- package/dist/react.use-context.d.ts +7 -0
- package/dist/react.use-context.js +867 -0
- package/dist/reactors/ai-sdk.chunk-map.d.ts +1 -0
- package/dist/reactors/ai-sdk.chunk-map.js +56 -5
- package/dist/reactors/ai-sdk.reactor.d.ts +8 -5
- package/dist/reactors/ai-sdk.reactor.js +10 -9
- package/dist/reactors/ai-sdk.step.d.ts +6 -6
- package/dist/reactors/ai-sdk.step.js +32 -24
- package/dist/reactors/scripted.reactor.d.ts +7 -4
- package/dist/reactors/types.d.ts +23 -8
- package/dist/runtime.d.ts +6 -0
- package/dist/runtime.js +9 -0
- package/dist/runtime.step.js +2 -2
- package/dist/schema.d.ts +268 -2
- package/dist/schema.js +5 -9
- package/dist/steps/do-context-stream-step.d.ts +2 -2
- package/dist/steps/do-context-stream-step.js +6 -8
- package/dist/steps/durable.steps.d.ts +28 -0
- package/dist/steps/durable.steps.js +34 -0
- package/dist/steps/store.steps.d.ts +121 -39
- package/dist/steps/store.steps.js +266 -111
- package/dist/steps/stream.steps.d.ts +36 -3
- package/dist/steps/stream.steps.js +137 -14
- package/dist/steps/trace.steps.d.ts +4 -2
- package/dist/steps/trace.steps.js +26 -8
- package/dist/stores/instant.store.d.ts +15 -11
- package/dist/stores/instant.store.js +155 -6
- package/dist/tools-to-model-tools.d.ts +39 -3
- package/dist/tools-to-model-tools.js +63 -6
- package/package.json +20 -6
- package/dist/context.toolcalls.d.ts +0 -60
- package/dist/context.toolcalls.js +0 -117
package/dist/context.engine.js
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getContextRuntimeServices } from "./context.runtime.js";
|
|
2
2
|
import { OUTPUT_ITEM_TYPE, WEB_CHANNEL } from "./context.events.js";
|
|
3
|
-
import {
|
|
3
|
+
import { applyActionExecutionResultToParts } from "./context.action-calls.js";
|
|
4
4
|
import { isContextPartEnvelope, normalizePartsForPersistence, } from "./context.parts.js";
|
|
5
|
-
import { toolsToModelTools } from "./tools-to-model-tools.js";
|
|
6
5
|
import { createAiSdkReactor, } from "./context.reactor.js";
|
|
7
|
-
import { abortPersistedContextStepStream,
|
|
8
|
-
import { completeExecution, createContextStep, initializeContext,
|
|
6
|
+
import { abortPersistedContextStepStream, closeContextStream, createPersistedContextStepStreamForRuntime, finalizePersistedContextStepStreamForRuntime, writeActionResultPartChunksToSession, } from "./steps/stream.steps.js";
|
|
7
|
+
import { completeExecution, completeExecutionStep, createContextStep, getContextItems, initializeContext, openExecutionStep, openExecution, saveExecutionStepOutput, updateContextContent, updateContextDefinition, updateContextReactor, updateContextStatus, updateItem, updateContextStep, updateExecutionWorkflowRun, upsertContextResources, } from "./steps/store.steps.js";
|
|
8
|
+
import { readContextDurableWorkflowReturnValue, readContextDurableWorkflowStatus, resumeContextReturnValueHook, startContextDurableWorkflow, } from "./steps/durable.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 resolveReactRuntime(params) {
|
|
15
|
+
if (params.runtime)
|
|
16
|
+
return params.runtime;
|
|
17
|
+
throw new Error("ContextEngine.react requires runtime.");
|
|
18
|
+
}
|
|
14
19
|
export { toolApprovalHookToken, toolApprovalWebhookToken, getClientResumeHookUrl };
|
|
15
20
|
function nowIso() {
|
|
16
21
|
return new Date().toISOString();
|
|
@@ -24,13 +29,21 @@ function summarizePartPreview(part) {
|
|
|
24
29
|
if (!part || typeof part !== "object")
|
|
25
30
|
return {};
|
|
26
31
|
if (isContextPartEnvelope(part)) {
|
|
27
|
-
const preview = part.
|
|
28
|
-
? part.content[0]
|
|
29
|
-
:
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
const preview = part.type === "message"
|
|
33
|
+
? part.content.text ?? JSON.stringify(part.content.blocks?.[0] ?? part)
|
|
34
|
+
: part.type === "reasoning"
|
|
35
|
+
? part.content.text
|
|
36
|
+
: part.type === "source"
|
|
37
|
+
? JSON.stringify(part.content.sources[0] ?? part)
|
|
38
|
+
: part.content.status === "failed"
|
|
39
|
+
? part.content.error.message
|
|
40
|
+
: JSON.stringify(part.content);
|
|
41
|
+
const state = part.type === "reasoning"
|
|
42
|
+
? part.content.state
|
|
43
|
+
: part.type === "action"
|
|
44
|
+
? part.content.status
|
|
45
|
+
: undefined;
|
|
46
|
+
const toolCallId = part.type === "action" ? part.content.actionCallId : undefined;
|
|
34
47
|
return {
|
|
35
48
|
partPreview: preview ? clipPreview(preview) : undefined,
|
|
36
49
|
partState: state,
|
|
@@ -89,9 +102,39 @@ async function readActiveWorkflowRunId() {
|
|
|
89
102
|
return null;
|
|
90
103
|
}
|
|
91
104
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
105
|
+
function serializeContextReturnValueError(error) {
|
|
106
|
+
if (error instanceof Error) {
|
|
107
|
+
return {
|
|
108
|
+
name: error.name,
|
|
109
|
+
message: error.message,
|
|
110
|
+
stack: error.stack,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return {
|
|
114
|
+
message: String(error),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function unwrapContextReturnValueHookPayload(payload) {
|
|
118
|
+
if (payload.ok)
|
|
119
|
+
return payload.result;
|
|
120
|
+
const error = new Error(payload.error.message);
|
|
121
|
+
if (payload.error.name) {
|
|
122
|
+
error.name = payload.error.name;
|
|
123
|
+
}
|
|
124
|
+
if (payload.error.stack) {
|
|
125
|
+
error.stack = payload.error.stack;
|
|
126
|
+
}
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
129
|
+
function isEmptyContextContent(content) {
|
|
130
|
+
if (content == null)
|
|
131
|
+
return true;
|
|
132
|
+
if (typeof content !== "object")
|
|
133
|
+
return false;
|
|
134
|
+
return Object.keys(content).length === 0;
|
|
135
|
+
}
|
|
136
|
+
async function createRuntimeOps(runtimeHandle, benchmark) {
|
|
137
|
+
const runtime = await getContextRuntimeServices(runtimeHandle);
|
|
95
138
|
const { db } = runtime;
|
|
96
139
|
const { InstantStore } = await import("./stores/instant.store.js");
|
|
97
140
|
const requireContextId = (contextIdentifier) => {
|
|
@@ -145,13 +188,16 @@ async function createRuntimeOps(env, benchmark) {
|
|
|
145
188
|
return { context, isNew: true };
|
|
146
189
|
},
|
|
147
190
|
updateContextContent: async (contextIdentifier, content) => await store.updateContextContent(contextIdentifier, content),
|
|
191
|
+
updateContextDefinition: async (contextIdentifier, definition) => await store.updateContextDefinition(contextIdentifier, definition),
|
|
192
|
+
upsertContextResources: async (contextIdentifier, resources) => await store.upsertContextResources(contextIdentifier, resources),
|
|
193
|
+
updateContextReactor: async (contextIdentifier, reactor) => await store.updateContextReactor(contextIdentifier, reactor),
|
|
148
194
|
updateContextStatus: async (contextIdentifier, status) => await instrumentedDb.transact([
|
|
149
195
|
instrumentedDb.tx.event_contexts[requireContextId(contextIdentifier)].update({
|
|
150
196
|
status,
|
|
151
197
|
updatedAt: new Date(),
|
|
152
198
|
}),
|
|
153
199
|
]),
|
|
154
|
-
|
|
200
|
+
openExecution: async ({ contextIdentifier, triggerEvent }) => {
|
|
155
201
|
const contextId = requireContextId(contextIdentifier);
|
|
156
202
|
const triggerId = String(triggerEvent.id);
|
|
157
203
|
const reactionId = makeRuntimeId();
|
|
@@ -209,6 +255,31 @@ async function createRuntimeOps(env, benchmark) {
|
|
|
209
255
|
},
|
|
210
256
|
};
|
|
211
257
|
},
|
|
258
|
+
openExecutionStep: async ({ contextIdentifier, content, executionId, iteration }) => {
|
|
259
|
+
const stepId = makeRuntimeId();
|
|
260
|
+
const now = new Date();
|
|
261
|
+
await instrumentedDb.transact([
|
|
262
|
+
instrumentedDb.tx.event_steps[stepId].create({
|
|
263
|
+
createdAt: now,
|
|
264
|
+
updatedAt: now,
|
|
265
|
+
status: "running",
|
|
266
|
+
iteration,
|
|
267
|
+
}),
|
|
268
|
+
instrumentedDb.tx.event_steps[stepId].link({ execution: executionId }),
|
|
269
|
+
]);
|
|
270
|
+
const stream = await createPersistedContextStepStreamForRuntime({ db: instrumentedDb }, {
|
|
271
|
+
executionId,
|
|
272
|
+
stepId,
|
|
273
|
+
});
|
|
274
|
+
const context = await store.updateContextContent(contextIdentifier, content);
|
|
275
|
+
const events = await store.getItems(contextIdentifier);
|
|
276
|
+
return {
|
|
277
|
+
stepId,
|
|
278
|
+
stream,
|
|
279
|
+
context,
|
|
280
|
+
events,
|
|
281
|
+
};
|
|
282
|
+
},
|
|
212
283
|
createContextStep: async ({ executionId, iteration }) => {
|
|
213
284
|
const stepId = makeRuntimeId();
|
|
214
285
|
await instrumentedDb.transact([
|
|
@@ -223,16 +294,67 @@ async function createRuntimeOps(env, benchmark) {
|
|
|
223
294
|
return { stepId };
|
|
224
295
|
},
|
|
225
296
|
updateContextStep: async (params) => {
|
|
297
|
+
const update = { updatedAt: new Date() };
|
|
298
|
+
if (params.patch.status !== undefined)
|
|
299
|
+
update.status = params.patch.status;
|
|
300
|
+
if (params.patch.errorText !== undefined)
|
|
301
|
+
update.errorText = params.patch.errorText;
|
|
226
302
|
await instrumentedDb.transact([
|
|
227
|
-
instrumentedDb.tx.event_steps[params.stepId].update(
|
|
228
|
-
...params.patch,
|
|
229
|
-
updatedAt: new Date(),
|
|
230
|
-
}),
|
|
303
|
+
instrumentedDb.tx.event_steps[params.stepId].update(update),
|
|
231
304
|
]);
|
|
232
305
|
},
|
|
233
|
-
|
|
306
|
+
completeExecutionStep: async (params) => {
|
|
307
|
+
const actionResultChunkEvents = await writeActionResultPartChunksToSession({
|
|
308
|
+
session: params.session,
|
|
309
|
+
contextId: String(params.contextId ?? ""),
|
|
310
|
+
executionId: String(params.executionId ?? ""),
|
|
311
|
+
itemId: String(params.reactionEventId ?? ""),
|
|
312
|
+
actionResults: params.actionResults ?? [],
|
|
313
|
+
});
|
|
314
|
+
if (params.parts) {
|
|
315
|
+
await store.saveStepParts({ stepId: params.stepId, parts: params.parts });
|
|
316
|
+
}
|
|
317
|
+
if (params.session) {
|
|
318
|
+
await finalizePersistedContextStepStreamForRuntime({
|
|
319
|
+
runtime: { db: instrumentedDb },
|
|
320
|
+
session: params.session,
|
|
321
|
+
mode: "close",
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
const update = { updatedAt: new Date() };
|
|
325
|
+
update.status = params.stepStatus ?? "completed";
|
|
326
|
+
if (params.errorText !== undefined)
|
|
327
|
+
update.errorText = params.errorText;
|
|
328
|
+
await instrumentedDb.transact([
|
|
329
|
+
instrumentedDb.tx.event_steps[params.stepId].update(update),
|
|
330
|
+
]);
|
|
331
|
+
if (!params.reactionEventId || !params.reactionEvent) {
|
|
332
|
+
return { actionResultChunkEvents };
|
|
333
|
+
}
|
|
334
|
+
await instrumentedDb.transact([
|
|
335
|
+
instrumentedDb.tx.event_items[params.reactionEventId].update(params.reactionEvent),
|
|
336
|
+
]);
|
|
337
|
+
return {
|
|
338
|
+
reactionEvent: {
|
|
339
|
+
...params.reactionEvent,
|
|
340
|
+
id: params.reactionEventId,
|
|
341
|
+
},
|
|
342
|
+
actionResultChunkEvents,
|
|
343
|
+
};
|
|
344
|
+
},
|
|
345
|
+
saveExecutionStepOutput: async (params) => {
|
|
234
346
|
await store.saveStepParts({ stepId: params.stepId, parts: params.parts });
|
|
347
|
+
await instrumentedDb.transact([
|
|
348
|
+
instrumentedDb.tx.event_items[params.reactionEventId].update(params.reactionEvent),
|
|
349
|
+
]);
|
|
350
|
+
return {
|
|
351
|
+
reactionEvent: {
|
|
352
|
+
...params.reactionEvent,
|
|
353
|
+
id: params.reactionEventId,
|
|
354
|
+
},
|
|
355
|
+
};
|
|
235
356
|
},
|
|
357
|
+
getItems: async (contextIdentifier) => await store.getItems(contextIdentifier),
|
|
236
358
|
updateItem: async (itemId, item) => {
|
|
237
359
|
await instrumentedDb.transact([instrumentedDb.tx.event_items[itemId].update(item)]);
|
|
238
360
|
return {
|
|
@@ -240,9 +362,9 @@ async function createRuntimeOps(env, benchmark) {
|
|
|
240
362
|
id: itemId,
|
|
241
363
|
};
|
|
242
364
|
},
|
|
243
|
-
completeExecution: async (contextIdentifier, executionId, status) => {
|
|
365
|
+
completeExecution: async (contextIdentifier, executionId, status, opts) => {
|
|
244
366
|
const contextId = requireContextId(contextIdentifier);
|
|
245
|
-
|
|
367
|
+
const txs = [
|
|
246
368
|
instrumentedDb.tx.event_executions[executionId].update({
|
|
247
369
|
status,
|
|
248
370
|
updatedAt: new Date(),
|
|
@@ -251,38 +373,67 @@ async function createRuntimeOps(env, benchmark) {
|
|
|
251
373
|
status: "closed",
|
|
252
374
|
updatedAt: new Date(),
|
|
253
375
|
}),
|
|
254
|
-
]
|
|
376
|
+
];
|
|
377
|
+
if (opts?.reactionEventId && opts.reactionEvent) {
|
|
378
|
+
txs.push(instrumentedDb.tx.event_items[opts.reactionEventId].update(opts.reactionEvent));
|
|
379
|
+
}
|
|
380
|
+
await instrumentedDb.transact(txs);
|
|
381
|
+
return opts?.reactionEventId && opts.reactionEvent
|
|
382
|
+
? {
|
|
383
|
+
reactionEvent: {
|
|
384
|
+
...opts.reactionEvent,
|
|
385
|
+
id: opts.reactionEventId,
|
|
386
|
+
},
|
|
387
|
+
}
|
|
388
|
+
: {};
|
|
255
389
|
},
|
|
256
390
|
};
|
|
257
391
|
}
|
|
258
|
-
async function createWorkflowOps(
|
|
392
|
+
async function createWorkflowOps(runtime) {
|
|
393
|
+
const env = runtime.env;
|
|
259
394
|
return {
|
|
260
|
-
initializeContext: async (contextIdentifier
|
|
261
|
-
updateContextContent: async (contextIdentifier, content) => await updateContextContent(
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
395
|
+
initializeContext: async (contextIdentifier) => await initializeContext({ runtime, contextIdentifier }),
|
|
396
|
+
updateContextContent: async (contextIdentifier, content) => await updateContextContent({ runtime, contextIdentifier, content }),
|
|
397
|
+
updateContextDefinition: async (contextIdentifier, definition) => await updateContextDefinition({ runtime, contextIdentifier, definition }),
|
|
398
|
+
upsertContextResources: async (contextIdentifier, resources) => await upsertContextResources({ runtime, contextIdentifier, resources }),
|
|
399
|
+
updateContextReactor: async (contextIdentifier, reactor) => await updateContextReactor({ runtime, contextIdentifier, reactor }),
|
|
400
|
+
updateContextStatus: async (contextIdentifier, status) => await updateContextStatus({ runtime, contextIdentifier, status }),
|
|
401
|
+
openExecution: async ({ contextIdentifier, triggerEvent }) => await openExecution({ runtime, contextIdentifier, triggerEvent }),
|
|
402
|
+
openExecutionStep: async (params) => await openExecutionStep({ runtime, ...params }),
|
|
403
|
+
createContextStep: async ({ executionId, iteration }) => await createContextStep({ runtime, executionId, iteration }),
|
|
404
|
+
updateContextStep: async (params) => await updateContextStep({ runtime, ...params }),
|
|
405
|
+
completeExecutionStep: async (params) => await completeExecutionStep({ runtime, ...params }),
|
|
406
|
+
saveExecutionStepOutput: async (params) => await saveExecutionStepOutput({ runtime, ...params }),
|
|
407
|
+
getItems: async (contextIdentifier) => await getContextItems({ runtime, contextIdentifier }),
|
|
408
|
+
updateItem: async (itemId, item, opts) => await updateItem({ runtime, eventId: itemId, event: item, opts }),
|
|
409
|
+
completeExecution: async (contextIdentifier, executionId, status, opts) => await completeExecution({ runtime, contextIdentifier, executionId, status, ...opts }),
|
|
269
410
|
};
|
|
270
411
|
}
|
|
271
|
-
async function getContextEngineOps(
|
|
412
|
+
async function getContextEngineOps(runtime, benchmark) {
|
|
413
|
+
const env = runtime.env;
|
|
272
414
|
const workflowRunId = await readActiveWorkflowRunId();
|
|
273
415
|
if (workflowRunId) {
|
|
274
|
-
|
|
275
|
-
return await createWorkflowOps(env);
|
|
416
|
+
return await createWorkflowOps(runtime);
|
|
276
417
|
}
|
|
277
|
-
|
|
278
|
-
return await createRuntimeOps(env, benchmark);
|
|
418
|
+
return await createRuntimeOps(runtime, benchmark);
|
|
279
419
|
}
|
|
280
420
|
export class ContextEngine {
|
|
281
421
|
constructor(opts = {}, reactor) {
|
|
282
422
|
this.opts = opts;
|
|
283
|
-
this.reactor =
|
|
423
|
+
this.reactor =
|
|
424
|
+
reactor ??
|
|
425
|
+
createAiSdkReactor();
|
|
284
426
|
}
|
|
285
|
-
async
|
|
427
|
+
async describeContext(_content, _context, _env, _runtime) {
|
|
428
|
+
return null;
|
|
429
|
+
}
|
|
430
|
+
async defineGoal(_content, _context, _env, _runtime) {
|
|
431
|
+
return null;
|
|
432
|
+
}
|
|
433
|
+
async defineResources(_content, _context, _env, _runtime) {
|
|
434
|
+
return [];
|
|
435
|
+
}
|
|
436
|
+
async buildSkills(_context, _env, _runtime) {
|
|
286
437
|
return [];
|
|
287
438
|
}
|
|
288
439
|
/**
|
|
@@ -302,13 +453,13 @@ export class ContextEngine {
|
|
|
302
453
|
* the builder) so results are durable and replay-safe.
|
|
303
454
|
* - If it’s pure/deterministic, it can run in workflow context.
|
|
304
455
|
*/
|
|
305
|
-
async expandEvents(events, _context, _env) {
|
|
456
|
+
async expandEvents(events, _context, _env, _runtime) {
|
|
306
457
|
return events;
|
|
307
458
|
}
|
|
308
|
-
getModel(_context, _env) {
|
|
459
|
+
getModel(_context, _env, _runtime) {
|
|
309
460
|
return "openai/gpt-5";
|
|
310
461
|
}
|
|
311
|
-
getReactor(_context, _env) {
|
|
462
|
+
getReactor(_context, _env, _runtime) {
|
|
312
463
|
return this.reactor;
|
|
313
464
|
}
|
|
314
465
|
/**
|
|
@@ -323,30 +474,36 @@ export class ContextEngine {
|
|
|
323
474
|
return true;
|
|
324
475
|
}
|
|
325
476
|
async react(triggerEvent, params) {
|
|
326
|
-
if (params.durable) {
|
|
327
|
-
return await ContextEngine.
|
|
477
|
+
if (params.durable === false) {
|
|
478
|
+
return await ContextEngine.runDirect(this, triggerEvent, params);
|
|
328
479
|
}
|
|
329
|
-
return await ContextEngine.
|
|
480
|
+
return await ContextEngine.startDurable(this, triggerEvent, params);
|
|
330
481
|
}
|
|
331
482
|
static async prepareExecutionShell(story, triggerEvent, params) {
|
|
332
|
-
const
|
|
333
|
-
const
|
|
334
|
-
const
|
|
483
|
+
const runtimeHandle = await resolveReactRuntime(params);
|
|
484
|
+
const env = runtimeHandle.env;
|
|
485
|
+
const ops = await measureBenchmark(params.__benchmark, "react.resolveOpsMs", async () => await getContextEngineOps(runtimeHandle, params.__benchmark));
|
|
486
|
+
const ctxResult = await measureBenchmark(params.__benchmark, "react.initializeContextMs", async () => await ops.initializeContext(params.context ?? null));
|
|
335
487
|
let currentContext = ctxResult.context;
|
|
336
488
|
const contextSelector = { id: String(currentContext.id) };
|
|
337
489
|
if (ctxResult.isNew) {
|
|
338
|
-
await story.opts.onContextCreated?.({
|
|
490
|
+
await story.opts.onContextCreated?.({
|
|
491
|
+
env,
|
|
492
|
+
runtime: runtimeHandle,
|
|
493
|
+
context: currentContext,
|
|
494
|
+
});
|
|
339
495
|
}
|
|
340
496
|
if (currentContext.status === "closed") {
|
|
341
497
|
await measureBenchmark(params.__benchmark, "react.reopenClosedContextMs", async () => await ops.updateContextStatus(contextSelector, "open_idle"));
|
|
342
498
|
currentContext = { ...currentContext, status: "open_idle" };
|
|
343
499
|
}
|
|
344
|
-
const shell = await measureBenchmark(params.__benchmark, "react.
|
|
500
|
+
const shell = await measureBenchmark(params.__benchmark, "react.openExecutionMs", async () => await ops.openExecution({
|
|
345
501
|
contextIdentifier: contextSelector,
|
|
346
502
|
triggerEvent,
|
|
347
503
|
}));
|
|
348
504
|
currentContext = { ...currentContext, status: "open_streaming" };
|
|
349
505
|
return {
|
|
506
|
+
runtimeHandle,
|
|
350
507
|
contextSelector,
|
|
351
508
|
currentContext,
|
|
352
509
|
trigger: shell.triggerEvent,
|
|
@@ -355,6 +512,8 @@ export class ContextEngine {
|
|
|
355
512
|
};
|
|
356
513
|
}
|
|
357
514
|
static async startDurable(story, triggerEvent, params) {
|
|
515
|
+
const runtimeHandle = await resolveReactRuntime(params);
|
|
516
|
+
const env = runtimeHandle.env;
|
|
358
517
|
if (params.options?.writable) {
|
|
359
518
|
throw new Error("ContextEngine.react: durable runs manage their own workflow stream");
|
|
360
519
|
}
|
|
@@ -364,44 +523,89 @@ export class ContextEngine {
|
|
|
364
523
|
}
|
|
365
524
|
const workflow = getContextDurableWorkflow();
|
|
366
525
|
if (typeof workflow !== "function") {
|
|
367
|
-
|
|
526
|
+
const contextKeyLabel = contextKey || "(missing)";
|
|
527
|
+
throw new Error([
|
|
528
|
+
"ContextEngine.react(..., { durable: true }) needs a registered durable context workflow.",
|
|
529
|
+
"Call configureContextDurableWorkflow(contextDurableWorkflow) during server/workflow bootstrap.",
|
|
530
|
+
"If you want inline execution inside the current workflow step, pass durable: false.",
|
|
531
|
+
`Context key: ${contextKeyLabel}.`,
|
|
532
|
+
].join(" "));
|
|
368
533
|
}
|
|
369
534
|
const shell = await ContextEngine.prepareExecutionShell(story, triggerEvent, params);
|
|
535
|
+
if (params.__initialContent !== undefined &&
|
|
536
|
+
isEmptyContextContent(shell.currentContext.content)) {
|
|
537
|
+
const ops = await getContextEngineOps(runtimeHandle, params.__benchmark);
|
|
538
|
+
const initialContent = params.__initialContent;
|
|
539
|
+
shell.currentContext = await ops.updateContextContent(shell.contextSelector, initialContent);
|
|
540
|
+
}
|
|
541
|
+
let run;
|
|
370
542
|
try {
|
|
371
|
-
const
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
{
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
543
|
+
const parentWorkflowRunId = await readActiveWorkflowRunId();
|
|
544
|
+
let returnValueHook = null;
|
|
545
|
+
let returnValueHookPromise = null;
|
|
546
|
+
if (parentWorkflowRunId) {
|
|
547
|
+
try {
|
|
548
|
+
const { createHook } = await import("workflow");
|
|
549
|
+
const hook = createHook({
|
|
550
|
+
token: `context:return:${shell.execution.id}`,
|
|
551
|
+
metadata: {
|
|
552
|
+
kind: "context.returnValue",
|
|
553
|
+
contextId: shell.currentContext.id,
|
|
554
|
+
executionId: shell.execution.id,
|
|
555
|
+
parentWorkflowRunId,
|
|
556
|
+
},
|
|
557
|
+
});
|
|
558
|
+
returnValueHook = {
|
|
559
|
+
token: hook.token,
|
|
560
|
+
parentWorkflowRunId,
|
|
561
|
+
};
|
|
562
|
+
returnValueHookPromise = Promise.resolve(hook);
|
|
563
|
+
}
|
|
564
|
+
catch (error) {
|
|
565
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
566
|
+
if (!message.includes("can only be called inside a workflow function")) {
|
|
567
|
+
throw error;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
const payload = {
|
|
572
|
+
contextKey,
|
|
573
|
+
runtime: runtimeHandle,
|
|
574
|
+
context: params.context ?? null,
|
|
575
|
+
triggerEvent,
|
|
576
|
+
options: {
|
|
577
|
+
maxIterations: params.options?.maxIterations,
|
|
578
|
+
maxModelSteps: params.options?.maxModelSteps,
|
|
579
|
+
preventClose: params.options?.preventClose,
|
|
580
|
+
sendFinish: params.options?.sendFinish,
|
|
393
581
|
},
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
}
|
|
401
|
-
|
|
582
|
+
bootstrap: {
|
|
583
|
+
contextId: shell.currentContext.id,
|
|
584
|
+
trigger: shell.trigger,
|
|
585
|
+
reaction: shell.reaction,
|
|
586
|
+
execution: shell.execution,
|
|
587
|
+
returnValueHookToken: returnValueHook?.token ?? null,
|
|
588
|
+
},
|
|
589
|
+
};
|
|
590
|
+
const startedRun = await measureBenchmark(params.__benchmark, "react.durable.startWorkflowMs", async () => await startContextDurableWorkflow({ payload }));
|
|
591
|
+
run = {
|
|
592
|
+
runId: String(startedRun.runId),
|
|
593
|
+
status: readContextDurableWorkflowStatus({ runId: String(startedRun.runId) }),
|
|
594
|
+
returnValue: returnValueHookPromise
|
|
595
|
+
? returnValueHookPromise.then(unwrapContextReturnValueHookPayload)
|
|
596
|
+
: readContextDurableWorkflowReturnValue({
|
|
597
|
+
runId: String(startedRun.runId),
|
|
598
|
+
}),
|
|
599
|
+
returnValueHook,
|
|
600
|
+
};
|
|
601
|
+
await measureBenchmark(params.__benchmark, "react.durable.persistWorkflowRunIdMs", async () => await updateExecutionWorkflowRun({
|
|
602
|
+
runtime: runtimeHandle,
|
|
603
|
+
executionId: shell.execution.id,
|
|
604
|
+
workflowRunId: String(startedRun.runId),
|
|
605
|
+
}));
|
|
402
606
|
}
|
|
403
607
|
catch (error) {
|
|
404
|
-
const ops = await getContextEngineOps(
|
|
608
|
+
const ops = await getContextEngineOps(runtimeHandle, params.__benchmark);
|
|
405
609
|
await ops.completeExecution(shell.contextSelector, shell.execution.id, "failed").catch(() => null);
|
|
406
610
|
throw error;
|
|
407
611
|
}
|
|
@@ -410,21 +614,52 @@ export class ContextEngine {
|
|
|
410
614
|
trigger: shell.trigger,
|
|
411
615
|
reaction: shell.reaction,
|
|
412
616
|
execution: shell.execution,
|
|
617
|
+
run,
|
|
413
618
|
};
|
|
414
619
|
}
|
|
415
620
|
static async runDirect(story, triggerEvent, params) {
|
|
416
|
-
|
|
621
|
+
if (!params.__bootstrap) {
|
|
622
|
+
const shell = await ContextEngine.prepareExecutionShell(story, triggerEvent, params);
|
|
623
|
+
const run = ContextEngine.runDirect(story, triggerEvent, {
|
|
624
|
+
...params,
|
|
625
|
+
runtime: shell.runtimeHandle,
|
|
626
|
+
__bootstrap: {
|
|
627
|
+
contextId: shell.currentContext.id,
|
|
628
|
+
trigger: shell.trigger,
|
|
629
|
+
reaction: shell.reaction,
|
|
630
|
+
execution: shell.execution,
|
|
631
|
+
},
|
|
632
|
+
});
|
|
633
|
+
return {
|
|
634
|
+
context: shell.currentContext,
|
|
635
|
+
trigger: shell.trigger,
|
|
636
|
+
reaction: shell.reaction,
|
|
637
|
+
execution: shell.execution,
|
|
638
|
+
run,
|
|
639
|
+
};
|
|
640
|
+
}
|
|
641
|
+
const runtimeHandle = await resolveReactRuntime(params);
|
|
642
|
+
const env = runtimeHandle.env;
|
|
643
|
+
const ops = await measureBenchmark(params.__benchmark, "react.resolveOpsMs", async () => await getContextEngineOps(runtimeHandle, params.__benchmark));
|
|
417
644
|
const maxIterations = params.options?.maxIterations ?? 20;
|
|
418
645
|
const maxModelSteps = params.options?.maxModelSteps ?? 1;
|
|
419
646
|
const preventClose = params.options?.preventClose ?? false;
|
|
420
647
|
const sendFinish = params.options?.sendFinish ?? true;
|
|
421
|
-
const silent = params.options?.silent ?? false;
|
|
422
648
|
const writable = params.options?.writable;
|
|
423
649
|
const bootstrapped = params.__bootstrap;
|
|
650
|
+
const returnValueHookToken = bootstrapped?.returnValueHookToken ?? null;
|
|
651
|
+
const resumeReturnValueHook = async (payload) => {
|
|
652
|
+
if (!returnValueHookToken)
|
|
653
|
+
return;
|
|
654
|
+
await resumeContextReturnValueHook({
|
|
655
|
+
token: returnValueHookToken,
|
|
656
|
+
payload,
|
|
657
|
+
});
|
|
658
|
+
};
|
|
424
659
|
const shell = bootstrapped
|
|
425
660
|
? {
|
|
426
661
|
contextSelector: { id: String(bootstrapped.contextId) },
|
|
427
|
-
currentContext: (await measureBenchmark(params.__benchmark, "react.bootstrapContextLookupMs", async () => await ops.initializeContext({ id: String(bootstrapped.contextId) }
|
|
662
|
+
currentContext: (await measureBenchmark(params.__benchmark, "react.bootstrapContextLookupMs", async () => await ops.initializeContext({ id: String(bootstrapped.contextId) }))).context,
|
|
428
663
|
trigger: bootstrapped.trigger,
|
|
429
664
|
reaction: bootstrapped.reaction,
|
|
430
665
|
execution: bootstrapped.execution,
|
|
@@ -447,7 +682,6 @@ export class ContextEngine {
|
|
|
447
682
|
execution = { ...execution, status: "failed" };
|
|
448
683
|
updatedContext = { ...updatedContext, status: "closed" };
|
|
449
684
|
await emitContextEvents({
|
|
450
|
-
silent,
|
|
451
685
|
writable,
|
|
452
686
|
events: [
|
|
453
687
|
{
|
|
@@ -470,9 +704,7 @@ export class ContextEngine {
|
|
|
470
704
|
// noop
|
|
471
705
|
}
|
|
472
706
|
try {
|
|
473
|
-
|
|
474
|
-
await closeContextStream({ preventClose, sendFinish, writable });
|
|
475
|
-
}
|
|
707
|
+
await closeContextStream({ preventClose, sendFinish, writable });
|
|
476
708
|
}
|
|
477
709
|
catch {
|
|
478
710
|
// noop
|
|
@@ -480,55 +712,102 @@ export class ContextEngine {
|
|
|
480
712
|
};
|
|
481
713
|
try {
|
|
482
714
|
for (let iter = 0; iter < maxIterations; iter++) {
|
|
483
|
-
// Create a persisted step per iteration (IDs generated in step runtime for replay safety)
|
|
484
715
|
const stagePrefix = `react.iteration.${iter}`;
|
|
485
|
-
|
|
716
|
+
runtimeHandle.__ekairosContextRun = {
|
|
717
|
+
contextId: currentContext.id,
|
|
486
718
|
executionId,
|
|
719
|
+
triggerEventId,
|
|
720
|
+
reactionEventId,
|
|
487
721
|
iteration: iter,
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
722
|
+
};
|
|
723
|
+
// Hook: Context DSL `context()` (implemented by subclasses via `initialize()`)
|
|
724
|
+
const nextContent = await measureBenchmark(params.__benchmark, `${stagePrefix}.contextMs`, async () => await story.initialize(updatedContext, env, runtimeHandle));
|
|
725
|
+
const openedStep = await measureBenchmark(params.__benchmark, `${stagePrefix}.openExecutionStepMs`, async () => await ops.openExecutionStep({
|
|
726
|
+
contextIdentifier: activeContextSelector,
|
|
727
|
+
content: nextContent,
|
|
492
728
|
executionId,
|
|
493
|
-
|
|
494
|
-
});
|
|
729
|
+
iteration: iter,
|
|
730
|
+
}));
|
|
731
|
+
currentStepId = openedStep.stepId;
|
|
732
|
+
currentStepStream = openedStep.stream;
|
|
733
|
+
updatedContext = openedStep.context;
|
|
734
|
+
const rawEvents = openedStep.events;
|
|
735
|
+
const previousResources = updatedContext.resources ?? [];
|
|
736
|
+
const resources = await measureBenchmark(params.__benchmark, `${stagePrefix}.resourcesMs`, async () => await story.defineResources(nextContent, updatedContext, env, runtimeHandle));
|
|
737
|
+
const shouldPersistResources = resources.length > 0 || previousResources.length > 0;
|
|
738
|
+
let contextResources = previousResources;
|
|
739
|
+
if (shouldPersistResources) {
|
|
740
|
+
contextResources = await measureBenchmark(params.__benchmark, `${stagePrefix}.contextResourcesMs`, async () => await ops.upsertContextResources(activeContextSelector, resources));
|
|
741
|
+
updatedContext = {
|
|
742
|
+
...updatedContext,
|
|
743
|
+
resources: contextResources,
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
else {
|
|
747
|
+
updatedContext = {
|
|
748
|
+
...updatedContext,
|
|
749
|
+
resources: [],
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
const description = await measureBenchmark(params.__benchmark, `${stagePrefix}.descriptionMs`, async () => await story.describeContext(nextContent, updatedContext, env, runtimeHandle));
|
|
753
|
+
const goal = await measureBenchmark(params.__benchmark, `${stagePrefix}.goalMs`, async () => await story.defineGoal(nextContent, updatedContext, env, runtimeHandle));
|
|
754
|
+
if (description !== null || goal !== null) {
|
|
755
|
+
updatedContext = await measureBenchmark(params.__benchmark, `${stagePrefix}.contextDefinitionMs`, async () => await ops.updateContextDefinition(activeContextSelector, {
|
|
756
|
+
...(description !== null ? { description } : {}),
|
|
757
|
+
...(goal !== null ? { goal } : {}),
|
|
758
|
+
}));
|
|
759
|
+
updatedContext = {
|
|
760
|
+
...updatedContext,
|
|
761
|
+
resources: contextResources,
|
|
762
|
+
};
|
|
763
|
+
}
|
|
495
764
|
await emitContextEvents({
|
|
496
|
-
silent,
|
|
497
765
|
writable,
|
|
498
766
|
events: [
|
|
499
767
|
{
|
|
500
768
|
type: "step.created",
|
|
501
769
|
at: nowIso(),
|
|
502
|
-
stepId: String(
|
|
770
|
+
stepId: String(openedStep.stepId),
|
|
503
771
|
executionId,
|
|
504
772
|
iteration: iter,
|
|
505
773
|
status: "running",
|
|
506
774
|
},
|
|
507
|
-
],
|
|
508
|
-
});
|
|
509
|
-
// Hook: Context DSL `context()` (implemented by subclasses via `initialize()`)
|
|
510
|
-
const nextContent = await measureBenchmark(params.__benchmark, `${stagePrefix}.contextMs`, async () => await story.initialize(updatedContext, params.env));
|
|
511
|
-
updatedContext = await measureBenchmark(params.__benchmark, `${stagePrefix}.persistContextMs`, async () => await ops.updateContextContent(activeContextSelector, nextContent));
|
|
512
|
-
await emitContextEvents({
|
|
513
|
-
silent,
|
|
514
|
-
writable,
|
|
515
|
-
events: [
|
|
516
775
|
{
|
|
517
776
|
type: "context.content_updated",
|
|
518
777
|
at: nowIso(),
|
|
519
778
|
contextId: String(updatedContext.id),
|
|
520
779
|
},
|
|
780
|
+
...(description !== null || goal !== null
|
|
781
|
+
? [
|
|
782
|
+
{
|
|
783
|
+
type: "context.definition_updated",
|
|
784
|
+
at: nowIso(),
|
|
785
|
+
contextId: String(updatedContext.id),
|
|
786
|
+
},
|
|
787
|
+
]
|
|
788
|
+
: []),
|
|
789
|
+
...(shouldPersistResources
|
|
790
|
+
? [
|
|
791
|
+
{
|
|
792
|
+
type: "context.resources_updated",
|
|
793
|
+
at: nowIso(),
|
|
794
|
+
contextId: String(updatedContext.id),
|
|
795
|
+
},
|
|
796
|
+
]
|
|
797
|
+
: []),
|
|
521
798
|
],
|
|
522
799
|
});
|
|
523
|
-
await story.opts.onContextUpdated?.({
|
|
800
|
+
await story.opts.onContextUpdated?.({
|
|
801
|
+
env,
|
|
802
|
+
runtime: runtimeHandle,
|
|
803
|
+
context: updatedContext,
|
|
804
|
+
});
|
|
524
805
|
// Hook: Context DSL `narrative()` (implemented by subclasses via `buildSystemPrompt()`)
|
|
525
|
-
const systemPrompt = await measureBenchmark(params.__benchmark, `${stagePrefix}.narrativeMs`, async () => await story.buildSystemPrompt(updatedContext,
|
|
806
|
+
const systemPrompt = await measureBenchmark(params.__benchmark, `${stagePrefix}.narrativeMs`, async () => await story.buildSystemPrompt(updatedContext, env, runtimeHandle));
|
|
526
807
|
// 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,
|
|
529
|
-
|
|
530
|
-
// Match DurableAgent behavior: convert tool input schemas to plain JSON Schema in workflow context.
|
|
531
|
-
const toolsForModel = toolsToModelTools(toolsAll);
|
|
808
|
+
const toolsAll = await measureBenchmark(params.__benchmark, `${stagePrefix}.actionsMs`, async () => await story.buildTools(updatedContext, env, runtimeHandle));
|
|
809
|
+
const skillsAll = await measureBenchmark(params.__benchmark, `${stagePrefix}.skillsMs`, async () => await story.buildSkills(updatedContext, env, runtimeHandle));
|
|
810
|
+
const expandedEvents = await measureBenchmark(params.__benchmark, `${stagePrefix}.expandEventsMs`, async () => await story.expandEvents(rawEvents, updatedContext, env, runtimeHandle));
|
|
532
811
|
// Execute model reaction for this iteration using the stable reaction event id.
|
|
533
812
|
//
|
|
534
813
|
// IMPORTANT:
|
|
@@ -536,7 +815,7 @@ export class ContextEngine {
|
|
|
536
815
|
// If we stream with a per-step id, the UI will render an optimistic assistant message
|
|
537
816
|
// (step id) and then a second persisted assistant message (reaction id) with the same
|
|
538
817
|
// content once InstantDB updates.
|
|
539
|
-
const reactor = story.getReactor(updatedContext,
|
|
818
|
+
const reactor = story.getReactor(updatedContext, env, runtimeHandle);
|
|
540
819
|
const reactionPartsBeforeStep = Array.isArray(reactionEvent.content?.parts)
|
|
541
820
|
? [...reactionEvent.content.parts]
|
|
542
821
|
: [];
|
|
@@ -547,45 +826,48 @@ export class ContextEngine {
|
|
|
547
826
|
if (nextSignature === persistedReactionPartsSignature)
|
|
548
827
|
return;
|
|
549
828
|
persistedReactionPartsSignature = nextSignature;
|
|
550
|
-
await ops.
|
|
551
|
-
stepId:
|
|
829
|
+
const saved = await ops.saveExecutionStepOutput({
|
|
830
|
+
stepId: openedStep.stepId,
|
|
552
831
|
parts: normalizedParts,
|
|
832
|
+
reactionEventId: reactionEvent.id,
|
|
833
|
+
reactionEvent: {
|
|
834
|
+
...reactionEvent,
|
|
835
|
+
content: {
|
|
836
|
+
...reactionEvent.content,
|
|
837
|
+
parts: [...reactionPartsBeforeStep, ...normalizedParts],
|
|
838
|
+
},
|
|
839
|
+
status: "pending",
|
|
840
|
+
},
|
|
553
841
|
executionId,
|
|
554
842
|
contextId: String(currentContext.id),
|
|
555
843
|
iteration: iter,
|
|
556
844
|
});
|
|
557
|
-
reactionEvent =
|
|
558
|
-
...reactionEvent,
|
|
559
|
-
content: {
|
|
560
|
-
...reactionEvent.content,
|
|
561
|
-
parts: [...reactionPartsBeforeStep, ...normalizedParts],
|
|
562
|
-
},
|
|
563
|
-
status: "pending",
|
|
564
|
-
}, { executionId, contextId: String(currentContext.id) });
|
|
845
|
+
reactionEvent = saved.reactionEvent;
|
|
565
846
|
};
|
|
566
|
-
const
|
|
567
|
-
|
|
847
|
+
const reactionResult = await measureBenchmark(params.__benchmark, `${stagePrefix}.reactorMs`, async () => await reactor({
|
|
848
|
+
runtime: runtimeHandle,
|
|
568
849
|
context: updatedContext,
|
|
569
850
|
contextIdentifier: activeContextSelector,
|
|
851
|
+
resources: contextResources,
|
|
852
|
+
events: expandedEvents,
|
|
570
853
|
triggerEvent,
|
|
571
|
-
model: story.getModel(updatedContext,
|
|
854
|
+
model: story.getModel(updatedContext, env, runtimeHandle),
|
|
572
855
|
systemPrompt,
|
|
573
856
|
actions: toolsAll,
|
|
574
|
-
toolsForModel,
|
|
575
857
|
skills: skillsAll,
|
|
576
858
|
eventId: reactionEventId,
|
|
577
859
|
executionId,
|
|
578
860
|
contextId: String(currentContext.id),
|
|
579
|
-
stepId: String(
|
|
861
|
+
stepId: String(openedStep.stepId),
|
|
580
862
|
iteration: iter,
|
|
581
863
|
maxModelSteps,
|
|
582
864
|
// Only emit a `start` chunk once per story turn.
|
|
583
|
-
sendStart:
|
|
584
|
-
silent,
|
|
865
|
+
sendStart: iter === 0,
|
|
585
866
|
contextStepStream: currentStepStream?.stream,
|
|
586
867
|
writable,
|
|
587
868
|
persistReactionParts,
|
|
588
869
|
}));
|
|
870
|
+
const { assistantEvent, actionRequests, messagesForModel } = reactionResult;
|
|
589
871
|
const reviewRequests = actionRequests.length > 0
|
|
590
872
|
? actionRequests.flatMap((actionRequest) => {
|
|
591
873
|
const toolDef = toolsAll[actionRequest.actionName];
|
|
@@ -614,21 +896,34 @@ export class ContextEngine {
|
|
|
614
896
|
parts: stepParts,
|
|
615
897
|
},
|
|
616
898
|
};
|
|
617
|
-
|
|
618
|
-
|
|
899
|
+
const nextAssistantParts = Array.isArray(assistantEventEffective.content?.parts)
|
|
900
|
+
? assistantEventEffective.content.parts
|
|
901
|
+
: [];
|
|
902
|
+
const nextReactionEvent = {
|
|
903
|
+
...reactionEvent,
|
|
904
|
+
content: {
|
|
905
|
+
...reactionEvent.content,
|
|
906
|
+
parts: [...reactionPartsBeforeStep, ...nextAssistantParts],
|
|
907
|
+
},
|
|
908
|
+
status: "pending",
|
|
909
|
+
};
|
|
910
|
+
const appendedReactorOutput = await measureBenchmark(params.__benchmark, `${stagePrefix}.saveExecutionStepOutputMs`, async () => await ops.saveExecutionStepOutput({
|
|
911
|
+
stepId: openedStep.stepId,
|
|
619
912
|
parts: stepParts,
|
|
913
|
+
reactionEventId: reactionEvent.id,
|
|
914
|
+
reactionEvent: nextReactionEvent,
|
|
620
915
|
executionId,
|
|
621
916
|
contextId: String(currentContext.id),
|
|
622
917
|
iteration: iter,
|
|
623
918
|
}));
|
|
919
|
+
reactionEvent = appendedReactorOutput.reactionEvent;
|
|
624
920
|
await emitContextEvents({
|
|
625
|
-
silent,
|
|
626
921
|
writable,
|
|
627
922
|
events: stepParts.map((part, idx) => ({
|
|
628
923
|
type: "part.created",
|
|
629
924
|
at: nowIso(),
|
|
630
|
-
partKey: `${String(
|
|
631
|
-
stepId: String(
|
|
925
|
+
partKey: `${String(openedStep.stepId)}:${idx}`,
|
|
926
|
+
stepId: String(openedStep.stepId),
|
|
632
927
|
idx,
|
|
633
928
|
partType: part && typeof part.type === "string"
|
|
634
929
|
? String(part.type)
|
|
@@ -636,60 +931,26 @@ export class ContextEngine {
|
|
|
636
931
|
...summarizePartPreview(part),
|
|
637
932
|
})),
|
|
638
933
|
});
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
parts: [...reactionPartsBeforeStep, ...nextAssistantParts],
|
|
648
|
-
},
|
|
649
|
-
status: "pending",
|
|
650
|
-
};
|
|
651
|
-
reactionEvent = await measureBenchmark(params.__benchmark, `${stagePrefix}.persistAssistantReactionMs`, async () => await ops.updateItem(reactionEvent.id, nextReactionEvent, { executionId, contextId: String(currentContext.id) }));
|
|
652
|
-
if (currentStepStream) {
|
|
653
|
-
await closePersistedContextStepStream({
|
|
654
|
-
env: params.env,
|
|
655
|
-
session: currentStepStream,
|
|
656
|
-
});
|
|
657
|
-
currentStepStream = null;
|
|
934
|
+
if (reactionResult.reactor?.kind) {
|
|
935
|
+
updatedContext = await measureBenchmark(params.__benchmark, `${stagePrefix}.persistReactorStateMs`, async () => await ops.updateContextReactor(activeContextSelector, {
|
|
936
|
+
kind: reactionResult.reactor.kind,
|
|
937
|
+
state: {
|
|
938
|
+
...(reactionResult.reactor.state ?? {}),
|
|
939
|
+
updatedAt: nowIso(),
|
|
940
|
+
},
|
|
941
|
+
}));
|
|
658
942
|
}
|
|
659
943
|
story.opts.onEventCreated?.(assistantEventEffective);
|
|
660
|
-
const firstActionRequest = actionRequests?.[0];
|
|
661
|
-
await measureBenchmark(params.__benchmark, `${stagePrefix}.markStepRunningMs`, async () => await ops.updateContextStep({
|
|
662
|
-
stepId: stepCreate.stepId,
|
|
663
|
-
patch: firstActionRequest
|
|
664
|
-
? {
|
|
665
|
-
kind: "action_execute",
|
|
666
|
-
actionName: typeof firstActionRequest.actionName === "string"
|
|
667
|
-
? firstActionRequest.actionName
|
|
668
|
-
: undefined,
|
|
669
|
-
actionInput: firstActionRequest.input,
|
|
670
|
-
}
|
|
671
|
-
: {
|
|
672
|
-
kind: "message",
|
|
673
|
-
},
|
|
674
|
-
executionId,
|
|
675
|
-
contextId: String(currentContext.id),
|
|
676
|
-
iteration: iter,
|
|
677
|
-
}));
|
|
678
944
|
await emitContextEvents({
|
|
679
|
-
silent,
|
|
680
945
|
writable,
|
|
681
946
|
events: [
|
|
682
947
|
{
|
|
683
948
|
type: "step.updated",
|
|
684
949
|
at: nowIso(),
|
|
685
|
-
stepId: String(
|
|
950
|
+
stepId: String(openedStep.stepId),
|
|
686
951
|
executionId,
|
|
687
952
|
iteration: iter,
|
|
688
953
|
status: "running",
|
|
689
|
-
kind: firstActionRequest ? "action_execute" : "message",
|
|
690
|
-
actionName: firstActionRequest && typeof firstActionRequest.actionName === "string"
|
|
691
|
-
? firstActionRequest.actionName
|
|
692
|
-
: undefined,
|
|
693
954
|
},
|
|
694
955
|
],
|
|
695
956
|
});
|
|
@@ -697,50 +958,45 @@ export class ContextEngine {
|
|
|
697
958
|
if (!actionRequests.length) {
|
|
698
959
|
const endResult = await story.callOnEnd(assistantEventEffective);
|
|
699
960
|
if (endResult) {
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
961
|
+
const completedReactionEvent = {
|
|
962
|
+
...reactionEvent,
|
|
963
|
+
status: "completed",
|
|
964
|
+
};
|
|
965
|
+
const finalized = await measureBenchmark(params.__benchmark, `${stagePrefix}.completeExecutionStepMs`, async () => await ops.completeExecutionStep({
|
|
966
|
+
session: currentStepStream,
|
|
967
|
+
stepId: openedStep.stepId,
|
|
968
|
+
stepStatus: "completed",
|
|
969
|
+
reactionEventId,
|
|
970
|
+
reactionEvent: completedReactionEvent,
|
|
710
971
|
executionId,
|
|
711
972
|
contextId: String(currentContext.id),
|
|
712
973
|
iteration: iter,
|
|
713
974
|
}));
|
|
975
|
+
currentStepStream = null;
|
|
976
|
+
currentStepId = null;
|
|
977
|
+
reactionEvent = finalized.reactionEvent ?? completedReactionEvent;
|
|
714
978
|
await emitContextEvents({
|
|
715
|
-
silent,
|
|
716
979
|
writable,
|
|
717
980
|
events: [
|
|
718
981
|
{
|
|
719
982
|
type: "step.updated",
|
|
720
983
|
at: nowIso(),
|
|
721
|
-
stepId: String(
|
|
984
|
+
stepId: String(openedStep.stepId),
|
|
722
985
|
executionId,
|
|
723
986
|
iteration: iter,
|
|
724
987
|
status: "completed",
|
|
725
|
-
kind: "message",
|
|
726
988
|
},
|
|
727
989
|
{
|
|
728
990
|
type: "step.completed",
|
|
729
991
|
at: nowIso(),
|
|
730
|
-
stepId: String(
|
|
992
|
+
stepId: String(openedStep.stepId),
|
|
731
993
|
executionId,
|
|
732
994
|
iteration: iter,
|
|
733
995
|
status: "completed",
|
|
734
996
|
},
|
|
735
997
|
],
|
|
736
998
|
});
|
|
737
|
-
// Mark reaction event completed
|
|
738
|
-
await measureBenchmark(params.__benchmark, `${stagePrefix}.completeReactionMs`, async () => await ops.updateItem(reactionEventId, {
|
|
739
|
-
...reactionEvent,
|
|
740
|
-
status: "completed",
|
|
741
|
-
}, { executionId, contextId: String(currentContext.id) }));
|
|
742
999
|
await emitContextEvents({
|
|
743
|
-
silent,
|
|
744
1000
|
writable,
|
|
745
1001
|
events: [
|
|
746
1002
|
{
|
|
@@ -757,7 +1013,6 @@ export class ContextEngine {
|
|
|
757
1013
|
execution = { ...execution, status: "completed" };
|
|
758
1014
|
updatedContext = { ...updatedContext, status: "closed" };
|
|
759
1015
|
await emitContextEvents({
|
|
760
|
-
silent,
|
|
761
1016
|
writable,
|
|
762
1017
|
events: [
|
|
763
1018
|
{
|
|
@@ -775,19 +1030,15 @@ export class ContextEngine {
|
|
|
775
1030
|
},
|
|
776
1031
|
],
|
|
777
1032
|
});
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
}
|
|
781
|
-
reactionEvent = {
|
|
782
|
-
...reactionEvent,
|
|
783
|
-
status: "completed",
|
|
784
|
-
};
|
|
785
|
-
return {
|
|
1033
|
+
await closeContextStream({ preventClose, sendFinish, writable });
|
|
1034
|
+
const result = {
|
|
786
1035
|
context: updatedContext,
|
|
787
1036
|
trigger,
|
|
788
1037
|
reaction: reactionEvent,
|
|
789
1038
|
execution,
|
|
790
1039
|
};
|
|
1040
|
+
await resumeReturnValueHook({ ok: true, result });
|
|
1041
|
+
return result;
|
|
791
1042
|
}
|
|
792
1043
|
}
|
|
793
1044
|
// Execute actions (workflow context; action implementations decide step vs workflow)
|
|
@@ -807,9 +1058,8 @@ export class ContextEngine {
|
|
|
807
1058
|
const { createHook, createWebhook } = await import("workflow");
|
|
808
1059
|
const toolCallId = String(actionRequest.actionRef);
|
|
809
1060
|
const hookToken = toolApprovalHookToken({ executionId, toolCallId });
|
|
810
|
-
const webhookToken = toolApprovalWebhookToken({ executionId, toolCallId });
|
|
811
1061
|
const hook = createHook({ token: hookToken });
|
|
812
|
-
const webhook = createWebhook(
|
|
1062
|
+
const webhook = createWebhook();
|
|
813
1063
|
const approvalOrRequest = await Promise.race([
|
|
814
1064
|
hook.then((approval) => ({ source: "hook", approval })),
|
|
815
1065
|
webhook.then((request) => ({ source: "webhook", request })),
|
|
@@ -831,14 +1081,21 @@ export class ContextEngine {
|
|
|
831
1081
|
actionInput = approval.args;
|
|
832
1082
|
}
|
|
833
1083
|
}
|
|
834
|
-
const
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
1084
|
+
const executeAction = toolDef.execute;
|
|
1085
|
+
const output = await Reflect.apply(executeAction, undefined, [actionInput, {
|
|
1086
|
+
runtime: runtimeHandle,
|
|
1087
|
+
context: updatedContext,
|
|
1088
|
+
contextIdentifier: activeContextSelector,
|
|
1089
|
+
toolCallId: actionRequest.actionRef,
|
|
1090
|
+
messages: messagesForModel,
|
|
1091
|
+
eventId: reactionEventId,
|
|
1092
|
+
executionId,
|
|
1093
|
+
triggerEventId,
|
|
1094
|
+
contextId: currentContext.id,
|
|
1095
|
+
stepId: String(openedStep.stepId),
|
|
1096
|
+
iteration: iter,
|
|
1097
|
+
contextStepStream: currentStepStream?.stream,
|
|
1098
|
+
}]);
|
|
842
1099
|
return { actionRequest, success: true, output };
|
|
843
1100
|
}
|
|
844
1101
|
catch (e) {
|
|
@@ -850,26 +1107,19 @@ export class ContextEngine {
|
|
|
850
1107
|
};
|
|
851
1108
|
}
|
|
852
1109
|
})));
|
|
853
|
-
// Merge action results into
|
|
1110
|
+
// Merge action results into step parts so the next reaction can see them.
|
|
854
1111
|
let finalizedStepParts = Array.isArray(stepParts) ? [...stepParts] : [];
|
|
855
1112
|
for (const r of actionResults) {
|
|
856
|
-
finalizedStepParts =
|
|
857
|
-
|
|
858
|
-
|
|
1113
|
+
finalizedStepParts = applyActionExecutionResultToParts(finalizedStepParts, {
|
|
1114
|
+
actionCallId: r.actionRequest.actionRef,
|
|
1115
|
+
actionName: r.actionRequest.actionName,
|
|
859
1116
|
}, {
|
|
860
1117
|
success: Boolean(r.success),
|
|
861
1118
|
result: r.output,
|
|
862
1119
|
message: r.errorText,
|
|
863
1120
|
});
|
|
864
1121
|
}
|
|
865
|
-
|
|
866
|
-
stepId: stepCreate.stepId,
|
|
867
|
-
parts: finalizedStepParts,
|
|
868
|
-
executionId,
|
|
869
|
-
contextId: String(currentContext.id),
|
|
870
|
-
iteration: iter,
|
|
871
|
-
}));
|
|
872
|
-
reactionEvent = {
|
|
1122
|
+
const pendingReactionEvent = {
|
|
873
1123
|
...reactionEvent,
|
|
874
1124
|
content: {
|
|
875
1125
|
...reactionEvent.content,
|
|
@@ -879,85 +1129,70 @@ export class ContextEngine {
|
|
|
879
1129
|
},
|
|
880
1130
|
status: "pending",
|
|
881
1131
|
};
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
success: r.success,
|
|
887
|
-
output: r.output,
|
|
888
|
-
errorText: r.errorText,
|
|
889
|
-
eventId: reactionEventId,
|
|
890
|
-
executionId,
|
|
891
|
-
});
|
|
892
|
-
}
|
|
893
|
-
// Stop/continue boundary: allow the Context to decide if the loop should continue.
|
|
894
|
-
// IMPORTANT: we call this after tool results have been merged into the persisted `reactionEvent`,
|
|
895
|
-
// so stories can inspect `reactionEvent.content.parts` deterministically.
|
|
896
|
-
const continueLoop = await measureBenchmark(params.__benchmark, `${stagePrefix}.shouldContinueMs`, async () => await story.shouldContinue({
|
|
897
|
-
env: params.env,
|
|
898
|
-
context: updatedContext,
|
|
899
|
-
reactionEvent,
|
|
900
|
-
assistantEvent: assistantEventEffective,
|
|
901
|
-
actionRequests,
|
|
1132
|
+
const completedStep = await measureBenchmark(params.__benchmark, `${stagePrefix}.completeExecutionStepMs`, async () => await ops.completeExecutionStep({
|
|
1133
|
+
session: currentStepStream,
|
|
1134
|
+
stepId: openedStep.stepId,
|
|
1135
|
+
parts: finalizedStepParts,
|
|
902
1136
|
actionResults: actionResults,
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
stepId: stepCreate.stepId,
|
|
907
|
-
patch: {
|
|
908
|
-
status: "completed",
|
|
909
|
-
kind: actionRequests?.length ? "action_result" : "message",
|
|
910
|
-
actionName: typeof actionResults?.[0]?.actionRequest?.actionName === "string"
|
|
911
|
-
? actionResults[0].actionRequest.actionName
|
|
912
|
-
: undefined,
|
|
913
|
-
actionInput: actionResults?.[0]?.actionRequest?.input,
|
|
914
|
-
actionOutput: actionResults?.[0]?.success === true
|
|
915
|
-
? actionResults[0]?.output
|
|
916
|
-
: undefined,
|
|
917
|
-
actionError: actionResults?.[0]?.success === false
|
|
918
|
-
? String(actionResults[0]?.errorText ?? "action_execution_failed")
|
|
919
|
-
: undefined,
|
|
920
|
-
actionRequests,
|
|
921
|
-
actionResults,
|
|
922
|
-
continueLoop: continueLoop !== false,
|
|
923
|
-
},
|
|
1137
|
+
stepStatus: "completed",
|
|
1138
|
+
reactionEventId,
|
|
1139
|
+
reactionEvent: pendingReactionEvent,
|
|
924
1140
|
executionId,
|
|
925
1141
|
contextId: String(currentContext.id),
|
|
926
1142
|
iteration: iter,
|
|
927
1143
|
}));
|
|
1144
|
+
currentStepStream = null;
|
|
1145
|
+
currentStepId = null;
|
|
1146
|
+
reactionEvent = completedStep.reactionEvent ?? pendingReactionEvent;
|
|
1147
|
+
await emitContextEvents({
|
|
1148
|
+
writable,
|
|
1149
|
+
events: completedStep.actionResultChunkEvents,
|
|
1150
|
+
});
|
|
928
1151
|
await emitContextEvents({
|
|
929
|
-
silent,
|
|
930
1152
|
writable,
|
|
931
1153
|
events: [
|
|
932
1154
|
{
|
|
933
1155
|
type: "step.updated",
|
|
934
1156
|
at: nowIso(),
|
|
935
|
-
stepId: String(
|
|
1157
|
+
stepId: String(openedStep.stepId),
|
|
936
1158
|
executionId,
|
|
937
1159
|
iteration: iter,
|
|
938
1160
|
status: "completed",
|
|
939
|
-
kind: actionRequests?.length ? "action_result" : "message",
|
|
940
|
-
actionName: typeof actionResults?.[0]?.actionRequest?.actionName === "string"
|
|
941
|
-
? actionResults[0].actionRequest.actionName
|
|
942
|
-
: undefined,
|
|
943
1161
|
},
|
|
944
1162
|
{
|
|
945
1163
|
type: "step.completed",
|
|
946
1164
|
at: nowIso(),
|
|
947
|
-
stepId: String(
|
|
1165
|
+
stepId: String(openedStep.stepId),
|
|
948
1166
|
executionId,
|
|
949
1167
|
iteration: iter,
|
|
950
1168
|
status: "completed",
|
|
951
1169
|
},
|
|
952
1170
|
],
|
|
953
1171
|
});
|
|
1172
|
+
// Callback for observability/integration
|
|
1173
|
+
for (const r of actionResults) {
|
|
1174
|
+
await story.opts.onActionExecuted?.({
|
|
1175
|
+
actionRequest: r.actionRequest,
|
|
1176
|
+
success: r.success,
|
|
1177
|
+
output: r.output,
|
|
1178
|
+
errorText: r.errorText,
|
|
1179
|
+
eventId: reactionEventId,
|
|
1180
|
+
executionId,
|
|
1181
|
+
});
|
|
1182
|
+
}
|
|
1183
|
+
// Stop/continue boundary: allow the Context to decide if the loop should continue.
|
|
1184
|
+
// Tool results are already persisted in the completed reaction step here.
|
|
1185
|
+
const continueLoop = await measureBenchmark(params.__benchmark, `${stagePrefix}.shouldContinueMs`, async () => await story.shouldContinue({
|
|
1186
|
+
env,
|
|
1187
|
+
runtime: runtimeHandle,
|
|
1188
|
+
context: updatedContext,
|
|
1189
|
+
reactionEvent,
|
|
1190
|
+
assistantEvent: assistantEventEffective,
|
|
1191
|
+
actionRequests,
|
|
1192
|
+
actionResults: actionResults,
|
|
1193
|
+
}));
|
|
954
1194
|
if (continueLoop !== false) {
|
|
955
|
-
reactionEvent = await measureBenchmark(params.__benchmark, `${stagePrefix}.persistPendingReactionMs`, async () => await ops.updateItem(reactionEventId, {
|
|
956
|
-
...reactionEvent,
|
|
957
|
-
status: "pending",
|
|
958
|
-
}, { executionId, contextId: String(currentContext.id) }));
|
|
959
1195
|
await emitContextEvents({
|
|
960
|
-
silent,
|
|
961
1196
|
writable,
|
|
962
1197
|
events: [
|
|
963
1198
|
{
|
|
@@ -972,12 +1207,11 @@ export class ContextEngine {
|
|
|
972
1207
|
});
|
|
973
1208
|
}
|
|
974
1209
|
if (continueLoop === false) {
|
|
975
|
-
|
|
1210
|
+
reactionEvent = {
|
|
976
1211
|
...reactionEvent,
|
|
977
1212
|
status: "completed",
|
|
978
|
-
}
|
|
1213
|
+
};
|
|
979
1214
|
await emitContextEvents({
|
|
980
|
-
silent,
|
|
981
1215
|
writable,
|
|
982
1216
|
events: [
|
|
983
1217
|
{
|
|
@@ -990,11 +1224,14 @@ export class ContextEngine {
|
|
|
990
1224
|
},
|
|
991
1225
|
],
|
|
992
1226
|
});
|
|
993
|
-
await measureBenchmark(params.__benchmark, `${stagePrefix}.completeExecutionMs`, async () => await ops.completeExecution(activeContextSelector, executionId, "completed"
|
|
1227
|
+
await measureBenchmark(params.__benchmark, `${stagePrefix}.completeExecutionMs`, async () => await ops.completeExecution(activeContextSelector, executionId, "completed", {
|
|
1228
|
+
contextId: String(currentContext.id),
|
|
1229
|
+
reactionEventId,
|
|
1230
|
+
reactionEvent,
|
|
1231
|
+
}));
|
|
994
1232
|
execution = { ...execution, status: "completed" };
|
|
995
1233
|
updatedContext = { ...updatedContext, status: "closed" };
|
|
996
1234
|
await emitContextEvents({
|
|
997
|
-
silent,
|
|
998
1235
|
writable,
|
|
999
1236
|
events: [
|
|
1000
1237
|
{
|
|
@@ -1012,19 +1249,15 @@ export class ContextEngine {
|
|
|
1012
1249
|
},
|
|
1013
1250
|
],
|
|
1014
1251
|
});
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
}
|
|
1018
|
-
reactionEvent = {
|
|
1019
|
-
...reactionEvent,
|
|
1020
|
-
status: "completed",
|
|
1021
|
-
};
|
|
1022
|
-
return {
|
|
1252
|
+
await closeContextStream({ preventClose, sendFinish, writable });
|
|
1253
|
+
const result = {
|
|
1023
1254
|
context: updatedContext,
|
|
1024
1255
|
trigger,
|
|
1025
1256
|
reaction: reactionEvent,
|
|
1026
1257
|
execution,
|
|
1027
1258
|
};
|
|
1259
|
+
await resumeReturnValueHook({ ok: true, result });
|
|
1260
|
+
return result;
|
|
1028
1261
|
}
|
|
1029
1262
|
}
|
|
1030
1263
|
throw new Error(`ContextEngine: maxIterations reached (${maxIterations}) without completion`);
|
|
@@ -1033,7 +1266,7 @@ export class ContextEngine {
|
|
|
1033
1266
|
if (currentStepStream) {
|
|
1034
1267
|
try {
|
|
1035
1268
|
await abortPersistedContextStepStream({
|
|
1036
|
-
|
|
1269
|
+
runtime: runtimeHandle,
|
|
1037
1270
|
session: currentStepStream,
|
|
1038
1271
|
reason: error instanceof Error ? error.message : String(error),
|
|
1039
1272
|
});
|
|
@@ -1059,7 +1292,6 @@ export class ContextEngine {
|
|
|
1059
1292
|
contextId: String(currentContext.id),
|
|
1060
1293
|
}));
|
|
1061
1294
|
await emitContextEvents({
|
|
1062
|
-
silent,
|
|
1063
1295
|
writable,
|
|
1064
1296
|
events: [
|
|
1065
1297
|
{
|
|
@@ -1078,6 +1310,10 @@ export class ContextEngine {
|
|
|
1078
1310
|
}
|
|
1079
1311
|
}
|
|
1080
1312
|
await failExecution();
|
|
1313
|
+
await resumeReturnValueHook({
|
|
1314
|
+
ok: false,
|
|
1315
|
+
error: serializeContextReturnValueError(error),
|
|
1316
|
+
}).catch(() => null);
|
|
1081
1317
|
throw error;
|
|
1082
1318
|
}
|
|
1083
1319
|
}
|