@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
@@ -121,7 +121,7 @@ export class InstantStore {
121
121
  id: String(row?.id ?? ""),
122
122
  key: typeof row?.key === "string" ? row.key : null,
123
123
  name: typeof row?.name === "string" ? row.name : null,
124
- status: (typeof row?.status === "string" ? row.status : "open"),
124
+ status: (typeof row?.status === "string" ? row.status : "idle"),
125
125
  createdAt: row?.createdAt instanceof Date ? row.createdAt : new Date(row?.createdAt ?? Date.now()),
126
126
  updatedAt: row?.updatedAt instanceof Date ? row.updatedAt : row?.updatedAt ? new Date(row.updatedAt) : undefined,
127
127
  };
@@ -253,7 +253,7 @@ export class InstantStore {
253
253
  this.db.tx.thread_threads[threadId].create({
254
254
  createdAt: new Date(),
255
255
  updatedAt: new Date(),
256
- status: "open",
256
+ status: "idle",
257
257
  key,
258
258
  }),
259
259
  ]);
@@ -424,7 +424,7 @@ export class InstantStore {
424
424
  ];
425
425
  if (context.threadId) {
426
426
  const thread = await this.getThread({ id: context.threadId });
427
- const nextThreadStatus = (status === "closed" ? "closed" : status);
427
+ const nextThreadStatus = "idle";
428
428
  if (thread && thread.status !== nextThreadStatus) {
429
429
  assertThreadTransition(thread.status, nextThreadStatus);
430
430
  }
@@ -484,10 +484,10 @@ export class InstantStore {
484
484
  });
485
485
  throw error;
486
486
  }
487
- const persisted = await this.getItem(event.id);
488
- if (!persisted)
489
- throw new Error("InstantStore: failed to read event after save");
490
- return persisted;
487
+ return {
488
+ ...event,
489
+ status: "stored",
490
+ };
491
491
  }
492
492
  async updateItem(eventId, event) {
493
493
  const current = await this.getItem(eventId);
@@ -495,10 +495,11 @@ export class InstantStore {
495
495
  assertItemTransition(current.status, event.status);
496
496
  }
497
497
  await this.db.transact([this.db.tx.thread_items[eventId].update(event)]);
498
- const persisted = await this.getItem(eventId);
499
- if (!persisted)
500
- throw new Error("InstantStore: event not found after update");
501
- return persisted;
498
+ return {
499
+ ...current,
500
+ ...event,
501
+ id: eventId,
502
+ };
502
503
  }
503
504
  async getItem(eventId) {
504
505
  const res = await this.db.query({
@@ -559,6 +560,13 @@ export class InstantStore {
559
560
  status: "executing",
560
561
  });
561
562
  const txs = [execCreate];
563
+ if (context.status !== "open") {
564
+ assertContextTransition(context.status, "open");
565
+ txs.push(this.db.tx.thread_contexts[context.id].update({
566
+ status: "open",
567
+ updatedAt: new Date(),
568
+ }));
569
+ }
562
570
  txs.push(this.db.tx.thread_executions[executionId].link({ context: context.id }));
563
571
  txs.push(this.db.tx.thread_executions[executionId].link({ thread: thread.id }));
564
572
  txs.push(this.db.tx.thread_contexts[context.id].link({ currentExecution: executionId }));
@@ -603,17 +611,19 @@ export class InstantStore {
603
611
  if (currentExecutionStatus !== status) {
604
612
  assertExecutionTransition(currentExecutionStatus, status);
605
613
  }
606
- if (context.status !== "open") {
607
- assertContextTransition(context.status, "open");
614
+ if (context.status !== "closed") {
615
+ assertContextTransition(context.status, "closed");
608
616
  }
609
- const nextThreadStatus = status === "failed" ? "failed" : "open";
617
+ const nextThreadStatus = "idle";
610
618
  if (thread.status !== nextThreadStatus) {
611
619
  assertThreadTransition(thread.status, nextThreadStatus);
612
620
  }
613
621
  const txs = [];
614
622
  txs.push(this.db.tx.thread_executions[executionId].update({ status, updatedAt: new Date() }));
615
- // Update context status back to "open" when execution completes
616
- txs.push(this.db.tx.thread_contexts[context.id].update({ status: "open", updatedAt: new Date() }));
623
+ txs.push(this.db.tx.thread_contexts[context.id].update({
624
+ status: "closed",
625
+ updatedAt: new Date(),
626
+ }));
617
627
  txs.push(this.db.tx.thread_threads[thread.id].update({
618
628
  status: nextThreadStatus,
619
629
  updatedAt: new Date(),
@@ -622,14 +632,11 @@ export class InstantStore {
622
632
  }
623
633
  async createStep(params) {
624
634
  const stepId = id();
625
- const eventId = id();
626
635
  const txs = [
627
636
  this.db.tx.thread_steps[stepId].create({
628
637
  createdAt: new Date(),
629
638
  status: "running",
630
639
  iteration: params.iteration,
631
- executionId: params.executionId,
632
- eventId,
633
640
  }),
634
641
  ];
635
642
  txs.push(this.db.tx.thread_steps[stepId].link({ execution: params.executionId }));
@@ -643,14 +650,13 @@ export class InstantStore {
643
650
  executionId: params.executionId,
644
651
  iteration: params.iteration,
645
652
  stepId,
646
- eventId,
647
653
  },
648
654
  txs,
649
655
  error,
650
656
  });
651
657
  throw error;
652
658
  }
653
- return { id: stepId, eventId };
659
+ return { id: stepId };
654
660
  }
655
661
  async updateStep(stepId, patch) {
656
662
  if (patch.status) {
@@ -697,76 +703,16 @@ export class InstantStore {
697
703
  await this.db.transact(txs);
698
704
  }
699
705
  async itemsToModelMessages(events) {
700
- // Prefer parts-first reconstruction from thread_parts via the producing step.
701
- const eventIds = events.map((e) => String(e.id)).filter(Boolean);
702
- let eventsWithParts = events;
703
- if (eventIds.length) {
704
- try {
705
- // 1) Get steps for these events (eventId is stored on thread_steps)
706
- const stepsRes = await this.db.query({
707
- thread_steps: {
708
- $: {
709
- where: { eventId: { $in: eventIds } },
710
- fields: ["id", "eventId"],
711
- limit: 2000,
712
- },
713
- },
714
- });
715
- const steps = stepsRes.thread_steps ?? [];
716
- const stepIdByEventId = new Map();
717
- const stepIds = [];
718
- for (const s of steps) {
719
- const sid = String(s.id);
720
- const eid = String(s.eventId);
721
- if (sid && eid) {
722
- stepIdByEventId.set(eid, sid);
723
- stepIds.push(sid);
724
- }
725
- }
726
- // 2) Load parts for those steps
727
- const partsByStepId = new Map();
728
- if (stepIds.length) {
729
- const partsRes = await this.db.query({
730
- thread_parts: {
731
- $: {
732
- where: { stepId: { $in: stepIds } },
733
- order: { idx: "asc" },
734
- limit: 5000,
735
- },
736
- },
737
- });
738
- const rows = partsRes.thread_parts ?? [];
739
- for (const r of rows) {
740
- const sid = String(r.stepId);
741
- const arr = partsByStepId.get(sid) ?? [];
742
- arr.push(r.part);
743
- partsByStepId.set(sid, arr);
744
- }
745
- }
746
- // 3) Attach parts onto events
747
- eventsWithParts = events.map((e) => {
748
- const eid = String(e.id);
749
- const sid = stepIdByEventId.get(eid);
750
- if (!sid)
751
- return e;
752
- const parts = partsByStepId.get(sid);
753
- if (!parts || parts.length === 0)
754
- return e;
755
- return { ...e, content: { ...(e?.content ?? {}), parts } };
756
- });
757
- }
758
- catch {
759
- // If schema not pushed yet (or table absent), fallback to embedded parts.
760
- eventsWithParts = events;
761
- }
762
- }
706
+ // `thread_steps` only links to execution.
707
+ // Item reconstruction uses embedded `item.content.parts` as source for model messages.
708
+ const eventsWithParts = events;
763
709
  // Default behavior for Instant-backed stories:
764
- // - Expand file parts into derived `output_text` events (persisting parsed content into document_documents)
710
+ // - Expand file parts into derived `message` items (persisting parsed content into document_documents)
765
711
  // - Then convert expanded events to model messages
766
712
  const expanded = await expandEventsWithInstantDocuments({
767
713
  db: this.db,
768
714
  events: eventsWithParts,
769
- derivedEventType: "output_text",
715
+ derivedEventType: "output",
770
716
  });
771
717
  return await convertItemsToModelMessages(expanded);
772
718
  }
@@ -2,28 +2,36 @@ export type Transition<From extends string, To extends string> = {
2
2
  from: From;
3
3
  to: To;
4
4
  };
5
- export declare const THREAD_STATUSES: readonly ["open", "streaming", "closed", "failed"];
5
+ export declare const THREAD_STATUSES: readonly ["idle", "streaming"];
6
6
  export type ThreadThreadStatus = (typeof THREAD_STATUSES)[number];
7
- export declare const THREAD_CONTEXT_STATUSES: readonly ["open", "streaming", "closed"];
7
+ export declare const THREAD_CONTEXT_STATUSES: readonly ["open", "closed"];
8
8
  export type ThreadContextStatus = (typeof THREAD_CONTEXT_STATUSES)[number];
9
9
  export declare const THREAD_EXECUTION_STATUSES: readonly ["executing", "completed", "failed"];
10
10
  export type ThreadExecutionStatus = (typeof THREAD_EXECUTION_STATUSES)[number];
11
11
  export declare const THREAD_STEP_STATUSES: readonly ["running", "completed", "failed"];
12
12
  export type ThreadStepStatus = (typeof THREAD_STEP_STATUSES)[number];
13
+ export declare const THREAD_STEP_KINDS: readonly ["message", "action_execute", "action_result"];
14
+ export type ThreadStepKind = (typeof THREAD_STEP_KINDS)[number];
13
15
  export declare const THREAD_ITEM_STATUSES: readonly ["stored", "pending", "completed"];
14
16
  export type ThreadItemStatus = (typeof THREAD_ITEM_STATUSES)[number];
15
- export declare const THREAD_ITEM_TYPES: readonly ["input_text", "output_text", "ekairos:system"];
17
+ export declare const THREAD_ITEM_TYPES: readonly ["input", "output"];
16
18
  export type ThreadItemType = (typeof THREAD_ITEM_TYPES)[number];
17
19
  export declare const THREAD_CHANNELS: readonly ["web", "whatsapp", "email"];
18
20
  export type ThreadChannel = (typeof THREAD_CHANNELS)[number];
19
21
  export declare const THREAD_TRACE_EVENT_KINDS: readonly ["workflow.run", "workflow.step", "thread.run", "thread.context", "thread.execution", "thread.item", "thread.review", "thread.step", "thread.part", "thread.llm"];
20
22
  export type ThreadTraceEventKind = (typeof THREAD_TRACE_EVENT_KINDS)[number];
21
- export declare const THREAD_STREAM_CHUNK_TYPES: readonly ["data-context-id", "data-context-substate", "data-thread-ping", "tool-output-available", "tool-output-error", "finish"];
23
+ export declare const THREAD_STREAM_LIFECYCLE_CHUNK_TYPES: readonly ["chunk.start", "chunk.start_step", "chunk.finish_step", "chunk.finish"];
24
+ export declare const THREAD_STREAM_TEXT_CHUNK_TYPES: readonly ["chunk.text_start", "chunk.text_delta", "chunk.text_end"];
25
+ export declare const THREAD_STREAM_REASONING_CHUNK_TYPES: readonly ["chunk.reasoning_start", "chunk.reasoning_delta", "chunk.reasoning_end"];
26
+ export declare const THREAD_STREAM_ACTION_CHUNK_TYPES: readonly ["chunk.action_input_start", "chunk.action_input_delta", "chunk.action_input_available", "chunk.action_output_available", "chunk.action_output_error"];
27
+ export declare const THREAD_STREAM_SOURCE_CHUNK_TYPES: readonly ["chunk.source_url", "chunk.source_document", "chunk.file"];
28
+ export declare const THREAD_STREAM_METADATA_CHUNK_TYPES: readonly ["chunk.message_metadata", "chunk.response_metadata"];
29
+ export declare const THREAD_STREAM_ERROR_CHUNK_TYPES: readonly ["chunk.error", "chunk.unknown"];
30
+ export declare const THREAD_STREAM_CHUNK_TYPES: readonly ["chunk.start", "chunk.start_step", "chunk.finish_step", "chunk.finish", "chunk.text_start", "chunk.text_delta", "chunk.text_end", "chunk.reasoning_start", "chunk.reasoning_delta", "chunk.reasoning_end", "chunk.action_input_start", "chunk.action_input_delta", "chunk.action_input_available", "chunk.action_output_available", "chunk.action_output_error", "chunk.source_url", "chunk.source_document", "chunk.file", "chunk.message_metadata", "chunk.response_metadata", "chunk.error", "chunk.unknown"];
22
31
  export type ThreadStreamChunkType = (typeof THREAD_STREAM_CHUNK_TYPES)[number];
23
- export declare const THREAD_CONTEXT_SUBSTATE_KEYS: readonly ["actions"];
24
- export type ThreadContextSubstateKey = (typeof THREAD_CONTEXT_SUBSTATE_KEYS)[number];
25
- export type ThreadTransition = Transition<"open" | "streaming" | "failed", "open" | "streaming" | "closed" | "failed">;
26
- export type ContextTransition = Transition<"open" | "streaming", "streaming" | "open" | "closed">;
32
+ export declare function isThreadStreamChunkType(value: string): value is ThreadStreamChunkType;
33
+ export type ThreadTransition = Transition<"idle" | "streaming", "idle" | "streaming">;
34
+ export type ContextTransition = Transition<"open" | "closed", "open" | "closed">;
27
35
  export type ExecutionTransition = Transition<"executing", "completed" | "failed">;
28
36
  export type StepTransition = Transition<"running", "completed" | "failed">;
29
37
  export type ItemTransition = Transition<"stored" | "pending", "pending" | "completed">;
@@ -1,9 +1,17 @@
1
- export const THREAD_STATUSES = ["open", "streaming", "closed", "failed"];
2
- export const THREAD_CONTEXT_STATUSES = ["open", "streaming", "closed"];
1
+ export const THREAD_STATUSES = ["idle", "streaming"];
2
+ export const THREAD_CONTEXT_STATUSES = ["open", "closed"];
3
3
  export const THREAD_EXECUTION_STATUSES = ["executing", "completed", "failed"];
4
4
  export const THREAD_STEP_STATUSES = ["running", "completed", "failed"];
5
+ export const THREAD_STEP_KINDS = [
6
+ "message",
7
+ "action_execute",
8
+ "action_result",
9
+ ];
5
10
  export const THREAD_ITEM_STATUSES = ["stored", "pending", "completed"];
6
- export const THREAD_ITEM_TYPES = ["input_text", "output_text", "ekairos:system"];
11
+ export const THREAD_ITEM_TYPES = [
12
+ "input",
13
+ "output",
14
+ ];
7
15
  export const THREAD_CHANNELS = ["web", "whatsapp", "email"];
8
16
  export const THREAD_TRACE_EVENT_KINDS = [
9
17
  "workflow.run",
@@ -17,27 +25,61 @@ export const THREAD_TRACE_EVENT_KINDS = [
17
25
  "thread.part",
18
26
  "thread.llm",
19
27
  ];
28
+ export const THREAD_STREAM_LIFECYCLE_CHUNK_TYPES = [
29
+ "chunk.start",
30
+ "chunk.start_step",
31
+ "chunk.finish_step",
32
+ "chunk.finish",
33
+ ];
34
+ export const THREAD_STREAM_TEXT_CHUNK_TYPES = [
35
+ "chunk.text_start",
36
+ "chunk.text_delta",
37
+ "chunk.text_end",
38
+ ];
39
+ export const THREAD_STREAM_REASONING_CHUNK_TYPES = [
40
+ "chunk.reasoning_start",
41
+ "chunk.reasoning_delta",
42
+ "chunk.reasoning_end",
43
+ ];
44
+ export const THREAD_STREAM_ACTION_CHUNK_TYPES = [
45
+ "chunk.action_input_start",
46
+ "chunk.action_input_delta",
47
+ "chunk.action_input_available",
48
+ "chunk.action_output_available",
49
+ "chunk.action_output_error",
50
+ ];
51
+ export const THREAD_STREAM_SOURCE_CHUNK_TYPES = [
52
+ "chunk.source_url",
53
+ "chunk.source_document",
54
+ "chunk.file",
55
+ ];
56
+ export const THREAD_STREAM_METADATA_CHUNK_TYPES = [
57
+ "chunk.message_metadata",
58
+ "chunk.response_metadata",
59
+ ];
60
+ export const THREAD_STREAM_ERROR_CHUNK_TYPES = [
61
+ "chunk.error",
62
+ "chunk.unknown",
63
+ ];
20
64
  export const THREAD_STREAM_CHUNK_TYPES = [
21
- "data-context-id",
22
- "data-context-substate",
23
- "data-thread-ping",
24
- "tool-output-available",
25
- "tool-output-error",
26
- "finish",
27
- ];
28
- export const THREAD_CONTEXT_SUBSTATE_KEYS = ["actions"];
65
+ ...THREAD_STREAM_LIFECYCLE_CHUNK_TYPES,
66
+ ...THREAD_STREAM_TEXT_CHUNK_TYPES,
67
+ ...THREAD_STREAM_REASONING_CHUNK_TYPES,
68
+ ...THREAD_STREAM_ACTION_CHUNK_TYPES,
69
+ ...THREAD_STREAM_SOURCE_CHUNK_TYPES,
70
+ ...THREAD_STREAM_METADATA_CHUNK_TYPES,
71
+ ...THREAD_STREAM_ERROR_CHUNK_TYPES,
72
+ ];
73
+ export function isThreadStreamChunkType(value) {
74
+ return THREAD_STREAM_CHUNK_TYPES.includes(value);
75
+ }
29
76
  export const THREAD_THREAD_TRANSITIONS = [
30
- { from: "open", to: "streaming" },
31
- { from: "streaming", to: "open" },
32
- { from: "streaming", to: "closed" },
33
- { from: "streaming", to: "failed" },
34
- { from: "failed", to: "open" },
77
+ { from: "idle", to: "streaming" },
78
+ { from: "streaming", to: "idle" },
35
79
  ];
36
80
  export const THREAD_CONTEXT_TRANSITIONS = [
37
- { from: "open", to: "streaming" },
38
- { from: "streaming", to: "open" },
39
81
  { from: "open", to: "closed" },
40
- { from: "streaming", to: "closed" },
82
+ { from: "closed", to: "open" },
41
83
  ];
42
84
  export const THREAD_EXECUTION_TRANSITIONS = [
43
85
  { from: "executing", to: "completed" },
package/dist/thread.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export { Thread, type ThreadOptions, type ThreadStreamOptions, type ShouldContinue, type ThreadShouldContinueArgs, } from "./thread.engine.js";
2
2
  export { thread, createThread, type ThreadConfig, type ThreadInstance, type RegistrableThreadBuilder, } from "./thread.builder.js";
3
- export { createAiSdkReactor, createScriptedReactor, type CreateAiSdkReactorOptions, type CreateScriptedReactorOptions, type ScriptedReactorStep, type ThreadReactor, type ThreadReactorParams, type ThreadReactionResult, type ThreadReactionToolCall, type ThreadReactionLLM, } from "./thread.reactor.js";
3
+ export { createAiSdkReactor, createScriptedReactor, type CreateAiSdkReactorOptions, type CreateScriptedReactorOptions, type ScriptedReactorStep, type ThreadReactor, type ThreadReactorParams, type ThreadReactionResult, type ThreadActionRequest, type ThreadReactionLLM, } from "./thread.reactor.js";
@@ -13,12 +13,8 @@ export interface ThreadOptions<Context = any, Env extends ThreadEnvironment = Th
13
13
  context: StoredContext<Context>;
14
14
  }) => void | Promise<void>;
15
15
  onEventCreated?: (event: ThreadItem) => void | Promise<void>;
16
- onToolCallExecuted?: (executionEvent: any) => void | Promise<void>;
17
- onEnd?: (lastEvent: ThreadItem) => void | {
18
- end?: boolean;
19
- } | Promise<void | {
20
- end?: boolean;
21
- }>;
16
+ onActionExecuted?: (executionEvent: any) => void | Promise<void>;
17
+ onEnd?: (lastEvent: ThreadItem) => void | boolean | Promise<void | boolean>;
22
18
  }
23
19
  export interface ThreadStreamOptions {
24
20
  /**
@@ -134,9 +130,17 @@ export type ThreadShouldContinueArgs<Context = any, Env extends ThreadEnvironmen
134
130
  */
135
131
  reactionEvent: ThreadItem;
136
132
  assistantEvent: ThreadItem;
137
- toolCalls: any[];
138
- toolExecutionResults: Array<{
139
- tc: any;
133
+ actionRequests: Array<{
134
+ actionRef: string;
135
+ actionName: string;
136
+ input: unknown;
137
+ }>;
138
+ actionResults: Array<{
139
+ actionRequest: {
140
+ actionRef: string;
141
+ actionName: string;
142
+ input: unknown;
143
+ };
140
144
  success: boolean;
141
145
  output: any;
142
146
  errorText?: string;