@ekairos/thread 1.22.15-beta.feature-thread-unify.0 → 1.22.17-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.
- package/README.md +7 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.js +2 -2
- package/dist/react.d.ts +2 -18
- package/dist/react.js +2 -15
- package/dist/reactors/ai-sdk.chunk-map.d.ts +12 -0
- package/dist/reactors/ai-sdk.chunk-map.js +143 -0
- package/dist/reactors/ai-sdk.reactor.js +5 -1
- package/dist/reactors/scripted.reactor.d.ts +2 -2
- package/dist/reactors/scripted.reactor.js +3 -2
- package/dist/reactors/types.d.ts +5 -5
- package/dist/schema.js +10 -9
- package/dist/steps/do-thread-stream-step.d.ts +6 -2
- package/dist/steps/do-thread-stream-step.js +9 -5
- package/dist/steps/reaction.steps.js +32 -13
- package/dist/steps/store.steps.d.ts +10 -11
- package/dist/steps/store.steps.js +34 -77
- package/dist/steps/stream.steps.d.ts +3 -33
- package/dist/steps/stream.steps.js +7 -68
- package/dist/steps/trace.steps.js +1 -1
- package/dist/stores/instant.documents.d.ts +1 -1
- package/dist/stores/instant.documents.js +1 -1
- package/dist/stores/instant.store.d.ts +7 -3
- package/dist/stores/instant.store.js +32 -86
- package/dist/thread.contract.d.ts +16 -8
- package/dist/thread.contract.js +61 -19
- package/dist/thread.d.ts +1 -1
- package/dist/thread.engine.d.ts +13 -9
- package/dist/thread.engine.js +463 -75
- package/dist/thread.events.d.ts +3 -3
- package/dist/thread.events.js +11 -34
- package/dist/thread.reactor.d.ts +1 -1
- package/dist/thread.store.d.ts +9 -9
- package/dist/thread.stream.d.ts +100 -33
- package/dist/thread.stream.js +72 -63
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
Durable AI threads for production apps.
|
|
4
4
|
|
|
5
|
+
## Specification
|
|
6
|
+
|
|
7
|
+
Normative contract and compatibility profile:
|
|
8
|
+
|
|
9
|
+
- `SPEC.md`
|
|
10
|
+
|
|
5
11
|
`@ekairos/thread` gives you an execution model that is:
|
|
6
12
|
|
|
7
13
|
- workflow-compatible,
|
|
@@ -33,7 +39,7 @@ This design supports long-running, resumable agent runs without losing state.
|
|
|
33
39
|
- `Reactor`: pluggable reaction implementation (`AI SDK`, `Codex`, `Claude`, `Cursor`, ...).
|
|
34
40
|
- `Thread Key`: stable public identifier (`thread.key`) for continuity.
|
|
35
41
|
- `Context`: typed persistent state attached to a thread.
|
|
36
|
-
- `Item`: normalized
|
|
42
|
+
- `Item`: normalized timeline record (`message`, `action_execute`, `action_result`, ...).
|
|
37
43
|
- `Execution`: one run for a trigger/reaction pair.
|
|
38
44
|
- `Step`: one loop iteration inside an execution.
|
|
39
45
|
- `Part`: normalized content fragment persisted by step.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
export { thread, createThread, createAiSdkReactor, createScriptedReactor, type CreateAiSdkReactorOptions, type CreateScriptedReactorOptions, type ScriptedReactorStep, type ThreadConfig, type ThreadInstance, type ThreadOptions, type ThreadStreamOptions, type ThreadReactor, type ThreadReactorParams, type ThreadReactionResult, type
|
|
1
|
+
export { thread, createThread, createAiSdkReactor, createScriptedReactor, type CreateAiSdkReactorOptions, type CreateScriptedReactorOptions, type ScriptedReactorStep, type ThreadConfig, type ThreadInstance, type ThreadOptions, type ThreadStreamOptions, type ThreadReactor, type ThreadReactorParams, type ThreadReactionResult, type ThreadActionRequest, type ThreadReactionLLM, Thread, type RegistrableThreadBuilder, } from "./thread.js";
|
|
2
2
|
export type { ThreadStore, ThreadIdentifier, ContextIdentifier, StoredThread, StoredContext, ThreadItem, } from "./thread.store.js";
|
|
3
3
|
export type { WireDate, ThreadMirrorContext, ThreadMirrorExecution, ThreadMirrorWrite, ThreadMirrorRequest, } from "./mirror.js";
|
|
4
4
|
export { registerThread, getThread, getThreadFactory, hasThread, listThreads, type ThreadKey, } from "./thread.registry.js";
|
|
5
5
|
export { threadDomain } from "./schema.js";
|
|
6
6
|
export { didToolExecute, extractToolCallsFromParts } from "./thread.toolcalls.js";
|
|
7
|
-
export {
|
|
8
|
-
export { THREAD_STATUSES, THREAD_CONTEXT_STATUSES, THREAD_EXECUTION_STATUSES, THREAD_STEP_STATUSES, THREAD_ITEM_STATUSES, THREAD_ITEM_TYPES, THREAD_CHANNELS, THREAD_TRACE_EVENT_KINDS, THREAD_STREAM_CHUNK_TYPES,
|
|
9
|
-
export type { Transition, ThreadThreadStatus, ThreadContextStatus, ThreadExecutionStatus, ThreadStepStatus, ThreadItemStatus, ThreadItemType, ThreadChannel, ThreadTraceEventKind, ThreadStreamChunkType,
|
|
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 "./thread.events.js";
|
|
8
|
+
export { THREAD_STATUSES, THREAD_CONTEXT_STATUSES, THREAD_EXECUTION_STATUSES, THREAD_STEP_STATUSES, THREAD_STEP_KINDS, THREAD_ITEM_STATUSES, THREAD_ITEM_TYPES, THREAD_CHANNELS, THREAD_TRACE_EVENT_KINDS, THREAD_STREAM_CHUNK_TYPES, THREAD_STREAM_LIFECYCLE_CHUNK_TYPES, THREAD_STREAM_TEXT_CHUNK_TYPES, THREAD_STREAM_REASONING_CHUNK_TYPES, THREAD_STREAM_ACTION_CHUNK_TYPES, THREAD_STREAM_SOURCE_CHUNK_TYPES, THREAD_STREAM_METADATA_CHUNK_TYPES, THREAD_STREAM_ERROR_CHUNK_TYPES, THREAD_THREAD_TRANSITIONS, THREAD_CONTEXT_TRANSITIONS, THREAD_EXECUTION_TRANSITIONS, THREAD_STEP_TRANSITIONS, THREAD_ITEM_TRANSITIONS, canThreadTransition, canContextTransition, canExecutionTransition, canStepTransition, canItemTransition, assertThreadTransition, assertContextTransition, assertExecutionTransition, assertStepTransition, assertItemTransition, isThreadStreamChunkType, assertThreadPartKey, } from "./thread.contract.js";
|
|
9
|
+
export type { Transition, ThreadThreadStatus, ThreadContextStatus, ThreadExecutionStatus, ThreadStepStatus, ThreadStepKind, ThreadItemStatus, ThreadItemType, ThreadChannel, ThreadTraceEventKind, ThreadStreamChunkType, ThreadTransition, ContextTransition, ExecutionTransition, StepTransition, ItemTransition, } from "./thread.contract.js";
|
|
10
10
|
export { DEFAULT_CODEX_TOOL_NAME, DEFAULT_CODEX_MODEL, codexToolInputSchema, buildDefaultCodexNarrative, didCodexToolExecute, createCodexThreadBuilder, type CodexThreadRuntimeMode, type CodexThreadReasoningLevel, type CodexThreadRuntime, type CodexThreadEnv, type CodexToolInput, type CodexToolOutput, type CodexExecuteArgs, type CodexThreadBuilderConfig, type CodexThreadBuilder, } from "./codex.js";
|
|
11
11
|
export { useThread, type ThreadSnapshot, type ThreadStreamChunk, type UseThreadOptions, } from "./react.js";
|
|
12
12
|
export { parseThreadStreamEvent, assertThreadStreamTransitions, validateThreadStreamTimeline, } from "./thread.stream.js";
|
|
13
|
-
export type { ThreadStreamEvent, ContextCreatedEvent, ContextResolvedEvent,
|
|
13
|
+
export type { ThreadStreamEvent, ContextCreatedEvent, ContextResolvedEvent, ContextOpenedEvent, ContextClosedEvent, ContextContentUpdatedEvent, ThreadCreatedEvent, ThreadResolvedEvent, ThreadStreamingStartedEvent, ThreadIdleEvent, ExecutionCreatedEvent, ExecutionCompletedEvent, ExecutionFailedEvent, ItemCreatedEvent, ItemUpdatedEvent, ItemPendingEvent, ItemCompletedEvent, StepCreatedEvent, StepUpdatedEvent, StepCompletedEvent, StepFailedEvent, PartCreatedEvent, PartUpdatedEvent, ChunkEmittedEvent, } from "./thread.stream.js";
|
package/dist/index.js
CHANGED
|
@@ -4,8 +4,8 @@ thread, createThread, createAiSdkReactor, createScriptedReactor, Thread, } from
|
|
|
4
4
|
export { registerThread, getThread, getThreadFactory, hasThread, listThreads, } from "./thread.registry.js";
|
|
5
5
|
export { threadDomain } from "./schema.js";
|
|
6
6
|
export { didToolExecute, extractToolCallsFromParts } from "./thread.toolcalls.js";
|
|
7
|
-
export {
|
|
8
|
-
export { THREAD_STATUSES, THREAD_CONTEXT_STATUSES, THREAD_EXECUTION_STATUSES, THREAD_STEP_STATUSES, THREAD_ITEM_STATUSES, THREAD_ITEM_TYPES, THREAD_CHANNELS, THREAD_TRACE_EVENT_KINDS, THREAD_STREAM_CHUNK_TYPES,
|
|
7
|
+
export { INPUT_ITEM_TYPE, INPUT_TEXT_ITEM_TYPE, OUTPUT_ITEM_TYPE, WEB_CHANNEL, AGENT_CHANNEL, EMAIL_CHANNEL, createUserItemFromUIMessages, createAssistantItemFromUIMessages, convertToUIMessage, convertItemToModelMessages, convertItemsToModelMessages, convertModelMessageToItem, } from "./thread.events.js";
|
|
8
|
+
export { THREAD_STATUSES, THREAD_CONTEXT_STATUSES, THREAD_EXECUTION_STATUSES, THREAD_STEP_STATUSES, THREAD_STEP_KINDS, THREAD_ITEM_STATUSES, THREAD_ITEM_TYPES, THREAD_CHANNELS, THREAD_TRACE_EVENT_KINDS, THREAD_STREAM_CHUNK_TYPES, THREAD_STREAM_LIFECYCLE_CHUNK_TYPES, THREAD_STREAM_TEXT_CHUNK_TYPES, THREAD_STREAM_REASONING_CHUNK_TYPES, THREAD_STREAM_ACTION_CHUNK_TYPES, THREAD_STREAM_SOURCE_CHUNK_TYPES, THREAD_STREAM_METADATA_CHUNK_TYPES, THREAD_STREAM_ERROR_CHUNK_TYPES, THREAD_THREAD_TRANSITIONS, THREAD_CONTEXT_TRANSITIONS, THREAD_EXECUTION_TRANSITIONS, THREAD_STEP_TRANSITIONS, THREAD_ITEM_TRANSITIONS, canThreadTransition, canContextTransition, canExecutionTransition, canStepTransition, canItemTransition, assertThreadTransition, assertContextTransition, assertExecutionTransition, assertStepTransition, assertItemTransition, isThreadStreamChunkType, assertThreadPartKey, } from "./thread.contract.js";
|
|
9
9
|
export { DEFAULT_CODEX_TOOL_NAME, DEFAULT_CODEX_MODEL, codexToolInputSchema, buildDefaultCodexNarrative, didCodexToolExecute, createCodexThreadBuilder, } from "./codex.js";
|
|
10
10
|
export { useThread, } from "./react.js";
|
|
11
11
|
export { parseThreadStreamEvent, assertThreadStreamTransitions, validateThreadStreamTimeline, } from "./thread.stream.js";
|
package/dist/react.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ThreadContextStatus,
|
|
1
|
+
import type { ThreadContextStatus, ThreadThreadStatus } from "./thread.contract.js";
|
|
2
2
|
export type ThreadSnapshot<Context = unknown, Item = Record<string, unknown>> = {
|
|
3
3
|
thread: {
|
|
4
4
|
id: string;
|
|
@@ -17,25 +17,10 @@ export type ThreadSnapshot<Context = unknown, Item = Record<string, unknown>> =
|
|
|
17
17
|
items: Item[];
|
|
18
18
|
};
|
|
19
19
|
export type ThreadStreamChunk = {
|
|
20
|
-
type:
|
|
20
|
+
type: `data-context.${string}`;
|
|
21
21
|
data?: {
|
|
22
22
|
contextId?: string;
|
|
23
23
|
};
|
|
24
|
-
id?: string;
|
|
25
|
-
} | {
|
|
26
|
-
type: "data-context-substate";
|
|
27
|
-
data?: {
|
|
28
|
-
key?: ThreadContextSubstateKey | null;
|
|
29
|
-
};
|
|
30
|
-
transient?: boolean;
|
|
31
|
-
} | {
|
|
32
|
-
type: "tool-output-available";
|
|
33
|
-
toolCallId?: string;
|
|
34
|
-
output?: unknown;
|
|
35
|
-
} | {
|
|
36
|
-
type: "tool-output-error";
|
|
37
|
-
toolCallId?: string;
|
|
38
|
-
errorText?: string;
|
|
39
24
|
} | {
|
|
40
25
|
type: string;
|
|
41
26
|
[key: string]: unknown;
|
|
@@ -57,7 +42,6 @@ export declare function useThread<Context = unknown, Item = Record<string, unkno
|
|
|
57
42
|
refresh: () => Promise<void>;
|
|
58
43
|
setData: import("react").Dispatch<import("react").SetStateAction<ThreadSnapshot<Context, Item> | null>>;
|
|
59
44
|
contextId: string | null;
|
|
60
|
-
substateKey: string | null;
|
|
61
45
|
applyChunk: (chunk: ThreadStreamChunk) => void;
|
|
62
46
|
url: string;
|
|
63
47
|
};
|
package/dist/react.js
CHANGED
|
@@ -21,7 +21,6 @@ export function useThread(options) {
|
|
|
21
21
|
const [isLoading, setIsLoading] = useState(true);
|
|
22
22
|
const [error, setError] = useState(null);
|
|
23
23
|
const [contextId, setContextId] = useState(null);
|
|
24
|
-
const [substateKey, setSubstateKey] = useState(null);
|
|
25
24
|
const enabled = options.enabled ?? true;
|
|
26
25
|
const url = useMemo(() => {
|
|
27
26
|
if (!enabled || !options.threadKey)
|
|
@@ -54,26 +53,15 @@ export function useThread(options) {
|
|
|
54
53
|
const applyChunk = useCallback((chunk) => {
|
|
55
54
|
if (!chunk || typeof chunk !== "object")
|
|
56
55
|
return;
|
|
57
|
-
if (chunk.type === "data-context
|
|
56
|
+
if (typeof chunk.type === "string" && chunk.type.startsWith("data-context.")) {
|
|
58
57
|
const payload = "data" in chunk && chunk.data && typeof chunk.data === "object"
|
|
59
58
|
? chunk.data
|
|
60
59
|
: undefined;
|
|
61
60
|
const candidate = typeof payload?.contextId === "string"
|
|
62
61
|
? payload.contextId
|
|
63
|
-
:
|
|
64
|
-
? chunk.id
|
|
65
|
-
: null;
|
|
62
|
+
: null;
|
|
66
63
|
if (candidate)
|
|
67
64
|
setContextId(candidate);
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
if (chunk.type === "data-context-substate") {
|
|
71
|
-
const payload = "data" in chunk && chunk.data && typeof chunk.data === "object"
|
|
72
|
-
? chunk.data
|
|
73
|
-
: undefined;
|
|
74
|
-
const key = payload?.key;
|
|
75
|
-
setSubstateKey(typeof key === "string" ? key : null);
|
|
76
|
-
return;
|
|
77
65
|
}
|
|
78
66
|
}, []);
|
|
79
67
|
useEffect(() => {
|
|
@@ -94,7 +82,6 @@ export function useThread(options) {
|
|
|
94
82
|
refresh,
|
|
95
83
|
setData,
|
|
96
84
|
contextId,
|
|
97
|
-
substateKey,
|
|
98
85
|
applyChunk,
|
|
99
86
|
url,
|
|
100
87
|
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { UIMessageChunk } from "ai";
|
|
2
|
+
import type { ChunkEmittedEvent } from "../thread.stream.js";
|
|
3
|
+
export type MapAiSdkChunkToThreadEventParams = {
|
|
4
|
+
chunk: UIMessageChunk | Record<string, unknown>;
|
|
5
|
+
contextId: string;
|
|
6
|
+
executionId?: string;
|
|
7
|
+
stepId?: string;
|
|
8
|
+
itemId?: string;
|
|
9
|
+
provider?: string;
|
|
10
|
+
sequence: number;
|
|
11
|
+
};
|
|
12
|
+
export declare function mapAiSdkChunkToThreadEvent(params: MapAiSdkChunkToThreadEventParams): ChunkEmittedEvent;
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
const REDACT_KEY = /token|authorization|cookie|secret|api[_-]?key|password/i;
|
|
2
|
+
function asRecord(value) {
|
|
3
|
+
if (!value || typeof value !== "object")
|
|
4
|
+
return {};
|
|
5
|
+
return value;
|
|
6
|
+
}
|
|
7
|
+
function readString(record, key) {
|
|
8
|
+
const value = record[key];
|
|
9
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
10
|
+
}
|
|
11
|
+
function toJsonSafe(value) {
|
|
12
|
+
if (typeof value === "undefined")
|
|
13
|
+
return undefined;
|
|
14
|
+
try {
|
|
15
|
+
return JSON.parse(JSON.stringify(value));
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function sanitizeRaw(value) {
|
|
22
|
+
const seen = new WeakSet();
|
|
23
|
+
try {
|
|
24
|
+
return JSON.parse(JSON.stringify(value, (key, currentValue) => {
|
|
25
|
+
if (REDACT_KEY.test(key))
|
|
26
|
+
return "[redacted]";
|
|
27
|
+
if (typeof currentValue === "string" && currentValue.length > 20000) {
|
|
28
|
+
return "[truncated-string]";
|
|
29
|
+
}
|
|
30
|
+
if (currentValue && typeof currentValue === "object") {
|
|
31
|
+
if (seen.has(currentValue))
|
|
32
|
+
return "[circular]";
|
|
33
|
+
seen.add(currentValue);
|
|
34
|
+
}
|
|
35
|
+
return currentValue;
|
|
36
|
+
}));
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function mapAiSdkChunkType(providerChunkType) {
|
|
43
|
+
switch (providerChunkType) {
|
|
44
|
+
case "start":
|
|
45
|
+
case "stream-start":
|
|
46
|
+
return "chunk.start";
|
|
47
|
+
case "start-step":
|
|
48
|
+
return "chunk.start_step";
|
|
49
|
+
case "finish-step":
|
|
50
|
+
return "chunk.finish_step";
|
|
51
|
+
case "finish":
|
|
52
|
+
return "chunk.finish";
|
|
53
|
+
case "text-start":
|
|
54
|
+
return "chunk.text_start";
|
|
55
|
+
case "text-delta":
|
|
56
|
+
return "chunk.text_delta";
|
|
57
|
+
case "text-end":
|
|
58
|
+
return "chunk.text_end";
|
|
59
|
+
case "reasoning-start":
|
|
60
|
+
return "chunk.reasoning_start";
|
|
61
|
+
case "reasoning-delta":
|
|
62
|
+
return "chunk.reasoning_delta";
|
|
63
|
+
case "reasoning-end":
|
|
64
|
+
return "chunk.reasoning_end";
|
|
65
|
+
case "tool-input-start":
|
|
66
|
+
case "tool-call-start":
|
|
67
|
+
return "chunk.action_input_start";
|
|
68
|
+
case "tool-input-delta":
|
|
69
|
+
case "tool-call-delta":
|
|
70
|
+
return "chunk.action_input_delta";
|
|
71
|
+
case "tool-input-available":
|
|
72
|
+
case "tool-input-end":
|
|
73
|
+
case "tool-call":
|
|
74
|
+
case "tool-call-end":
|
|
75
|
+
return "chunk.action_input_available";
|
|
76
|
+
case "tool-output-available":
|
|
77
|
+
return "chunk.action_output_available";
|
|
78
|
+
case "tool-output-error":
|
|
79
|
+
return "chunk.action_output_error";
|
|
80
|
+
case "source-url":
|
|
81
|
+
return "chunk.source_url";
|
|
82
|
+
case "source-document":
|
|
83
|
+
return "chunk.source_document";
|
|
84
|
+
case "file":
|
|
85
|
+
return "chunk.file";
|
|
86
|
+
case "message-metadata":
|
|
87
|
+
return "chunk.message_metadata";
|
|
88
|
+
case "response-metadata":
|
|
89
|
+
return "chunk.response_metadata";
|
|
90
|
+
case "error":
|
|
91
|
+
return "chunk.error";
|
|
92
|
+
default:
|
|
93
|
+
return "chunk.unknown";
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function buildNormalizedData(chunk) {
|
|
97
|
+
const normalized = {};
|
|
98
|
+
const fields = [
|
|
99
|
+
"id",
|
|
100
|
+
"text",
|
|
101
|
+
"delta",
|
|
102
|
+
"state",
|
|
103
|
+
"toolName",
|
|
104
|
+
"toolCallId",
|
|
105
|
+
"finishReason",
|
|
106
|
+
"url",
|
|
107
|
+
"title",
|
|
108
|
+
"name",
|
|
109
|
+
"mimeType",
|
|
110
|
+
];
|
|
111
|
+
for (const field of fields) {
|
|
112
|
+
const value = chunk[field];
|
|
113
|
+
if (typeof value !== "undefined") {
|
|
114
|
+
normalized[field] = value;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (Object.keys(normalized).length === 0) {
|
|
118
|
+
return {};
|
|
119
|
+
}
|
|
120
|
+
return toJsonSafe(normalized) ?? {};
|
|
121
|
+
}
|
|
122
|
+
export function mapAiSdkChunkToThreadEvent(params) {
|
|
123
|
+
const chunk = asRecord(params.chunk);
|
|
124
|
+
const providerChunkType = readString(chunk, "type") ?? "unknown";
|
|
125
|
+
const chunkType = mapAiSdkChunkType(providerChunkType);
|
|
126
|
+
const actionRef = readString(chunk, "toolCallId") ??
|
|
127
|
+
readString(chunk, "id");
|
|
128
|
+
return {
|
|
129
|
+
type: "chunk.emitted",
|
|
130
|
+
at: new Date().toISOString(),
|
|
131
|
+
chunkType,
|
|
132
|
+
contextId: params.contextId,
|
|
133
|
+
executionId: params.executionId,
|
|
134
|
+
stepId: params.stepId,
|
|
135
|
+
itemId: params.itemId,
|
|
136
|
+
actionRef: chunkType.startsWith("chunk.action_") ? actionRef : undefined,
|
|
137
|
+
provider: params.provider,
|
|
138
|
+
providerChunkType,
|
|
139
|
+
sequence: params.sequence,
|
|
140
|
+
data: buildNormalizedData(chunk),
|
|
141
|
+
raw: sanitizeRaw(chunk),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
@@ -57,7 +57,11 @@ export function createAiSdkReactor(options) {
|
|
|
57
57
|
});
|
|
58
58
|
return {
|
|
59
59
|
assistantEvent: result.assistantEvent,
|
|
60
|
-
|
|
60
|
+
actionRequests: result.toolCalls.map((entry) => ({
|
|
61
|
+
actionRef: String(entry.toolCallId),
|
|
62
|
+
actionName: String(entry.toolName),
|
|
63
|
+
input: entry.args,
|
|
64
|
+
})),
|
|
61
65
|
messagesForModel: result.messagesForModel,
|
|
62
66
|
llm: result.llm,
|
|
63
67
|
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { ModelMessage } from "ai";
|
|
2
2
|
import type { ThreadEnvironment } from "../thread.config.js";
|
|
3
3
|
import type { ThreadItem } from "../thread.store.js";
|
|
4
|
-
import type { ThreadReactionLLM,
|
|
4
|
+
import type { ThreadReactionLLM, ThreadActionRequest, ThreadReactor, ThreadReactorParams } from "./types.js";
|
|
5
5
|
type ScriptedReactionPayload = {
|
|
6
6
|
assistantEvent?: Partial<ThreadItem>;
|
|
7
|
-
|
|
7
|
+
actionRequests?: ThreadActionRequest[];
|
|
8
8
|
messagesForModel?: ModelMessage[];
|
|
9
9
|
llm?: ThreadReactionLLM;
|
|
10
10
|
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { OUTPUT_ITEM_TYPE } from "../thread.events.js";
|
|
1
2
|
function normalizeScriptedAssistantEvent(params, assistantEvent) {
|
|
2
3
|
const fallback = {
|
|
3
4
|
id: params.eventId,
|
|
4
|
-
type:
|
|
5
|
+
type: OUTPUT_ITEM_TYPE,
|
|
5
6
|
channel: params.triggerEvent.channel,
|
|
6
7
|
createdAt: new Date().toISOString(),
|
|
7
8
|
content: { parts: [] },
|
|
@@ -46,7 +47,7 @@ export function createScriptedReactor(options) {
|
|
|
46
47
|
: scriptedStep;
|
|
47
48
|
return {
|
|
48
49
|
assistantEvent: normalizeScriptedAssistantEvent(params, payload.assistantEvent),
|
|
49
|
-
|
|
50
|
+
actionRequests: Array.isArray(payload.actionRequests) ? payload.actionRequests : [],
|
|
50
51
|
messagesForModel: Array.isArray(payload.messagesForModel)
|
|
51
52
|
? payload.messagesForModel
|
|
52
53
|
: [],
|
package/dist/reactors/types.d.ts
CHANGED
|
@@ -3,10 +3,10 @@ import type { ThreadEnvironment } from "../thread.config.js";
|
|
|
3
3
|
import type { ThreadModelInit } from "../thread.engine.js";
|
|
4
4
|
import type { ContextIdentifier, StoredContext, ThreadItem } from "../thread.store.js";
|
|
5
5
|
import type { SerializableToolForModel } from "../tools-to-model-tools.js";
|
|
6
|
-
export type
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
export type ThreadActionRequest = {
|
|
7
|
+
actionRef: string;
|
|
8
|
+
actionName: string;
|
|
9
|
+
input: unknown;
|
|
10
10
|
};
|
|
11
11
|
export type ThreadReactionLLM = {
|
|
12
12
|
provider?: string;
|
|
@@ -22,7 +22,7 @@ export type ThreadReactionLLM = {
|
|
|
22
22
|
};
|
|
23
23
|
export type ThreadReactionResult = {
|
|
24
24
|
assistantEvent: ThreadItem;
|
|
25
|
-
|
|
25
|
+
actionRequests: ThreadActionRequest[];
|
|
26
26
|
messagesForModel: ModelMessage[];
|
|
27
27
|
llm?: ThreadReactionLLM;
|
|
28
28
|
};
|
package/dist/schema.js
CHANGED
|
@@ -8,14 +8,14 @@ export const threadDomain = domain("thread")
|
|
|
8
8
|
updatedAt: i.date().optional(),
|
|
9
9
|
key: i.string().optional().indexed().unique(),
|
|
10
10
|
name: i.string().optional(),
|
|
11
|
-
status: i.string().optional().indexed(), //
|
|
11
|
+
status: i.string().optional().indexed(), // idle | streaming
|
|
12
12
|
}),
|
|
13
13
|
thread_contexts: i.entity({
|
|
14
14
|
createdAt: i.date(),
|
|
15
15
|
updatedAt: i.date().optional(),
|
|
16
16
|
// Required for prefix/history queries that use `$like` over context keys.
|
|
17
17
|
key: i.string().optional().indexed().unique(),
|
|
18
|
-
status: i.string().optional().indexed(), // open |
|
|
18
|
+
status: i.string().optional().indexed(), // open | closed
|
|
19
19
|
content: i.any().optional(),
|
|
20
20
|
}),
|
|
21
21
|
thread_items: i.entity({
|
|
@@ -36,13 +36,14 @@ export const threadDomain = domain("thread")
|
|
|
36
36
|
updatedAt: i.date().optional(),
|
|
37
37
|
status: i.string().optional().indexed(), // running | completed | failed
|
|
38
38
|
iteration: i.number().indexed(),
|
|
39
|
-
// Deterministic ids generated in step runtime;
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
39
|
+
// Deterministic ids generated in step runtime; linked to execution/item entities.
|
|
40
|
+
kind: i.string().optional().indexed(), // message | action_execute | action_result
|
|
41
|
+
actionName: i.string().optional().indexed(),
|
|
42
|
+
actionInput: i.any().optional(),
|
|
43
|
+
actionOutput: i.any().optional(),
|
|
44
|
+
actionError: i.string().optional(),
|
|
45
|
+
actionRequests: i.any().optional(),
|
|
46
|
+
actionResults: i.any().optional(),
|
|
46
47
|
continueLoop: i.boolean().optional(),
|
|
47
48
|
errorText: i.string().optional(),
|
|
48
49
|
}),
|
|
@@ -7,7 +7,7 @@ import type { ThreadModelInit } from "../thread.engine.js";
|
|
|
7
7
|
*
|
|
8
8
|
* - Performs the provider/network call in a step (Node/runtime allowed).
|
|
9
9
|
* - Pipes AI SDK UI message chunks into the workflow-owned writable stream.
|
|
10
|
-
* - Returns the assistant event + extracted
|
|
10
|
+
* - Returns the assistant event + extracted action requests for the workflow loop.
|
|
11
11
|
*/
|
|
12
12
|
export declare function doThreadStreamStep(params: {
|
|
13
13
|
model: ThreadModelInit;
|
|
@@ -26,5 +26,9 @@ export declare function doThreadStreamStep(params: {
|
|
|
26
26
|
sendStart?: boolean;
|
|
27
27
|
}): Promise<{
|
|
28
28
|
assistantEvent: ThreadItem;
|
|
29
|
-
|
|
29
|
+
actionRequests: {
|
|
30
|
+
actionRef: string;
|
|
31
|
+
actionName: string;
|
|
32
|
+
input: any;
|
|
33
|
+
}[];
|
|
30
34
|
}>;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { OUTPUT_ITEM_TYPE } from "../thread.events.js";
|
|
2
2
|
/**
|
|
3
3
|
* Runs a single LLM streaming step as a Workflow step.
|
|
4
4
|
*
|
|
5
5
|
* - Performs the provider/network call in a step (Node/runtime allowed).
|
|
6
6
|
* - Pipes AI SDK UI message chunks into the workflow-owned writable stream.
|
|
7
|
-
* - Returns the assistant event + extracted
|
|
7
|
+
* - Returns the assistant event + extracted action requests for the workflow loop.
|
|
8
8
|
*/
|
|
9
9
|
export async function doThreadStreamStep(params) {
|
|
10
10
|
"use step";
|
|
@@ -62,7 +62,7 @@ export async function doThreadStreamStep(params) {
|
|
|
62
62
|
const lastMessage = messages[messages.length - 1];
|
|
63
63
|
const event = {
|
|
64
64
|
id: params.eventId,
|
|
65
|
-
type:
|
|
65
|
+
type: OUTPUT_ITEM_TYPE,
|
|
66
66
|
channel: "web",
|
|
67
67
|
createdAt: new Date().toISOString(),
|
|
68
68
|
content: { parts: lastMessage?.parts ?? [] },
|
|
@@ -84,9 +84,13 @@ export async function doThreadStreamStep(params) {
|
|
|
84
84
|
}));
|
|
85
85
|
await uiStream.pipeTo(writable, { preventClose: true });
|
|
86
86
|
const assistantEvent = await finishPromise;
|
|
87
|
-
const
|
|
87
|
+
const actionRequests = extractToolCallsFromParts(assistantEvent?.content?.parts).map((entry) => ({
|
|
88
|
+
actionRef: String(entry.toolCallId),
|
|
89
|
+
actionName: String(entry.toolName),
|
|
90
|
+
input: entry.args,
|
|
91
|
+
}));
|
|
88
92
|
return {
|
|
89
93
|
assistantEvent,
|
|
90
|
-
|
|
94
|
+
actionRequests,
|
|
91
95
|
};
|
|
92
96
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { OUTPUT_ITEM_TYPE } from "../thread.events.js";
|
|
2
|
+
import { mapAiSdkChunkToThreadEvent } from "../reactors/ai-sdk.chunk-map.js";
|
|
2
3
|
import { writeThreadTraceEvents } from "./trace.steps.js";
|
|
3
4
|
async function readWorkflowMetadata() {
|
|
4
5
|
try {
|
|
@@ -10,19 +11,17 @@ async function readWorkflowMetadata() {
|
|
|
10
11
|
}
|
|
11
12
|
}
|
|
12
13
|
async function resolveWorkflowRunId(env, executionId) {
|
|
13
|
-
const
|
|
14
|
-
let runId =
|
|
15
|
-
?
|
|
14
|
+
const envRunId = env?.workflowRunId;
|
|
15
|
+
let runId = typeof envRunId === "string" && envRunId.trim()
|
|
16
|
+
? envRunId.trim()
|
|
16
17
|
: "";
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
runId = envRunId.trim();
|
|
21
|
-
}
|
|
18
|
+
const meta = runId ? null : await readWorkflowMetadata();
|
|
19
|
+
if (!runId && meta && meta.workflowRunId !== undefined && meta.workflowRunId !== null) {
|
|
20
|
+
runId = String(meta.workflowRunId);
|
|
22
21
|
}
|
|
23
22
|
if (!runId && executionId) {
|
|
24
23
|
try {
|
|
25
|
-
const { getThreadRuntime } = await import("
|
|
24
|
+
const { getThreadRuntime } = await import("../runtime.js");
|
|
26
25
|
const runtime = await getThreadRuntime(env);
|
|
27
26
|
const db = runtime?.db;
|
|
28
27
|
if (db) {
|
|
@@ -82,7 +81,7 @@ function safeErrorJson(error) {
|
|
|
82
81
|
*/
|
|
83
82
|
export async function executeReaction(params) {
|
|
84
83
|
"use step";
|
|
85
|
-
const { getThreadRuntime } = await import("
|
|
84
|
+
const { getThreadRuntime } = await import("../runtime.js");
|
|
86
85
|
const { store } = await getThreadRuntime(params.env);
|
|
87
86
|
let events;
|
|
88
87
|
try {
|
|
@@ -132,10 +131,13 @@ export async function executeReaction(params) {
|
|
|
132
131
|
result.consumeStream();
|
|
133
132
|
let resolveFinish;
|
|
134
133
|
let rejectFinish;
|
|
134
|
+
let chunkSequence = 0;
|
|
135
135
|
const finishPromise = new Promise((resolve, reject) => {
|
|
136
136
|
resolveFinish = resolve;
|
|
137
137
|
rejectFinish = reject;
|
|
138
138
|
});
|
|
139
|
+
const modelId = typeof params.model === "string" ? params.model : "";
|
|
140
|
+
const mappedProvider = modelId.includes("/") ? modelId.split("/")[0] : undefined;
|
|
139
141
|
const uiStream = result
|
|
140
142
|
.toUIMessageStream({
|
|
141
143
|
sendStart: Boolean(params.sendStart),
|
|
@@ -147,7 +149,7 @@ export async function executeReaction(params) {
|
|
|
147
149
|
const lastMessage = messages[messages.length - 1];
|
|
148
150
|
const event = {
|
|
149
151
|
id: params.eventId,
|
|
150
|
-
type:
|
|
152
|
+
type: OUTPUT_ITEM_TYPE,
|
|
151
153
|
channel: "web",
|
|
152
154
|
createdAt: new Date().toISOString(),
|
|
153
155
|
content: { parts: lastMessage?.parts ?? [] },
|
|
@@ -162,6 +164,24 @@ export async function executeReaction(params) {
|
|
|
162
164
|
// Filter out per-step finish boundary. Workflow will emit a single finish.
|
|
163
165
|
.pipeThrough(new TransformStream({
|
|
164
166
|
transform(chunk, controller) {
|
|
167
|
+
const contextId = typeof params.contextId === "string" && params.contextId.length > 0
|
|
168
|
+
? params.contextId
|
|
169
|
+
: undefined;
|
|
170
|
+
if (contextId) {
|
|
171
|
+
const mapped = mapAiSdkChunkToThreadEvent({
|
|
172
|
+
chunk,
|
|
173
|
+
contextId,
|
|
174
|
+
executionId: params.executionId,
|
|
175
|
+
stepId: params.stepId,
|
|
176
|
+
itemId: params.eventId,
|
|
177
|
+
provider: mappedProvider,
|
|
178
|
+
sequence: ++chunkSequence,
|
|
179
|
+
});
|
|
180
|
+
controller.enqueue({
|
|
181
|
+
type: "data-chunk.emitted",
|
|
182
|
+
data: mapped,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
165
185
|
if (chunk.type === "finish")
|
|
166
186
|
return;
|
|
167
187
|
controller.enqueue(chunk);
|
|
@@ -209,7 +229,6 @@ export async function executeReaction(params) {
|
|
|
209
229
|
const usageJson = toPlainJson(usage);
|
|
210
230
|
const providerMetadataJson = toPlainJson(providerMetadata);
|
|
211
231
|
// Derive provider/model from gateway id when available.
|
|
212
|
-
const modelId = typeof params.model === "string" ? params.model : "";
|
|
213
232
|
const provider = modelId.includes("/") ? modelId.split("/")[0] : providerMetadata?.provider;
|
|
214
233
|
const model = modelId.includes("/") ? modelId.split("/").slice(1).join("/") : providerMetadata?.model;
|
|
215
234
|
// Token accounting: attempt to read cached prompt tokens from OpenAI-like usage shapes.
|
|
@@ -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
|
|
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:
|
|
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
|
-
|
|
81
|
-
|
|
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
|
};
|