@ekairos/thread 1.22.4-beta.feature-thread-unify.0 → 1.22.4-beta.feature-core-thread-registry-sync.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +7 -1
  2. package/dist/index.d.ts +5 -5
  3. package/dist/index.js +2 -2
  4. package/dist/react.d.ts +2 -18
  5. package/dist/react.js +2 -15
  6. package/dist/reactors/ai-sdk.chunk-map.d.ts +12 -0
  7. package/dist/reactors/ai-sdk.chunk-map.js +143 -0
  8. package/dist/reactors/ai-sdk.reactor.js +5 -1
  9. package/dist/reactors/scripted.reactor.d.ts +2 -2
  10. package/dist/reactors/scripted.reactor.js +3 -2
  11. package/dist/reactors/types.d.ts +6 -6
  12. package/dist/schema.js +10 -9
  13. package/dist/steps/do-thread-stream-step.d.ts +6 -2
  14. package/dist/steps/do-thread-stream-step.js +9 -5
  15. package/dist/steps/reaction.steps.d.ts +1 -1
  16. package/dist/steps/reaction.steps.js +48 -14
  17. package/dist/steps/store.steps.d.ts +10 -11
  18. package/dist/steps/store.steps.js +34 -77
  19. package/dist/steps/stream.steps.d.ts +3 -33
  20. package/dist/steps/stream.steps.js +7 -68
  21. package/dist/steps/trace.steps.js +1 -1
  22. package/dist/stores/instant.documents.d.ts +1 -1
  23. package/dist/stores/instant.documents.js +1 -1
  24. package/dist/stores/instant.store.d.ts +7 -3
  25. package/dist/stores/instant.store.js +32 -86
  26. package/dist/thread.contract.d.ts +16 -8
  27. package/dist/thread.contract.js +61 -19
  28. package/dist/thread.d.ts +1 -1
  29. package/dist/thread.engine.d.ts +13 -9
  30. package/dist/thread.engine.js +463 -84
  31. package/dist/thread.events.d.ts +3 -3
  32. package/dist/thread.events.js +11 -34
  33. package/dist/thread.reactor.d.ts +1 -1
  34. package/dist/thread.store.d.ts +9 -9
  35. package/dist/thread.stream.d.ts +100 -33
  36. package/dist/thread.stream.js +72 -63
  37. package/package.json +3 -2
@@ -1,12 +1,12 @@
1
1
  import type { UIMessageChunk } from "ai";
2
2
  import type { ThreadEnvironment } from "../thread.config.js";
3
- import type { ThreadItem, ContextIdentifier, StoredContext } from "../thread.store.js";
3
+ import type { ThreadItem, ContextIdentifier, StoredContext, ContextStatus } from "../thread.store.js";
4
4
  export type ThreadReviewRequest = {
5
5
  toolCallId: string;
6
6
  toolName?: string;
7
7
  };
8
8
  /**
9
- * Initializes/ensures the story context exists and emits a single `data-context-id` chunk.
9
+ * Initializes/ensures the story context exists.
10
10
  *
11
11
  * This is the "context init" boundary for the story engine.
12
12
  */
@@ -18,13 +18,8 @@ export declare function initializeContext<C>(env: ThreadEnvironment, contextIden
18
18
  isNew: boolean;
19
19
  }>;
20
20
  export declare function updateContextContent<C>(env: ThreadEnvironment, contextIdentifier: ContextIdentifier, content: C): Promise<StoredContext<C>>;
21
- export declare function updateContextStatus(env: ThreadEnvironment, contextIdentifier: ContextIdentifier, status: "open" | "streaming" | "closed"): Promise<void>;
21
+ export declare function updateContextStatus(env: ThreadEnvironment, contextIdentifier: ContextIdentifier, status: ContextStatus): Promise<void>;
22
22
  export declare function saveTriggerItem(env: ThreadEnvironment, contextIdentifier: ContextIdentifier, event: ThreadItem): Promise<ThreadItem>;
23
- export declare function emitContextIdChunk(params: {
24
- env: ThreadEnvironment;
25
- contextId: string;
26
- writable?: WritableStream<UIMessageChunk>;
27
- }): Promise<void>;
28
23
  export declare function saveTriggerAndCreateExecution(params: {
29
24
  env: ThreadEnvironment;
30
25
  contextIdentifier: ContextIdentifier;
@@ -67,7 +62,6 @@ export declare function createThreadStep(params: {
67
62
  iteration: number;
68
63
  }): Promise<{
69
64
  stepId: string;
70
- eventId: string;
71
65
  }>;
72
66
  export declare function updateThreadStep(params: {
73
67
  env: ThreadEnvironment;
@@ -77,8 +71,13 @@ export declare function updateThreadStep(params: {
77
71
  iteration?: number;
78
72
  patch: {
79
73
  status?: "running" | "completed" | "failed";
80
- toolCalls?: any;
81
- toolExecutionResults?: any;
74
+ kind?: "message" | "action_execute" | "action_result";
75
+ actionName?: string;
76
+ actionInput?: unknown;
77
+ actionOutput?: unknown;
78
+ actionError?: string;
79
+ actionRequests?: any;
80
+ actionResults?: any;
82
81
  continueLoop?: boolean;
83
82
  errorText?: string;
84
83
  };
@@ -31,15 +31,13 @@ function parseRunIdFromTriggerId(triggerEventId) {
31
31
  return parsed || undefined;
32
32
  }
33
33
  async function resolveWorkflowRunId(params) {
34
- const meta = await readWorkflowMetadata();
35
- let runId = meta && meta.workflowRunId !== undefined && meta.workflowRunId !== null
36
- ? String(meta.workflowRunId)
34
+ const envRunId = params.env?.workflowRunId;
35
+ let runId = typeof envRunId === "string" && envRunId.trim()
36
+ ? envRunId.trim()
37
37
  : "";
38
- if (!runId) {
39
- const envRunId = params.env?.workflowRunId;
40
- if (typeof envRunId === "string" && envRunId.trim()) {
41
- runId = envRunId.trim();
42
- }
38
+ const meta = runId ? null : await readWorkflowMetadata();
39
+ if (!runId && meta && meta.workflowRunId !== undefined && meta.workflowRunId !== null) {
40
+ runId = String(meta.workflowRunId);
43
41
  }
44
42
  if (!runId && params.triggerEventId) {
45
43
  const parsed = parseRunIdFromTriggerId(params.triggerEventId);
@@ -65,13 +63,11 @@ async function resolveWorkflowRunId(params) {
65
63
  return { runId: runId || undefined, meta };
66
64
  }
67
65
  function inferDirection(item) {
68
- const type = typeof item?.type === "string" ? item.type : "";
69
- if (type.startsWith("output") || type.startsWith("tool") || type.startsWith("assistant")) {
70
- return "outbound";
71
- }
72
- if (type.startsWith("input") || type.startsWith("user")) {
66
+ const type = typeof item?.type === "string" ? String(item.type) : "";
67
+ if (type === "input")
73
68
  return "inbound";
74
- }
69
+ if (type === "output")
70
+ return "outbound";
75
71
  return undefined;
76
72
  }
77
73
  function shouldDebugThreadStoreSteps() {
@@ -107,13 +103,13 @@ function logStepDebug(message, payload) {
107
103
  console.error(`[thread][store.steps] ${message}`, payload);
108
104
  }
109
105
  /**
110
- * Initializes/ensures the story context exists and emits a single `data-context-id` chunk.
106
+ * Initializes/ensures the story context exists.
111
107
  *
112
108
  * This is the "context init" boundary for the story engine.
113
109
  */
114
110
  export async function initializeContext(env, contextIdentifier, opts) {
115
111
  "use step";
116
- const { getThreadRuntime } = await import("@ekairos/thread/runtime");
112
+ const { getThreadRuntime } = await import("../runtime.js");
117
113
  const runtime = await getThreadRuntime(env);
118
114
  const { store, db } = runtime;
119
115
  // Detect creation explicitly so the engine can run onContextCreated hooks.
@@ -132,21 +128,6 @@ export async function initializeContext(env, contextIdentifier, opts) {
132
128
  result = { context: created, isNew: true };
133
129
  }
134
130
  }
135
- // If we're running in a non-streaming context (e.g. tests or headless usage),
136
- // we skip writing stream chunks entirely.
137
- if (!opts?.silent && opts?.writable) {
138
- const writer = opts.writable.getWriter();
139
- try {
140
- await writer.write({
141
- type: "data-context-id",
142
- id: String(result.context.id),
143
- data: { contextId: String(result.context.id) },
144
- });
145
- }
146
- finally {
147
- writer.releaseLock();
148
- }
149
- }
150
131
  const { runId } = await resolveWorkflowRunId({ env, db });
151
132
  if (runId) {
152
133
  await maybeWriteTraceEvents(env, [
@@ -168,42 +149,26 @@ export async function initializeContext(env, contextIdentifier, opts) {
168
149
  }
169
150
  export async function updateContextContent(env, contextIdentifier, content) {
170
151
  "use step";
171
- const { getThreadRuntime } = await import("@ekairos/thread/runtime");
152
+ const { getThreadRuntime } = await import("../runtime.js");
172
153
  const { store } = await getThreadRuntime(env);
173
154
  return await store.updateContextContent(contextIdentifier, content);
174
155
  }
175
156
  export async function updateContextStatus(env, contextIdentifier, status) {
176
157
  "use step";
177
- const { getThreadRuntime } = await import("@ekairos/thread/runtime");
158
+ const { getThreadRuntime } = await import("../runtime.js");
178
159
  const { store } = await getThreadRuntime(env);
179
160
  await store.updateContextStatus(contextIdentifier, status);
180
161
  }
181
162
  export async function saveTriggerItem(env, contextIdentifier, event) {
182
163
  "use step";
183
- const { getThreadRuntime } = await import("@ekairos/thread/runtime");
164
+ const { getThreadRuntime } = await import("../runtime.js");
184
165
  const { store } = await getThreadRuntime(env);
185
166
  const saved = await store.saveItem(contextIdentifier, event);
186
167
  return saved;
187
168
  }
188
- export async function emitContextIdChunk(params) {
189
- "use step";
190
- if (!params.writable)
191
- return;
192
- const writer = params.writable.getWriter();
193
- try {
194
- await writer.write({
195
- type: "data-context-id",
196
- id: String(params.contextId),
197
- data: { contextId: String(params.contextId) },
198
- });
199
- }
200
- finally {
201
- writer.releaseLock();
202
- }
203
- }
204
169
  export async function saveTriggerAndCreateExecution(params) {
205
170
  "use step";
206
- const { getThreadRuntime } = await import("@ekairos/thread/runtime");
171
+ const { getThreadRuntime } = await import("../runtime.js");
207
172
  const runtime = await getThreadRuntime(params.env);
208
173
  const { store, db } = runtime;
209
174
  logStepDebug("saveTriggerAndCreateExecution:start", {
@@ -229,18 +194,6 @@ export async function saveTriggerAndCreateExecution(params) {
229
194
  const reactionEventId = typeof uuid === "string"
230
195
  ? uuid
231
196
  : `${Date.now()}-${Math.random().toString(16).slice(2)}`;
232
- try {
233
- await store.updateContextStatus(params.contextIdentifier, "streaming");
234
- }
235
- catch (error) {
236
- logStepDebug("saveTriggerAndCreateExecution:updateContextStatus:error", {
237
- contextIdentifier: summarizeContextIdentifierForLog(params.contextIdentifier),
238
- triggerEventId: saved.id,
239
- reactionEventId,
240
- error: summarizeStepError(error),
241
- });
242
- throw error;
243
- }
244
197
  let execution;
245
198
  try {
246
199
  execution = await store.createExecution(params.contextIdentifier, saved.id, reactionEventId);
@@ -342,7 +295,7 @@ export async function saveTriggerAndCreateExecution(params) {
342
295
  }
343
296
  export async function saveReactionItem(env, contextIdentifier, event, opts) {
344
297
  "use step";
345
- const { getThreadRuntime } = await import("@ekairos/thread/runtime");
298
+ const { getThreadRuntime } = await import("../runtime.js");
346
299
  const runtime = await getThreadRuntime(env);
347
300
  const { store, db } = runtime;
348
301
  const saved = await store.saveItem(contextIdentifier, event);
@@ -409,7 +362,7 @@ export async function saveReactionItem(env, contextIdentifier, event, opts) {
409
362
  }
410
363
  export async function updateItem(env, eventId, event, opts) {
411
364
  "use step";
412
- const { getThreadRuntime } = await import("@ekairos/thread/runtime");
365
+ const { getThreadRuntime } = await import("../runtime.js");
413
366
  const runtime = await getThreadRuntime(env);
414
367
  const { store, db } = runtime;
415
368
  const saved = await store.updateItem(eventId, event);
@@ -439,26 +392,25 @@ export async function updateItem(env, eventId, event, opts) {
439
392
  }
440
393
  export async function createExecution(env, contextIdentifier, triggerEventId, reactionEventId) {
441
394
  "use step";
442
- const { getThreadRuntime } = await import("@ekairos/thread/runtime");
395
+ const { getThreadRuntime } = await import("../runtime.js");
443
396
  const { store } = await getThreadRuntime(env);
444
397
  return await store.createExecution(contextIdentifier, triggerEventId, reactionEventId);
445
398
  }
446
399
  export async function createReactionItem(params) {
447
400
  "use step";
448
- const { getThreadRuntime } = await import("@ekairos/thread/runtime");
401
+ const { getThreadRuntime } = await import("../runtime.js");
449
402
  const { store } = await getThreadRuntime(params.env);
450
403
  // Generate a new reaction event id inside the step boundary.
451
404
  const uuid = globalThis.crypto?.randomUUID?.();
452
405
  const reactionEventId = typeof uuid === "string"
453
406
  ? uuid
454
407
  : `${Date.now()}-${Math.random().toString(16).slice(2)}`;
455
- await store.updateContextStatus(params.contextIdentifier, "streaming");
456
408
  const execution = await store.createExecution(params.contextIdentifier, params.triggerEventId, reactionEventId);
457
409
  return { reactionEventId, executionId: execution.id };
458
410
  }
459
411
  export async function completeExecution(env, contextIdentifier, executionId, status) {
460
412
  "use step";
461
- const { getThreadRuntime } = await import("@ekairos/thread/runtime");
413
+ const { getThreadRuntime } = await import("../runtime.js");
462
414
  const runtime = await getThreadRuntime(env);
463
415
  const { store, db } = runtime;
464
416
  await store.completeExecution(contextIdentifier, executionId, status);
@@ -488,7 +440,7 @@ export async function completeExecution(env, contextIdentifier, executionId, sta
488
440
  }
489
441
  export async function updateExecutionWorkflowRun(params) {
490
442
  "use step";
491
- const { getThreadRuntime } = await import("@ekairos/thread/runtime");
443
+ const { getThreadRuntime } = await import("../runtime.js");
492
444
  const runtime = await getThreadRuntime(params.env);
493
445
  const db = runtime?.db;
494
446
  if (db) {
@@ -502,17 +454,17 @@ export async function updateExecutionWorkflowRun(params) {
502
454
  }
503
455
  export async function createThreadStep(params) {
504
456
  "use step";
505
- const { getThreadRuntime } = await import("@ekairos/thread/runtime");
457
+ const { getThreadRuntime } = await import("../runtime.js");
506
458
  const { store } = await getThreadRuntime(params.env);
507
459
  const res = await store.createStep({
508
460
  executionId: params.executionId,
509
461
  iteration: params.iteration,
510
462
  });
511
- return { stepId: res.id, eventId: res.eventId };
463
+ return { stepId: res.id };
512
464
  }
513
465
  export async function updateThreadStep(params) {
514
466
  "use step";
515
- const { getThreadRuntime } = await import("@ekairos/thread/runtime");
467
+ const { getThreadRuntime } = await import("../runtime.js");
516
468
  const runtime = await getThreadRuntime(params.env);
517
469
  const { store, db } = runtime;
518
470
  await store.updateStep(params.stepId, {
@@ -536,9 +488,14 @@ export async function updateThreadStep(params) {
536
488
  stepId: String(params.stepId),
537
489
  payload: {
538
490
  status: params.patch.status,
491
+ kind: params.patch.kind,
492
+ actionName: params.patch.actionName,
493
+ actionInput: params.patch.actionInput,
494
+ actionOutput: params.patch.actionOutput,
495
+ actionError: params.patch.actionError,
539
496
  iteration: params.iteration,
540
- toolCalls: params.patch.toolCalls,
541
- toolExecutionResults: params.patch.toolExecutionResults,
497
+ actionRequests: params.patch.actionRequests,
498
+ actionResults: params.patch.actionResults,
542
499
  continueLoop: params.patch.continueLoop,
543
500
  errorText: params.patch.errorText,
544
501
  },
@@ -548,13 +505,13 @@ export async function updateThreadStep(params) {
548
505
  }
549
506
  export async function linkItemToExecutionStep(params) {
550
507
  "use step";
551
- const { getThreadRuntime } = await import("@ekairos/thread/runtime");
508
+ const { getThreadRuntime } = await import("../runtime.js");
552
509
  const { store } = await getThreadRuntime(params.env);
553
510
  await store.linkItemToExecution({ itemId: params.itemId, executionId: params.executionId });
554
511
  }
555
512
  export async function saveThreadPartsStep(params) {
556
513
  "use step";
557
- const { getThreadRuntime } = await import("@ekairos/thread/runtime");
514
+ const { getThreadRuntime } = await import("../runtime.js");
558
515
  const runtime = await getThreadRuntime(params.env);
559
516
  const { store, db } = runtime;
560
517
  await store.saveStepParts({ stepId: params.stepId, parts: params.parts });
@@ -1,37 +1,7 @@
1
1
  import type { UIMessageChunk } from "ai";
2
- export declare function writeContextSubstate(params: {
3
- /**
4
- * Ephemeral substate key for the UI (thread engine internal state).
5
- *
6
- * - Provide a string key like "actions" to set it
7
- * - Provide null to clear it
8
- */
9
- key: string | null;
10
- transient?: boolean;
11
- writable?: WritableStream<UIMessageChunk>;
12
- }): Promise<void>;
13
- export declare function writeContextIdChunk(params: {
14
- contextId: string;
15
- writable?: WritableStream<UIMessageChunk>;
16
- }): Promise<void>;
17
- export declare function writeThreadPing(params: {
18
- /**
19
- * Simple ping event to validate that the workflow stream is alive.
20
- * This is intentionally generic so clients can ignore it safely.
21
- */
22
- label?: string;
23
- writable?: WritableStream<UIMessageChunk>;
24
- }): Promise<void>;
25
- export declare function writeToolOutputs(params: {
26
- results: Array<{
27
- toolCallId: string;
28
- success: true;
29
- output: unknown;
30
- } | {
31
- toolCallId: string;
32
- success: false;
33
- errorText: string;
34
- }>;
2
+ import type { ThreadStreamEvent } from "../thread.stream.js";
3
+ export declare function writeThreadEvents(params: {
4
+ events: ThreadStreamEvent[];
35
5
  writable?: WritableStream<UIMessageChunk>;
36
6
  }): Promise<void>;
37
7
  export declare function closeThreadStream(params: {
@@ -1,76 +1,15 @@
1
- export async function writeContextSubstate(params) {
1
+ export async function writeThreadEvents(params) {
2
2
  "use step";
3
3
  const writable = params.writable;
4
- if (!writable)
5
- return;
6
- const writer = writable.getWriter();
7
- try {
8
- await writer.write({
9
- type: "data-context-substate",
10
- data: { key: params.key },
11
- transient: params.transient ?? true,
12
- });
13
- }
14
- finally {
15
- writer.releaseLock();
16
- }
17
- }
18
- export async function writeContextIdChunk(params) {
19
- "use step";
20
- const writable = params.writable;
21
- if (!writable)
22
- return;
23
- const writer = writable.getWriter();
24
- try {
25
- await writer.write({
26
- type: "data-context-id",
27
- id: params.contextId,
28
- data: { contextId: params.contextId },
29
- });
30
- }
31
- finally {
32
- writer.releaseLock();
33
- }
34
- }
35
- export async function writeThreadPing(params) {
36
- "use step";
37
- const writable = params.writable;
38
- if (!writable)
39
- return;
40
- const writer = writable.getWriter();
41
- try {
42
- await writer.write({
43
- type: "data-thread-ping",
44
- data: { label: params.label ?? "thread-ping" },
45
- transient: true,
46
- });
47
- }
48
- finally {
49
- writer.releaseLock();
50
- }
51
- }
52
- export async function writeToolOutputs(params) {
53
- "use step";
54
- const writable = params.writable;
55
- if (!writable)
4
+ if (!writable || !params.events.length)
56
5
  return;
57
6
  const writer = writable.getWriter();
58
7
  try {
59
- for (const r of params.results) {
60
- if (r.success) {
61
- await writer.write({
62
- type: "tool-output-available",
63
- toolCallId: r.toolCallId,
64
- output: r.output,
65
- });
66
- }
67
- else {
68
- await writer.write({
69
- type: "tool-output-error",
70
- toolCallId: r.toolCallId,
71
- errorText: r.errorText,
72
- });
73
- }
8
+ for (const event of params.events) {
9
+ await writer.write({
10
+ type: `data-${String(event.type)}`,
11
+ data: event,
12
+ });
74
13
  }
75
14
  }
76
15
  finally {
@@ -84,7 +84,7 @@ export async function writeThreadTraceEvents(params) {
84
84
  const strict = envTrace?.strict === true || process.env.EKAIROS_TRACES_STRICT === "1";
85
85
  // 1) Local trace persistence (InstantDB source of truth).
86
86
  try {
87
- const { getThreadRuntime } = await import("@ekairos/thread/runtime");
87
+ const { getThreadRuntime } = await import("../runtime.js");
88
88
  const runtime = await getThreadRuntime(params.env);
89
89
  const db = runtime?.db;
90
90
  if (db) {
@@ -10,7 +10,7 @@ export declare function expandEventsWithInstantDocuments(params: {
10
10
  */
11
11
  maxChars?: number;
12
12
  /**
13
- * Event type used for derived document text. Defaults to "output_text".
13
+ * Event type used for derived document text. Defaults to "output".
14
14
  */
15
15
  derivedEventType?: ThreadItem["type"];
16
16
  }): Promise<ThreadItem[]>;
@@ -72,7 +72,7 @@ async function ensureDocumentParsedForFile(db, params) {
72
72
  export async function expandEventsWithInstantDocuments(params) {
73
73
  const db = params.db;
74
74
  const maxChars = typeof params.maxChars === "number" ? params.maxChars : 120000;
75
- const derivedEventType = params.derivedEventType ?? "output_text";
75
+ const derivedEventType = params.derivedEventType ?? "output";
76
76
  const out = [];
77
77
  for (const event of params.events) {
78
78
  const parts = event?.content?.parts;
@@ -44,12 +44,16 @@ export declare class InstantStore implements ThreadStore {
44
44
  iteration: number;
45
45
  }): Promise<{
46
46
  id: string;
47
- eventId: string;
48
47
  }>;
49
48
  updateStep(stepId: string, patch: Partial<{
50
49
  status: "running" | "completed" | "failed";
51
- toolCalls: any;
52
- toolExecutionResults: any;
50
+ kind: "message" | "action_execute" | "action_result";
51
+ actionName: string;
52
+ actionInput: unknown;
53
+ actionOutput: unknown;
54
+ actionError: string;
55
+ actionRequests: any;
56
+ actionResults: any;
53
57
  continueLoop: boolean;
54
58
  errorText: string;
55
59
  updatedAt: Date;