@ekairos/events 1.22.32-beta.development.0 → 1.22.33-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.
@@ -12,6 +12,7 @@
12
12
  * Keeping this logic here helps `context.engine.ts` read like orchestration, and keeps
13
13
  * these transformations testable and reusable.
14
14
  */
15
+ import { isContextPartEnvelope, normalizePartsForPersistence, normalizeToolResultContentToBlocks, } from "./context.parts.js";
15
16
  /**
16
17
  * Extracts tool calls from an event's `parts` array.
17
18
  *
@@ -25,6 +26,16 @@
25
26
  export function extractToolCallsFromParts(parts) {
26
27
  const safeParts = parts ?? [];
27
28
  return safeParts.reduce((acc, p) => {
29
+ if (isContextPartEnvelope(p) && p.type === "tool-call") {
30
+ const firstContent = Array.isArray(p.content) ? p.content[0] : undefined;
31
+ const args = firstContent && firstContent.type === "json" ? firstContent.value : p.content;
32
+ acc.push({
33
+ toolCallId: p.toolCallId,
34
+ toolName: p.toolName,
35
+ args,
36
+ });
37
+ return acc;
38
+ }
28
39
  if (typeof p?.type === "string" && p.type.startsWith("tool-")) {
29
40
  const toolName = p.type.split("-").slice(1).join("-");
30
41
  acc.push({ toolCallId: p.toolCallId, toolName, args: p.input });
@@ -46,15 +57,45 @@ export function extractToolCallsFromParts(parts) {
46
57
  * - on failure: `{ state: "output-error", errorText: <message> }`
47
58
  */
48
59
  export function applyToolExecutionResultToParts(parts, toolCall, execution) {
49
- return parts.map((p) => {
50
- if (p?.type === `tool-${toolCall.toolName}` && p.toolCallId === toolCall.toolCallId) {
51
- if (execution.success) {
52
- return { ...p, state: "output-available", output: execution.result };
53
- }
54
- return { ...p, state: "output-error", errorText: String(execution.message || "Error") };
60
+ const normalized = normalizePartsForPersistence(parts);
61
+ const next = [];
62
+ let insertedResult = false;
63
+ const resultContent = execution.success
64
+ ? normalizeToolResultContentToBlocks(execution.result)
65
+ : [
66
+ {
67
+ type: "text",
68
+ text: String(execution.message || "Error"),
69
+ },
70
+ ];
71
+ for (const part of normalized) {
72
+ next.push(part);
73
+ if (part.type !== "tool-call") {
74
+ continue;
75
+ }
76
+ if (part.toolCallId !== toolCall.toolCallId ||
77
+ part.toolName !== toolCall.toolName) {
78
+ continue;
55
79
  }
56
- return p;
57
- });
80
+ next.push({
81
+ type: "tool-result",
82
+ toolCallId: toolCall.toolCallId,
83
+ toolName: toolCall.toolName,
84
+ state: execution.success ? "output-available" : "output-error",
85
+ content: resultContent,
86
+ });
87
+ insertedResult = true;
88
+ }
89
+ if (!insertedResult) {
90
+ next.push({
91
+ type: "tool-result",
92
+ toolCallId: toolCall.toolCallId,
93
+ toolName: toolCall.toolName,
94
+ state: execution.success ? "output-available" : "output-error",
95
+ content: resultContent,
96
+ });
97
+ }
98
+ return next;
58
99
  }
59
100
  /**
60
101
  * Returns `true` when a given tool has a **settled** execution result in an event's parts.
@@ -67,7 +108,10 @@ export function applyToolExecutionResultToParts(parts, toolCall, execution) {
67
108
  * decide based on the persisted `reactionEvent` (not ephemeral in-memory arrays).
68
109
  */
69
110
  export function didToolExecute(event, toolName) {
70
- const parts = event.content.parts;
71
- return parts.some((p) => p.type === `tool-${toolName}` &&
72
- (p.state === "output-available" || p.state === "output-error"));
111
+ const parts = (event.content.parts ?? []).flatMap((part) => isContextPartEnvelope(part) ? [part] : normalizePartsForPersistence([part]));
112
+ return parts.some((p) => (p.type === "tool-result" &&
113
+ p.toolName === toolName &&
114
+ (p.state === "output-available" || p.state === "output-error")) ||
115
+ (p.type === `tool-${toolName}` &&
116
+ (p.state === "output-available" || p.state === "output-error")));
73
117
  }
package/dist/index.d.ts CHANGED
@@ -4,7 +4,9 @@ export type { WireDate, ContextMirrorContext, ContextMirrorExecution, ContextMir
4
4
  export { registerContext, getContext, getContextFactory, hasContext, listContexts, type ContextKey, } from "./context.registry.js";
5
5
  export { eventsDomain } from "./schema.js";
6
6
  export { didToolExecute, extractToolCallsFromParts } from "./context.toolcalls.js";
7
- export { INPUT_ITEM_TYPE, INPUT_TEXT_ITEM_TYPE, OUTPUT_ITEM_TYPE, WEB_CHANNEL, AGENT_CHANNEL, EMAIL_CHANNEL, createUserItemFromUIMessages, createAssistantItemFromUIMessages, convertToUIMessage, convertItemToModelMessages, convertItemsToModelMessages, convertModelMessageToItem, type ResponseMessage, } from "./context.events.js";
7
+ export { contextPartSchema, contextPartEnvelopeSchema, contextPartContentSchema, isContextPartEnvelope, parseContextPartEnvelope, normalizePartsForPersistence, } from "./context.parts.js";
8
+ export type { ContextPart, ContextPartEnvelope, ContextPartContent, } from "./context.parts.js";
9
+ export { INPUT_ITEM_TYPE, INPUT_TEXT_ITEM_TYPE, OUTPUT_ITEM_TYPE, WEB_CHANNEL, AGENT_CHANNEL, EMAIL_CHANNEL, createUserItemFromUIMessages, createAssistantItemFromUIMessages, convertToUIMessage, convertItemToModelMessages, convertItemsToModelMessages, convertModelMessageToItem, isContextOutputPart, normalizeContextOutputPart, type ResponseMessage, type ContextOutputPart, type ContextOutputContentPart, } from "./context.events.js";
8
10
  export { CONTEXT_STATUSES, EXECUTION_STATUSES, STEP_STATUSES, STEP_KINDS, ITEM_STATUSES, ITEM_TYPES, CHANNELS, TRACE_EVENT_KINDS, CONTEXT_STREAM_CHUNK_TYPES, STREAM_LIFECYCLE_CHUNK_TYPES, STREAM_TEXT_CHUNK_TYPES, STREAM_REASONING_CHUNK_TYPES, STREAM_ACTION_CHUNK_TYPES, STREAM_SOURCE_CHUNK_TYPES, STREAM_METADATA_CHUNK_TYPES, STREAM_ERROR_CHUNK_TYPES, CONTEXT_TRANSITIONS, EXECUTION_TRANSITIONS, STEP_TRANSITIONS, ITEM_TRANSITIONS, canContextTransition, canExecutionTransition, canStepTransition, canItemTransition, assertContextTransition, assertExecutionTransition, assertStepTransition, assertItemTransition, isContextStreamChunkType, assertContextPartKey, } from "./context.contract.js";
9
11
  export type { Transition, ContextStatus, ExecutionStatus, StepStatus, StepKind, ItemStatus, ItemType, Channel, TraceEventKind, ContextStreamChunkType, ContextTransition, ExecutionTransition, StepTransition, ItemTransition, } from "./context.contract.js";
10
12
  export { DEFAULT_CODEX_TOOL_NAME, DEFAULT_CODEX_MODEL, codexToolInputSchema, buildDefaultCodexNarrative, didCodexToolExecute, createCodexContextBuilder, type CodexContextRuntimeMode, type CodexContextReasoningLevel, type CodexContextRuntime, type CodexContextEnv, type CodexToolInput, type CodexToolOutput, type CodexExecuteArgs, type CodexContextBuilderConfig, type CodexContextBuilder, } from "./codex.js";
package/dist/index.js CHANGED
@@ -2,7 +2,8 @@ export { context, createContext, createAiSdkReactor, createScriptedReactor, Cont
2
2
  export { registerContext, getContext, getContextFactory, hasContext, listContexts, } from "./context.registry.js";
3
3
  export { eventsDomain } from "./schema.js";
4
4
  export { didToolExecute, extractToolCallsFromParts } from "./context.toolcalls.js";
5
- export { INPUT_ITEM_TYPE, INPUT_TEXT_ITEM_TYPE, OUTPUT_ITEM_TYPE, WEB_CHANNEL, AGENT_CHANNEL, EMAIL_CHANNEL, createUserItemFromUIMessages, createAssistantItemFromUIMessages, convertToUIMessage, convertItemToModelMessages, convertItemsToModelMessages, convertModelMessageToItem, } from "./context.events.js";
5
+ export { contextPartSchema, contextPartEnvelopeSchema, contextPartContentSchema, isContextPartEnvelope, parseContextPartEnvelope, normalizePartsForPersistence, } from "./context.parts.js";
6
+ export { INPUT_ITEM_TYPE, INPUT_TEXT_ITEM_TYPE, OUTPUT_ITEM_TYPE, WEB_CHANNEL, AGENT_CHANNEL, EMAIL_CHANNEL, createUserItemFromUIMessages, createAssistantItemFromUIMessages, convertToUIMessage, convertItemToModelMessages, convertItemsToModelMessages, convertModelMessageToItem, isContextOutputPart, normalizeContextOutputPart, } from "./context.events.js";
6
7
  export { CONTEXT_STATUSES, EXECUTION_STATUSES, STEP_STATUSES, STEP_KINDS, ITEM_STATUSES, ITEM_TYPES, CHANNELS, TRACE_EVENT_KINDS, CONTEXT_STREAM_CHUNK_TYPES, STREAM_LIFECYCLE_CHUNK_TYPES, STREAM_TEXT_CHUNK_TYPES, STREAM_REASONING_CHUNK_TYPES, STREAM_ACTION_CHUNK_TYPES, STREAM_SOURCE_CHUNK_TYPES, STREAM_METADATA_CHUNK_TYPES, STREAM_ERROR_CHUNK_TYPES, CONTEXT_TRANSITIONS, EXECUTION_TRANSITIONS, STEP_TRANSITIONS, ITEM_TRANSITIONS, canContextTransition, canExecutionTransition, canStepTransition, canItemTransition, assertContextTransition, assertExecutionTransition, assertStepTransition, assertItemTransition, isContextStreamChunkType, assertContextPartKey, } from "./context.contract.js";
7
8
  export { DEFAULT_CODEX_TOOL_NAME, DEFAULT_CODEX_MODEL, codexToolInputSchema, buildDefaultCodexNarrative, didCodexToolExecute, createCodexContextBuilder, } from "./codex.js";
8
9
  export { useContext, } from "./react.js";
package/dist/schema.js CHANGED
@@ -52,8 +52,9 @@ export const eventsDomain = domain("events")
52
52
  key: i.string().unique().indexed(), // `${stepId}:${idx}`
53
53
  stepId: i.string().indexed(),
54
54
  idx: i.number().indexed(),
55
- type: i.string().optional().indexed(),
56
- part: i.any().optional(),
55
+ type: i.string().optional().indexed(), // canonical part.type
56
+ part: i.json().optional(),
57
+ metadata: i.json().optional(), // provider/model/runtime metadata only
57
58
  updatedAt: i.date().optional(),
58
59
  }),
59
60
  event_trace_events: i.entity({
@@ -20,6 +20,8 @@ export declare class InstantStore implements ContextStore {
20
20
  updateItem(eventId: string, event: ContextItem): Promise<ContextItem>;
21
21
  getItem(eventId: string): Promise<ContextItem | null>;
22
22
  getItems(contextIdentifier: ContextIdentifier): Promise<ContextItem[]>;
23
+ private getExecutionIdForItem;
24
+ private getProjectedPartsForOutputItem;
23
25
  createExecution(contextIdentifier: ContextIdentifier, triggerEventId: string, reactionEventId: string): Promise<{
24
26
  id: string;
25
27
  }>;
@@ -1,10 +1,11 @@
1
1
  import "../polyfills/dom-events.js";
2
2
  import { id, lookup } from "@instantdb/admin";
3
- import { convertItemsToModelMessages } from "../context.events.js";
3
+ import { convertItemToModelMessages } from "../context.events.js";
4
4
  import { assertContextTransition, assertExecutionTransition, assertItemTransition, assertStepTransition, } from "../context.contract.js";
5
5
  export { parseAndStoreDocument } from "./instant.document-parser.js";
6
6
  import { expandEventsWithInstantDocuments } from "./instant.documents.js";
7
7
  export { coerceDocumentTextPages, expandEventsWithInstantDocuments, } from "./instant.documents.js";
8
+ import { mergeContextPartEnvelope, normalizePartsForPersistence, splitContextPartEnvelope, } from "../context.parts.js";
8
9
  function shouldDebugInstantStore() {
9
10
  return (process.env.EKAIROS_CONTEXT_DEBUG === "1" ||
10
11
  process.env.EKAIROS_CONTEXT_DEBUG === "1" ||
@@ -307,6 +308,81 @@ export class InstantStore {
307
308
  }
308
309
  return sortItems((res.event_items ?? []));
309
310
  }
311
+ async getExecutionIdForItem(itemId) {
312
+ const directResult = await this.db.query({
313
+ event_items: {
314
+ $: { where: { id: itemId }, limit: 1 },
315
+ execution: {},
316
+ },
317
+ });
318
+ const directRow = directResult?.event_items?.[0];
319
+ const directExecutionId = directRow?.execution?.id;
320
+ if (typeof directExecutionId === "string" &&
321
+ directExecutionId.trim().length > 0) {
322
+ return directExecutionId;
323
+ }
324
+ const reverseResult = await this.db.query({
325
+ event_executions: {
326
+ $: { where: { "reaction.id": itemId }, limit: 1 },
327
+ },
328
+ });
329
+ const reverseRow = reverseResult?.event_executions?.[0];
330
+ const reverseExecutionId = reverseRow?.id;
331
+ return typeof reverseExecutionId === "string" && reverseExecutionId.trim().length > 0
332
+ ? reverseExecutionId
333
+ : null;
334
+ }
335
+ async getProjectedPartsForOutputItem(itemId) {
336
+ const executionId = await this.getExecutionIdForItem(itemId);
337
+ if (!executionId) {
338
+ return null;
339
+ }
340
+ const stepResult = await this.db.query({
341
+ event_steps: {
342
+ $: {
343
+ where: { "execution.id": executionId },
344
+ limit: 200,
345
+ },
346
+ },
347
+ });
348
+ const steps = sortItems((stepResult?.event_steps ?? [])).sort((a, b) => {
349
+ const ai = typeof a?.iteration === "number" ? a.iteration : 0;
350
+ const bi = typeof b?.iteration === "number" ? b.iteration : 0;
351
+ if (ai !== bi)
352
+ return ai - bi;
353
+ return String(a?.id ?? "").localeCompare(String(b?.id ?? ""));
354
+ });
355
+ if (steps.length === 0) {
356
+ return null;
357
+ }
358
+ const projectedParts = [];
359
+ for (const step of steps) {
360
+ const stepId = typeof step?.id === "string" ? step.id : "";
361
+ if (!stepId)
362
+ continue;
363
+ const partResult = await this.db.query({
364
+ event_parts: {
365
+ $: {
366
+ where: { stepId: stepId },
367
+ limit: 500,
368
+ order: { idx: "asc" },
369
+ },
370
+ },
371
+ });
372
+ const partRows = (partResult?.event_parts ?? []).sort((a, b) => {
373
+ const ai = typeof a?.idx === "number" ? a.idx : 0;
374
+ const bi = typeof b?.idx === "number" ? b.idx : 0;
375
+ if (ai !== bi)
376
+ return ai - bi;
377
+ return 0;
378
+ });
379
+ projectedParts.push(...partRows.map((row) => mergeContextPartEnvelope({
380
+ part: row?.part,
381
+ metadata: row?.metadata,
382
+ })));
383
+ }
384
+ return projectedParts;
385
+ }
310
386
  async createExecution(contextIdentifier, triggerEventId, reactionEventId) {
311
387
  const normalizedTriggerEventId = ensureValidEntityId(triggerEventId, "triggerEventId");
312
388
  const normalizedReactionEventId = ensureValidEntityId(reactionEventId, "reactionEventId");
@@ -433,17 +509,19 @@ export class InstantStore {
433
509
  ]);
434
510
  }
435
511
  async saveStepParts(params) {
436
- const parts = Array.isArray(params.parts) ? params.parts : [];
512
+ const parts = normalizePartsForPersistence(Array.isArray(params.parts) ? params.parts : []);
437
513
  if (parts.length === 0)
438
514
  return;
439
515
  const txs = parts.map((part, idx) => {
440
516
  const key = `${params.stepId}:${idx}`;
517
+ const split = splitContextPartEnvelope(part);
441
518
  return this.db.tx.event_parts[lookup("key", key)]
442
519
  .update({
443
520
  stepId: params.stepId,
444
521
  idx,
445
- type: typeof part?.type === "string" ? String(part.type) : undefined,
446
- part,
522
+ type: typeof split.part?.type === "string" ? String(split.part.type) : undefined,
523
+ part: split.part,
524
+ metadata: split.metadata,
447
525
  updatedAt: new Date(),
448
526
  })
449
527
  .link({ step: params.stepId });
@@ -456,7 +534,24 @@ export class InstantStore {
456
534
  events,
457
535
  derivedEventType: "output",
458
536
  });
459
- return await convertItemsToModelMessages(expanded);
537
+ const messages = [];
538
+ for (const event of expanded) {
539
+ const isOutputItem = event?.type === "output";
540
+ const projectedParts = isOutputItem
541
+ ? await this.getProjectedPartsForOutputItem(String(event?.id ?? ""))
542
+ : null;
543
+ const projectedEvent = projectedParts && projectedParts.length > 0
544
+ ? {
545
+ ...event,
546
+ content: {
547
+ ...(event?.content ?? {}),
548
+ parts: projectedParts,
549
+ },
550
+ }
551
+ : event;
552
+ messages.push(await convertItemToModelMessages(projectedEvent));
553
+ }
554
+ return messages.flat();
460
555
  }
461
556
  }
462
557
  export function createInstantStoreRuntime(params) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ekairos/events",
3
- "version": "1.22.32-beta.development.0",
3
+ "version": "1.22.33-beta.development.0",
4
4
  "description": "Ekairos Events - Context-first workflow runtime",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -116,7 +116,7 @@
116
116
  },
117
117
  "dependencies": {
118
118
  "@ai-sdk/openai": "^2.0.52",
119
- "@ekairos/domain": "^1.22.32-beta.development.0",
119
+ "@ekairos/domain": "^1.22.33-beta.development.0",
120
120
  "@instantdb/admin": "0.22.158",
121
121
  "@instantdb/core": "0.22.142",
122
122
  "@vercel/mcp-adapter": "^1.0.0",