@ekairos/thread 1.21.88-beta.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 (86) hide show
  1. package/README.md +363 -0
  2. package/dist/codex.d.ts +95 -0
  3. package/dist/codex.js +91 -0
  4. package/dist/env.d.ts +12 -0
  5. package/dist/env.js +62 -0
  6. package/dist/events.d.ts +35 -0
  7. package/dist/events.js +102 -0
  8. package/dist/index.d.ts +9 -0
  9. package/dist/index.js +9 -0
  10. package/dist/mcp.d.ts +1 -0
  11. package/dist/mcp.js +1 -0
  12. package/dist/mirror.d.ts +41 -0
  13. package/dist/mirror.js +1 -0
  14. package/dist/oidc.d.ts +7 -0
  15. package/dist/oidc.js +25 -0
  16. package/dist/polyfills/dom-events.d.ts +1 -0
  17. package/dist/polyfills/dom-events.js +89 -0
  18. package/dist/react.d.ts +62 -0
  19. package/dist/react.js +101 -0
  20. package/dist/runtime.d.ts +17 -0
  21. package/dist/runtime.js +23 -0
  22. package/dist/runtime.step.d.ts +9 -0
  23. package/dist/runtime.step.js +7 -0
  24. package/dist/schema.d.ts +2 -0
  25. package/dist/schema.js +200 -0
  26. package/dist/steps/do-story-stream-step.d.ts +29 -0
  27. package/dist/steps/do-story-stream-step.js +89 -0
  28. package/dist/steps/do-thread-stream-step.d.ts +29 -0
  29. package/dist/steps/do-thread-stream-step.js +90 -0
  30. package/dist/steps/mirror.steps.d.ts +6 -0
  31. package/dist/steps/mirror.steps.js +48 -0
  32. package/dist/steps/reaction.steps.d.ts +43 -0
  33. package/dist/steps/reaction.steps.js +354 -0
  34. package/dist/steps/store.steps.d.ts +98 -0
  35. package/dist/steps/store.steps.js +512 -0
  36. package/dist/steps/stream.steps.d.ts +41 -0
  37. package/dist/steps/stream.steps.js +99 -0
  38. package/dist/steps/trace.steps.d.ts +37 -0
  39. package/dist/steps/trace.steps.js +265 -0
  40. package/dist/stores/instant.document-parser.d.ts +6 -0
  41. package/dist/stores/instant.document-parser.js +210 -0
  42. package/dist/stores/instant.documents.d.ts +16 -0
  43. package/dist/stores/instant.documents.js +152 -0
  44. package/dist/stores/instant.store.d.ts +78 -0
  45. package/dist/stores/instant.store.js +530 -0
  46. package/dist/story.actions.d.ts +60 -0
  47. package/dist/story.actions.js +120 -0
  48. package/dist/story.builder.d.ts +115 -0
  49. package/dist/story.builder.js +130 -0
  50. package/dist/story.config.d.ts +54 -0
  51. package/dist/story.config.js +125 -0
  52. package/dist/story.d.ts +2 -0
  53. package/dist/story.engine.d.ts +224 -0
  54. package/dist/story.engine.js +464 -0
  55. package/dist/story.hooks.d.ts +21 -0
  56. package/dist/story.hooks.js +31 -0
  57. package/dist/story.js +6 -0
  58. package/dist/story.registry.d.ts +21 -0
  59. package/dist/story.registry.js +30 -0
  60. package/dist/story.store.d.ts +107 -0
  61. package/dist/story.store.js +1 -0
  62. package/dist/story.toolcalls.d.ts +60 -0
  63. package/dist/story.toolcalls.js +73 -0
  64. package/dist/thread.builder.d.ts +118 -0
  65. package/dist/thread.builder.js +134 -0
  66. package/dist/thread.config.d.ts +15 -0
  67. package/dist/thread.config.js +30 -0
  68. package/dist/thread.d.ts +3 -0
  69. package/dist/thread.engine.d.ts +229 -0
  70. package/dist/thread.engine.js +471 -0
  71. package/dist/thread.events.d.ts +35 -0
  72. package/dist/thread.events.js +105 -0
  73. package/dist/thread.hooks.d.ts +21 -0
  74. package/dist/thread.hooks.js +31 -0
  75. package/dist/thread.js +7 -0
  76. package/dist/thread.reactor.d.ts +82 -0
  77. package/dist/thread.reactor.js +65 -0
  78. package/dist/thread.registry.d.ts +21 -0
  79. package/dist/thread.registry.js +30 -0
  80. package/dist/thread.store.d.ts +121 -0
  81. package/dist/thread.store.js +1 -0
  82. package/dist/thread.toolcalls.d.ts +60 -0
  83. package/dist/thread.toolcalls.js +73 -0
  84. package/dist/tools-to-model-tools.d.ts +19 -0
  85. package/dist/tools-to-model-tools.js +21 -0
  86. package/package.json +133 -0
@@ -0,0 +1,82 @@
1
+ import type { ModelMessage, UIMessageChunk } from "ai";
2
+ import type { ThreadEnvironment } from "./thread.config.js";
3
+ import type { ThreadModelInit } from "./thread.engine.js";
4
+ import type { ContextIdentifier, StoredContext, ThreadItem } from "./thread.store.js";
5
+ import type { SerializableToolForModel } from "./tools-to-model-tools.js";
6
+ export type ThreadReactionToolCall = {
7
+ toolCallId: string;
8
+ toolName: string;
9
+ args: unknown;
10
+ };
11
+ export type ThreadReactionLLM = {
12
+ provider?: string;
13
+ model?: string;
14
+ promptTokens?: number;
15
+ promptTokensCached?: number;
16
+ promptTokensUncached?: number;
17
+ completionTokens?: number;
18
+ totalTokens?: number;
19
+ latencyMs?: number;
20
+ rawUsage?: unknown;
21
+ rawProviderMetadata?: unknown;
22
+ };
23
+ export type ThreadReactionResult = {
24
+ assistantEvent: ThreadItem;
25
+ toolCalls: ThreadReactionToolCall[];
26
+ messagesForModel: ModelMessage[];
27
+ llm?: ThreadReactionLLM;
28
+ };
29
+ export type ThreadReactorParams<Context = unknown, Env extends ThreadEnvironment = ThreadEnvironment> = {
30
+ env: Env;
31
+ context: StoredContext<Context>;
32
+ contextIdentifier: ContextIdentifier;
33
+ triggerEvent: ThreadItem;
34
+ model: ThreadModelInit;
35
+ systemPrompt: string;
36
+ actions: Record<string, unknown>;
37
+ toolsForModel: Record<string, SerializableToolForModel>;
38
+ eventId: string;
39
+ executionId: string;
40
+ contextId: string;
41
+ stepId: string;
42
+ iteration: number;
43
+ maxModelSteps: number;
44
+ sendStart: boolean;
45
+ silent: boolean;
46
+ writable?: WritableStream<UIMessageChunk>;
47
+ };
48
+ export type ThreadReactor<Context = unknown, Env extends ThreadEnvironment = ThreadEnvironment> = (params: ThreadReactorParams<Context, Env>) => Promise<ThreadReactionResult>;
49
+ export type CreateAiSdkReactorOptions<Context = unknown, Env extends ThreadEnvironment = ThreadEnvironment, Config = unknown> = {
50
+ resolveConfig?: (params: {
51
+ env: Env;
52
+ context: StoredContext<Context>;
53
+ contextIdentifier: ContextIdentifier;
54
+ triggerEvent: ThreadItem;
55
+ model: ThreadModelInit;
56
+ eventId: string;
57
+ executionId: string;
58
+ contextId: string;
59
+ stepId: string;
60
+ iteration: number;
61
+ }) => Promise<Config> | Config;
62
+ selectModel?: (params: {
63
+ env: Env;
64
+ context: StoredContext<Context>;
65
+ triggerEvent: ThreadItem;
66
+ baseModel: ThreadModelInit;
67
+ config: Config;
68
+ }) => Promise<ThreadModelInit> | ThreadModelInit;
69
+ selectMaxModelSteps?: (params: {
70
+ env: Env;
71
+ context: StoredContext<Context>;
72
+ triggerEvent: ThreadItem;
73
+ baseMaxModelSteps: number;
74
+ config: Config;
75
+ }) => Promise<number> | number;
76
+ };
77
+ /**
78
+ * Default reactor for Thread: Vercel AI SDK (`streamText`) with tool-call extraction.
79
+ *
80
+ * This keeps current behavior and can be replaced per-thread using `.reactor(...)`.
81
+ */
82
+ export declare function createAiSdkReactor<Context = unknown, Env extends ThreadEnvironment = ThreadEnvironment, Config = unknown>(options?: CreateAiSdkReactorOptions<Context, Env, Config>): ThreadReactor<Context, Env>;
@@ -0,0 +1,65 @@
1
+ import { executeReaction } from "./steps/reaction.steps.js";
2
+ /**
3
+ * Default reactor for Thread: Vercel AI SDK (`streamText`) with tool-call extraction.
4
+ *
5
+ * This keeps current behavior and can be replaced per-thread using `.reactor(...)`.
6
+ */
7
+ export function createAiSdkReactor(options) {
8
+ return async (params) => {
9
+ let config;
10
+ if (options?.resolveConfig) {
11
+ config = await options.resolveConfig({
12
+ env: params.env,
13
+ context: params.context,
14
+ contextIdentifier: params.contextIdentifier,
15
+ triggerEvent: params.triggerEvent,
16
+ model: params.model,
17
+ eventId: params.eventId,
18
+ executionId: params.executionId,
19
+ contextId: params.contextId,
20
+ stepId: params.stepId,
21
+ iteration: params.iteration,
22
+ });
23
+ }
24
+ const model = options?.selectModel && config !== undefined
25
+ ? await options.selectModel({
26
+ env: params.env,
27
+ context: params.context,
28
+ triggerEvent: params.triggerEvent,
29
+ baseModel: params.model,
30
+ config,
31
+ })
32
+ : params.model;
33
+ const maxSteps = options?.selectMaxModelSteps && config !== undefined
34
+ ? await options.selectMaxModelSteps({
35
+ env: params.env,
36
+ context: params.context,
37
+ triggerEvent: params.triggerEvent,
38
+ baseMaxModelSteps: params.maxModelSteps,
39
+ config,
40
+ })
41
+ : params.maxModelSteps;
42
+ const result = await executeReaction({
43
+ env: params.env,
44
+ contextIdentifier: params.contextIdentifier,
45
+ model,
46
+ system: params.systemPrompt,
47
+ tools: params.toolsForModel,
48
+ eventId: params.eventId,
49
+ iteration: params.iteration,
50
+ maxSteps,
51
+ sendStart: params.sendStart,
52
+ silent: params.silent,
53
+ writable: params.writable,
54
+ executionId: params.executionId,
55
+ contextId: params.contextId,
56
+ stepId: params.stepId,
57
+ });
58
+ return {
59
+ assistantEvent: result.assistantEvent,
60
+ toolCalls: result.toolCalls,
61
+ messagesForModel: result.messagesForModel,
62
+ llm: result.llm,
63
+ };
64
+ };
65
+ }
@@ -0,0 +1,21 @@
1
+ import type { ThreadEnvironment } from "./thread.config.js";
2
+ import type { ThreadInstance } from "./thread.builder.js";
3
+ /**
4
+ * Global registry for threads, similar to Inngest's function registry.
5
+ *
6
+ * Goals:
7
+ * - `createThread("key")` can be called many times (module reloads, tests, etc.)
8
+ * - Execution resolves a thread by key (`getThread("key")`) instead of importing the module directly.
9
+ * - Registration is intentionally **runtime-local** (per process / per serverless instance).
10
+ */
11
+ export type ThreadKey = string;
12
+ type AnyThread = ThreadInstance<any, any>;
13
+ export type ThreadFactory = () => AnyThread;
14
+ export declare function registerThread(key: ThreadKey, factory: ThreadFactory): void;
15
+ export declare function hasThread(key: ThreadKey): boolean;
16
+ export declare function getThread<Env extends ThreadEnvironment = ThreadEnvironment>(key: ThreadKey): AnyThread & {
17
+ __config: {};
18
+ };
19
+ export declare function getThreadFactory(key: ThreadKey): ThreadFactory;
20
+ export declare function listThreads(): string[];
21
+ export {};
@@ -0,0 +1,30 @@
1
+ const registry = new Map();
2
+ export function registerThread(key, factory) {
3
+ if (!key || typeof key !== "string") {
4
+ throw new Error("registerThread: key must be a non-empty string");
5
+ }
6
+ if (typeof factory !== "function") {
7
+ throw new Error("registerThread: factory must be a function");
8
+ }
9
+ registry.set(key, factory);
10
+ }
11
+ export function hasThread(key) {
12
+ return registry.has(key);
13
+ }
14
+ export function getThread(key) {
15
+ const factory = registry.get(key);
16
+ if (!factory) {
17
+ throw new Error(`Thread "${key}" is not registered. Ensure the module that calls createThread("${key}") is imported during boot.`);
18
+ }
19
+ return factory();
20
+ }
21
+ export function getThreadFactory(key) {
22
+ const factory = registry.get(key);
23
+ if (!factory) {
24
+ throw new Error(`Thread "${key}" is not registered. Ensure the module that calls createThread("${key}") is imported during boot.`);
25
+ }
26
+ return factory;
27
+ }
28
+ export function listThreads() {
29
+ return Array.from(registry.keys());
30
+ }
@@ -0,0 +1,121 @@
1
+ import type { ModelMessage } from "ai";
2
+ /**
3
+ * ## thread.store.ts
4
+ *
5
+ * A `ThreadStore` is the persistence boundary for threads.
6
+ *
7
+ * Workflow DevKit constraints mean **workflows must be deterministic** and all I/O must happen
8
+ * in steps. This library therefore models persistence as a pluggable store that can be
9
+ * instantiated *inside steps* (InstantDB, Postgres, etc.).
10
+ *
11
+ * The core engine should depend only on this interface (not on a specific database).
12
+ */
13
+ export type ThreadIdentifier = {
14
+ id: string;
15
+ key?: never;
16
+ } | {
17
+ key: string;
18
+ id?: never;
19
+ };
20
+ export type ContextIdentifier = ThreadIdentifier;
21
+ export type ThreadStatus = "open" | "streaming" | "closed" | "failed";
22
+ export type ContextStatus = "open" | "streaming" | "closed";
23
+ export type StoredThread = {
24
+ id: string;
25
+ key: string | null;
26
+ name?: string | null;
27
+ status: ThreadStatus;
28
+ createdAt: Date;
29
+ updatedAt?: Date;
30
+ };
31
+ export type StoredContext<Context> = {
32
+ id: string;
33
+ threadId?: string;
34
+ key: string | null;
35
+ status: ContextStatus;
36
+ createdAt: Date;
37
+ updatedAt?: Date;
38
+ content: Context | null;
39
+ };
40
+ export type ThreadItem = {
41
+ id: string;
42
+ type: string;
43
+ channel: string;
44
+ createdAt: string;
45
+ status?: string;
46
+ content: any;
47
+ };
48
+ export type ExecutionStatus = "executing" | "completed" | "failed";
49
+ export type ThreadStepStatus = "running" | "completed" | "failed";
50
+ export type ThreadStep = {
51
+ id: string;
52
+ createdAt: Date;
53
+ updatedAt?: Date;
54
+ status: ThreadStepStatus;
55
+ iteration: number;
56
+ executionId: string;
57
+ triggerEventId?: string;
58
+ reactionEventId?: string;
59
+ eventId: string;
60
+ toolCalls?: any;
61
+ toolExecutionResults?: any;
62
+ continueLoop?: boolean;
63
+ errorText?: string;
64
+ };
65
+ export interface ThreadStore {
66
+ getOrCreateThread(threadIdentifier: ThreadIdentifier | null): Promise<StoredThread>;
67
+ getThread(threadIdentifier: ThreadIdentifier): Promise<StoredThread | null>;
68
+ updateThreadStatus(threadIdentifier: ThreadIdentifier, status: ThreadStatus): Promise<void>;
69
+ getOrCreateContext<C>(contextIdentifier: ContextIdentifier | null): Promise<StoredContext<C>>;
70
+ getContext<C>(contextIdentifier: ContextIdentifier): Promise<StoredContext<C> | null>;
71
+ updateContextContent<C>(contextIdentifier: ContextIdentifier, content: C): Promise<StoredContext<C>>;
72
+ updateContextStatus(contextIdentifier: ContextIdentifier, status: ContextStatus): Promise<void>;
73
+ saveItem(contextIdentifier: ContextIdentifier, item: ThreadItem): Promise<ThreadItem>;
74
+ updateItem(itemId: string, item: ThreadItem): Promise<ThreadItem>;
75
+ getItem(itemId: string): Promise<ThreadItem | null>;
76
+ getItems(contextIdentifier: ContextIdentifier): Promise<ThreadItem[]>;
77
+ createExecution(contextIdentifier: ContextIdentifier, triggerEventId: string, reactionEventId: string): Promise<{
78
+ id: string;
79
+ }>;
80
+ completeExecution(contextIdentifier: ContextIdentifier, executionId: string, status: Exclude<ExecutionStatus, "executing">): Promise<void>;
81
+ /**
82
+ * Creates a persisted thread step (intended: one per loop iteration).
83
+ *
84
+ * IMPORTANT: IDs should be generated inside the store boundary (step runtime) to remain replay-safe.
85
+ */
86
+ createStep(params: {
87
+ executionId: string;
88
+ iteration: number;
89
+ }): Promise<{
90
+ id: string;
91
+ eventId: string;
92
+ }>;
93
+ /**
94
+ * Updates a persisted thread step with completion metadata (tools, errors, continue signal, etc).
95
+ */
96
+ updateStep(stepId: string, patch: Partial<Pick<ThreadStep, "status" | "toolCalls" | "toolExecutionResults" | "continueLoop" | "errorText" | "updatedAt">>): Promise<void>;
97
+ /**
98
+ * Persists normalized parts for a given step (parts-first).
99
+ * The item keeps `content.parts` for back-compat, but the source-of-truth can be `thread_parts`.
100
+ */
101
+ saveStepParts(params: {
102
+ stepId: string;
103
+ parts: any[];
104
+ }): Promise<void>;
105
+ /**
106
+ * Links an event to an execution so consumers can traverse:
107
+ * `event -> execution -> steps`
108
+ */
109
+ linkItemToExecution(params: {
110
+ itemId: string;
111
+ executionId: string;
112
+ }): Promise<void>;
113
+ /**
114
+ * Converts items to model messages for the next LLM call.
115
+ *
116
+ * NOTE:
117
+ * - Attachment/document expansion should happen earlier in the Thread loop via `expandEvents(...)`.
118
+ * - This method should stay focused on converting already-normalized event parts into `ModelMessage[]`.
119
+ */
120
+ itemsToModelMessages(items: ThreadItem[]): Promise<ModelMessage[]>;
121
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,60 @@
1
+ /**
2
+ * ## thread.toolcalls.ts
3
+ *
4
+ * This module isolates the **tool-call plumbing** used by `thread.engine.ts`.
5
+ *
6
+ * In our runtime, tool calls are represented as **event parts** produced by the AI SDK.
7
+ * The engine needs to:
8
+ * - extract a normalized list of tool calls from `event.content.parts`, and
9
+ * - merge tool execution outcomes back into those parts (so the persisted event reflects
10
+ * `output-available` / `output-error`, etc.).
11
+ *
12
+ * Keeping this logic here helps `thread.engine.ts` read like orchestration, and keeps
13
+ * these transformations testable and reusable.
14
+ */
15
+ import type { ThreadItem } from "./thread.store.js";
16
+ export type ToolCall = {
17
+ toolCallId: string;
18
+ toolName: string;
19
+ args: any;
20
+ };
21
+ /**
22
+ * Extracts tool calls from an event's `parts` array.
23
+ *
24
+ * Expected part shape (loosely):
25
+ * - `type`: string like `"tool-<toolName>"`
26
+ * - `toolCallId`: string
27
+ * - `input`: any (tool args)
28
+ *
29
+ * We intentionally treat the input as `any` because the part schema is produced by the AI SDK.
30
+ */
31
+ export declare function extractToolCallsFromParts(parts: any[] | undefined | null): ToolCall[];
32
+ /**
33
+ * Applies a tool execution outcome to the matching tool part.
34
+ *
35
+ * This does not mutate `parts` — it returns a new array.
36
+ *
37
+ * We match the tool part by:
38
+ * - `type === "tool-<toolName>"` and
39
+ * - `toolCallId` equality
40
+ *
41
+ * Then we set:
42
+ * - on success: `{ state: "output-available", output: <result> }`
43
+ * - on failure: `{ state: "output-error", errorText: <message> }`
44
+ */
45
+ export declare function applyToolExecutionResultToParts(parts: any[], toolCall: Pick<ToolCall, "toolCallId" | "toolName">, execution: {
46
+ success: boolean;
47
+ result: any;
48
+ message?: string;
49
+ }): any[];
50
+ /**
51
+ * Returns `true` when a given tool has a **settled** execution result in an event's parts.
52
+ *
53
+ * We treat a tool part as "executed" once it has either:
54
+ * - `state: "output-available"` (success), or
55
+ * - `state: "output-error"` (failure).
56
+ *
57
+ * This is useful for stop/continue logic in `thread.shouldContinue(...)` where you want to
58
+ * decide based on the persisted `reactionEvent` (not ephemeral in-memory arrays).
59
+ */
60
+ export declare function didToolExecute(event: Pick<ThreadItem, "content">, toolName: string): boolean;
@@ -0,0 +1,73 @@
1
+ /**
2
+ * ## thread.toolcalls.ts
3
+ *
4
+ * This module isolates the **tool-call plumbing** used by `thread.engine.ts`.
5
+ *
6
+ * In our runtime, tool calls are represented as **event parts** produced by the AI SDK.
7
+ * The engine needs to:
8
+ * - extract a normalized list of tool calls from `event.content.parts`, and
9
+ * - merge tool execution outcomes back into those parts (so the persisted event reflects
10
+ * `output-available` / `output-error`, etc.).
11
+ *
12
+ * Keeping this logic here helps `thread.engine.ts` read like orchestration, and keeps
13
+ * these transformations testable and reusable.
14
+ */
15
+ /**
16
+ * Extracts tool calls from an event's `parts` array.
17
+ *
18
+ * Expected part shape (loosely):
19
+ * - `type`: string like `"tool-<toolName>"`
20
+ * - `toolCallId`: string
21
+ * - `input`: any (tool args)
22
+ *
23
+ * We intentionally treat the input as `any` because the part schema is produced by the AI SDK.
24
+ */
25
+ export function extractToolCallsFromParts(parts) {
26
+ const safeParts = parts ?? [];
27
+ return safeParts.reduce((acc, p) => {
28
+ if (typeof p?.type === "string" && p.type.startsWith("tool-")) {
29
+ const toolName = p.type.split("-").slice(1).join("-");
30
+ acc.push({ toolCallId: p.toolCallId, toolName, args: p.input });
31
+ }
32
+ return acc;
33
+ }, []);
34
+ }
35
+ /**
36
+ * Applies a tool execution outcome to the matching tool part.
37
+ *
38
+ * This does not mutate `parts` — it returns a new array.
39
+ *
40
+ * We match the tool part by:
41
+ * - `type === "tool-<toolName>"` and
42
+ * - `toolCallId` equality
43
+ *
44
+ * Then we set:
45
+ * - on success: `{ state: "output-available", output: <result> }`
46
+ * - on failure: `{ state: "output-error", errorText: <message> }`
47
+ */
48
+ 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") };
55
+ }
56
+ return p;
57
+ });
58
+ }
59
+ /**
60
+ * Returns `true` when a given tool has a **settled** execution result in an event's parts.
61
+ *
62
+ * We treat a tool part as "executed" once it has either:
63
+ * - `state: "output-available"` (success), or
64
+ * - `state: "output-error"` (failure).
65
+ *
66
+ * This is useful for stop/continue logic in `thread.shouldContinue(...)` where you want to
67
+ * decide based on the persisted `reactionEvent` (not ephemeral in-memory arrays).
68
+ */
69
+ 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"));
73
+ }
@@ -0,0 +1,19 @@
1
+ import { type Tool } from "ai";
2
+ /**
3
+ * Serializable "tool" shape to pass across the Workflow step boundary.
4
+ *
5
+ * Mirrors Workflow DevKit's DurableAgent strategy:
6
+ * - Keep Zod/function values out of step arguments
7
+ * - Convert tool input schemas to plain JSON Schema in workflow context
8
+ */
9
+ export type SerializableToolForModel = {
10
+ description?: string;
11
+ inputSchema: unknown;
12
+ };
13
+ /**
14
+ * Convert AI SDK tools to a serializable representation that can be passed to `"use-step"` functions.
15
+ *
16
+ * This matches DurableAgent's internal `toolsToModelTools` behavior:
17
+ * `inputSchema: asSchema(tool.inputSchema).jsonSchema`
18
+ */
19
+ export declare function toolsToModelTools(tools: Record<string, Tool>): Record<string, SerializableToolForModel>;
@@ -0,0 +1,21 @@
1
+ import { asSchema } from "ai";
2
+ /**
3
+ * Convert AI SDK tools to a serializable representation that can be passed to `"use-step"` functions.
4
+ *
5
+ * This matches DurableAgent's internal `toolsToModelTools` behavior:
6
+ * `inputSchema: asSchema(tool.inputSchema).jsonSchema`
7
+ */
8
+ export function toolsToModelTools(tools) {
9
+ const out = {};
10
+ for (const [name, tool] of Object.entries(tools)) {
11
+ const inputSchema = tool?.inputSchema;
12
+ if (!inputSchema) {
13
+ throw new Error(`Thread: tool "${name}" is missing inputSchema (required for model tool calls)`);
14
+ }
15
+ out[name] = {
16
+ description: tool?.description,
17
+ inputSchema: asSchema(inputSchema).jsonSchema,
18
+ };
19
+ }
20
+ return out;
21
+ }
package/package.json ADDED
@@ -0,0 +1,133 @@
1
+ {
2
+ "name": "@ekairos/thread",
3
+ "version": "1.21.88-beta.0",
4
+ "description": "Pulzar Thread - Workflow-based AI Threads",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "publishConfig": {
12
+ "access": "public"
13
+ },
14
+ "license": "MIT",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/pulz-ar/pulzar-lib-core.git",
18
+ "directory": "packages/thread"
19
+ },
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/index.d.ts",
23
+ "import": "./dist/index.js",
24
+ "require": "./dist/index.js",
25
+ "default": "./dist/index.js"
26
+ },
27
+ "./schema": {
28
+ "types": "./dist/schema.d.ts",
29
+ "import": "./dist/schema.js",
30
+ "require": "./dist/schema.js",
31
+ "default": "./dist/schema.js"
32
+ },
33
+ "./runtime": {
34
+ "types": "./dist/runtime.d.ts",
35
+ "import": "./dist/runtime.js",
36
+ "require": "./dist/runtime.js",
37
+ "default": "./dist/runtime.js"
38
+ },
39
+ "./reactor": {
40
+ "types": "./dist/thread.reactor.d.ts",
41
+ "import": "./dist/thread.reactor.js",
42
+ "require": "./dist/thread.reactor.js",
43
+ "default": "./dist/thread.reactor.js"
44
+ },
45
+ "./mcp": {
46
+ "types": "./dist/mcp.d.ts",
47
+ "import": "./dist/mcp.js",
48
+ "require": "./dist/mcp.js",
49
+ "default": "./dist/mcp.js"
50
+ },
51
+ "./oidc": {
52
+ "types": "./dist/oidc.d.ts",
53
+ "import": "./dist/oidc.js",
54
+ "require": "./dist/oidc.js",
55
+ "default": "./dist/oidc.js"
56
+ },
57
+ "./codex": {
58
+ "types": "./dist/codex.d.ts",
59
+ "import": "./dist/codex.js",
60
+ "require": "./dist/codex.js",
61
+ "default": "./dist/codex.js"
62
+ },
63
+ "./react": {
64
+ "types": "./dist/react.d.ts",
65
+ "import": "./dist/react.js",
66
+ "require": "./dist/react.js",
67
+ "default": "./dist/react.js"
68
+ },
69
+ "./instant": {
70
+ "types": "./dist/stores/instant.store.d.ts",
71
+ "import": "./dist/stores/instant.store.js",
72
+ "require": "./dist/stores/instant.store.js",
73
+ "default": "./dist/stores/instant.store.js"
74
+ }
75
+ },
76
+ "typesVersions": {
77
+ "*": {
78
+ "schema": [
79
+ "dist/schema.d.ts"
80
+ ],
81
+ "runtime": [
82
+ "dist/runtime.d.ts"
83
+ ],
84
+ "reactor": [
85
+ "dist/thread.reactor.d.ts"
86
+ ],
87
+ "mcp": [
88
+ "dist/mcp.d.ts"
89
+ ],
90
+ "oidc": [
91
+ "dist/oidc.d.ts"
92
+ ],
93
+ "codex": [
94
+ "dist/codex.d.ts"
95
+ ],
96
+ "react": [
97
+ "dist/react.d.ts"
98
+ ],
99
+ "instant": [
100
+ "dist/stores/instant.store.d.ts"
101
+ ]
102
+ }
103
+ },
104
+ "scripts": {
105
+ "build": "tsc -p tsconfig.json",
106
+ "dev": "tsc -p tsconfig.json --watch",
107
+ "watch": "tsc -p tsconfig.json --watch",
108
+ "clean": "node -e \"require('fs').rmSync('dist', {recursive:true, force:true})\"",
109
+ "typecheck": "tsc --noEmit"
110
+ },
111
+ "dependencies": {
112
+ "@ai-sdk/openai": "^2.0.52",
113
+ "@ekairos/domain": "^1.21.88-beta.0",
114
+ "@instantdb/admin": "0.22.126",
115
+ "@instantdb/core": "0.22.126",
116
+ "@vercel/mcp-adapter": "^1.0.0",
117
+ "@vercel/sandbox": "^0.0.23",
118
+ "ai": "^5.0.95",
119
+ "ajv": "^8.17.1",
120
+ "jose": "^6.1.3",
121
+ "llamaindex": "^0.12.0",
122
+ "react": "^19.2.0",
123
+ "workflow": "4.1.0-beta.53",
124
+ "xmlbuilder2": "^3.1.1",
125
+ "zod": "^4.1.8"
126
+ },
127
+ "devDependencies": {
128
+ "@ekairos/tsconfig": "workspace:*",
129
+ "@types/node": "^24.5.0",
130
+ "@types/react": "^19.2.2",
131
+ "typescript": "^5.9.2"
132
+ }
133
+ }