@ekairos/events 1.22.34-beta.development.0 → 1.22.35
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 +58 -83
- package/dist/codex.d.ts +11 -2
- package/dist/codex.js +16 -8
- package/dist/context.action-calls.d.ts +48 -0
- package/dist/context.action-calls.js +123 -0
- package/dist/context.action.d.ts +55 -0
- package/dist/context.action.js +25 -0
- package/dist/context.builder.d.ts +71 -43
- package/dist/context.builder.js +123 -28
- package/dist/context.config.d.ts +2 -1
- package/dist/context.config.js +8 -3
- package/dist/context.contract.d.ts +2 -4
- package/dist/context.contract.js +3 -9
- package/dist/context.d.ts +3 -2
- package/dist/context.engine.d.ts +75 -46
- package/dist/context.engine.js +538 -302
- package/dist/context.events.js +28 -87
- package/dist/context.js +1 -0
- package/dist/context.part-identity.d.ts +40 -0
- package/dist/context.part-identity.js +270 -0
- package/dist/context.parts.d.ts +389 -164
- package/dist/context.parts.js +343 -218
- package/dist/context.registry.d.ts +1 -1
- package/dist/context.runtime.d.ts +21 -0
- package/dist/context.runtime.js +39 -0
- package/dist/context.step-stream.d.ts +16 -2
- package/dist/context.step-stream.js +58 -16
- package/dist/context.store.d.ts +63 -10
- package/dist/context.stream.d.ts +14 -4
- package/dist/context.stream.js +31 -3
- package/dist/domain.d.ts +1 -0
- package/dist/domain.js +1 -0
- package/dist/index.d.ts +13 -10
- package/dist/index.js +7 -6
- package/dist/react.context-event-parts.d.ts +18 -0
- package/dist/react.context-event-parts.js +509 -0
- package/dist/react.d.ts +7 -42
- package/dist/react.js +4 -87
- package/dist/react.step-stream.d.ts +39 -0
- package/dist/react.step-stream.js +625 -0
- package/dist/react.types.d.ts +121 -0
- package/dist/react.types.js +2 -0
- package/dist/react.use-context.d.ts +7 -0
- package/dist/react.use-context.js +867 -0
- package/dist/reactors/ai-sdk.chunk-map.d.ts +1 -0
- package/dist/reactors/ai-sdk.chunk-map.js +56 -5
- package/dist/reactors/ai-sdk.reactor.d.ts +8 -5
- package/dist/reactors/ai-sdk.reactor.js +10 -9
- package/dist/reactors/ai-sdk.step.d.ts +6 -6
- package/dist/reactors/ai-sdk.step.js +32 -24
- package/dist/reactors/scripted.reactor.d.ts +7 -4
- package/dist/reactors/types.d.ts +23 -8
- package/dist/runtime.d.ts +6 -0
- package/dist/runtime.js +9 -0
- package/dist/runtime.step.js +2 -2
- package/dist/schema.d.ts +268 -2
- package/dist/schema.js +5 -9
- package/dist/steps/do-context-stream-step.d.ts +2 -2
- package/dist/steps/do-context-stream-step.js +6 -8
- package/dist/steps/durable.steps.d.ts +28 -0
- package/dist/steps/durable.steps.js +34 -0
- package/dist/steps/store.steps.d.ts +121 -39
- package/dist/steps/store.steps.js +266 -111
- package/dist/steps/stream.steps.d.ts +36 -3
- package/dist/steps/stream.steps.js +137 -14
- package/dist/steps/trace.steps.d.ts +4 -2
- package/dist/steps/trace.steps.js +26 -8
- package/dist/stores/instant.store.d.ts +15 -11
- package/dist/stores/instant.store.js +155 -6
- package/dist/tools-to-model-tools.d.ts +39 -3
- package/dist/tools-to-model-tools.js +63 -6
- package/package.json +20 -6
- package/dist/context.toolcalls.d.ts +0 -60
- package/dist/context.toolcalls.js +0 -117
package/dist/context.events.js
CHANGED
|
@@ -44,9 +44,6 @@ function isToolUIPart(value) {
|
|
|
44
44
|
function readToolNameFromPart(part) {
|
|
45
45
|
return String(part.type).split("-").slice(1).join("-");
|
|
46
46
|
}
|
|
47
|
-
function stripDataUrlPrefix(value) {
|
|
48
|
-
return value.replace(/^data:[^;]+;base64,/i, "");
|
|
49
|
-
}
|
|
50
47
|
function asCanonicalParts(parts) {
|
|
51
48
|
return normalizePartsForPersistence(parts);
|
|
52
49
|
}
|
|
@@ -107,125 +104,69 @@ function contentBlockToPrimaryUiParts(block) {
|
|
|
107
104
|
}
|
|
108
105
|
return [];
|
|
109
106
|
}
|
|
110
|
-
function toolCallContentToInput(content) {
|
|
111
|
-
if (content.length === 0)
|
|
112
|
-
return undefined;
|
|
113
|
-
if (content.length === 1) {
|
|
114
|
-
const first = content[0];
|
|
115
|
-
if (first.type === "json")
|
|
116
|
-
return first.value;
|
|
117
|
-
if (first.type === "text")
|
|
118
|
-
return first.text;
|
|
119
|
-
return first;
|
|
120
|
-
}
|
|
121
|
-
return content;
|
|
122
|
-
}
|
|
123
107
|
function canonicalPartsToPrimaryUiParts(parts) {
|
|
124
108
|
const uiParts = [];
|
|
125
109
|
for (const part of parts) {
|
|
126
|
-
if (part.type === "
|
|
127
|
-
|
|
110
|
+
if (part.type === "message") {
|
|
111
|
+
if (part.content.text) {
|
|
112
|
+
uiParts.push({ type: "text", text: part.content.text });
|
|
113
|
+
}
|
|
114
|
+
if (Array.isArray(part.content.blocks)) {
|
|
115
|
+
uiParts.push(...part.content.blocks.flatMap((block) => contentBlockToPrimaryUiParts(block)));
|
|
116
|
+
}
|
|
128
117
|
continue;
|
|
129
118
|
}
|
|
130
119
|
if (part.type === "reasoning") {
|
|
131
|
-
|
|
132
|
-
.filter((block) => block.type === "text")
|
|
133
|
-
.map((block) => block.text)
|
|
134
|
-
.join("\n\n");
|
|
135
|
-
if (text.trim()) {
|
|
120
|
+
if (part.content.text.trim()) {
|
|
136
121
|
uiParts.push({
|
|
137
122
|
type: "reasoning",
|
|
138
|
-
text,
|
|
139
|
-
state: part.state,
|
|
123
|
+
text: part.content.text,
|
|
124
|
+
state: part.content.state,
|
|
140
125
|
});
|
|
141
126
|
}
|
|
142
127
|
continue;
|
|
143
128
|
}
|
|
144
129
|
if (part.type === "source") {
|
|
145
|
-
uiParts.push(...part.content.flatMap((block) => contentBlockToPrimaryUiParts(block)));
|
|
130
|
+
uiParts.push(...part.content.sources.flatMap((block) => contentBlockToPrimaryUiParts(block)));
|
|
146
131
|
continue;
|
|
147
132
|
}
|
|
148
|
-
if (part.type === "
|
|
133
|
+
if (part.type === "action" && part.content.status === "started") {
|
|
149
134
|
uiParts.push({
|
|
150
|
-
type: `tool-${part.
|
|
151
|
-
toolCallId: part.
|
|
152
|
-
state:
|
|
153
|
-
input:
|
|
135
|
+
type: `tool-${part.content.actionName}`,
|
|
136
|
+
toolCallId: part.content.actionCallId,
|
|
137
|
+
state: "input-available",
|
|
138
|
+
input: part.content.input,
|
|
154
139
|
});
|
|
155
140
|
}
|
|
156
141
|
}
|
|
157
142
|
return uiParts;
|
|
158
143
|
}
|
|
159
|
-
function canonicalToolResultContentToOutput(content) {
|
|
160
|
-
if (content.length === 1 && content[0]?.type === "json") {
|
|
161
|
-
return {
|
|
162
|
-
type: "json",
|
|
163
|
-
value: content[0].value,
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
return {
|
|
167
|
-
type: "content",
|
|
168
|
-
value: content.map((block) => {
|
|
169
|
-
if (block.type === "text") {
|
|
170
|
-
return {
|
|
171
|
-
type: "text",
|
|
172
|
-
text: block.text,
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
if (block.type === "file") {
|
|
176
|
-
return {
|
|
177
|
-
type: "media",
|
|
178
|
-
mediaType: block.mediaType,
|
|
179
|
-
data: typeof block.data === "string" && block.data.length > 0
|
|
180
|
-
? stripDataUrlPrefix(block.data)
|
|
181
|
-
: typeof block.url === "string" && block.url.length > 0
|
|
182
|
-
? block.url
|
|
183
|
-
: block.fileId,
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
if (block.type === "json") {
|
|
187
|
-
return {
|
|
188
|
-
type: "text",
|
|
189
|
-
text: JSON.stringify(block.value, null, 2),
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
return {
|
|
193
|
-
type: "text",
|
|
194
|
-
text: JSON.stringify(block),
|
|
195
|
-
};
|
|
196
|
-
}),
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
144
|
function canonicalToolPartsToModelMessages(parts) {
|
|
200
|
-
const
|
|
145
|
+
const actionInputs = new Map();
|
|
201
146
|
const toolResults = [];
|
|
202
147
|
for (const part of parts) {
|
|
203
|
-
if (part.type
|
|
204
|
-
toolInputs.set(part.toolCallId, toolCallContentToInput(part.content));
|
|
148
|
+
if (part.type !== "action") {
|
|
205
149
|
continue;
|
|
206
150
|
}
|
|
207
|
-
if (part.
|
|
151
|
+
if (part.content.status === "started") {
|
|
152
|
+
actionInputs.set(part.content.actionCallId, part.content.input);
|
|
208
153
|
continue;
|
|
209
154
|
}
|
|
210
|
-
if (part.
|
|
211
|
-
const text = part.content
|
|
212
|
-
.filter((block) => block.type === "text")
|
|
213
|
-
.map((block) => block.text)
|
|
214
|
-
.join("\n\n");
|
|
155
|
+
if (part.content.status === "failed") {
|
|
215
156
|
toolResults.push({
|
|
216
157
|
type: "tool-error",
|
|
217
|
-
toolCallId: part.
|
|
218
|
-
toolName: part.
|
|
219
|
-
input:
|
|
220
|
-
error:
|
|
158
|
+
toolCallId: part.content.actionCallId,
|
|
159
|
+
toolName: part.content.actionName,
|
|
160
|
+
input: actionInputs.get(part.content.actionCallId),
|
|
161
|
+
error: part.content.error.message || "Action execution failed.",
|
|
221
162
|
});
|
|
222
163
|
continue;
|
|
223
164
|
}
|
|
224
165
|
toolResults.push({
|
|
225
166
|
type: "tool-result",
|
|
226
|
-
toolCallId: part.
|
|
227
|
-
toolName: part.
|
|
228
|
-
output:
|
|
167
|
+
toolCallId: part.content.actionCallId,
|
|
168
|
+
toolName: part.content.actionName,
|
|
169
|
+
output: normalizeContextOutputPart(part.content.output),
|
|
229
170
|
});
|
|
230
171
|
}
|
|
231
172
|
if (toolResults.length === 0) {
|
package/dist/context.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { ContextEngine, runContextReactionDirect, } from "./context.engine.js";
|
|
2
2
|
export { context, createContext, } from "./context.builder.js";
|
|
3
|
+
export { defineAction, action, } from "./context.action.js";
|
|
3
4
|
export { createAiSdkReactor, createScriptedReactor, } from "./context.reactor.js";
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ContextStreamChunkType } from "./context.contract.js";
|
|
2
|
+
export declare const CONTEXT_PART_ID_NAMESPACE = "8be4c3a0-9e67-4f26-b60f-52b5b04d4b8d";
|
|
3
|
+
export declare const CONTEXT_PART_UUID_RE: RegExp;
|
|
4
|
+
export declare const CONTEXT_STREAM_PART_TYPES: readonly ["message", "reasoning", "source", "action"];
|
|
5
|
+
export type ContextStreamPartType = (typeof CONTEXT_STREAM_PART_TYPES)[number];
|
|
6
|
+
export type ContextStreamPartSlot = "message" | "reasoning" | "source" | "action:started" | "action:completed" | "action:failed";
|
|
7
|
+
export type ContextPartChunkIdentityInput = {
|
|
8
|
+
stepId?: string;
|
|
9
|
+
provider?: string;
|
|
10
|
+
providerPartId?: string;
|
|
11
|
+
chunkType: ContextStreamChunkType | string;
|
|
12
|
+
partType?: ContextStreamPartType | string;
|
|
13
|
+
partSlot?: ContextStreamPartSlot | string;
|
|
14
|
+
};
|
|
15
|
+
export type ContextPartChunkValidationInput = ContextPartChunkIdentityInput & {
|
|
16
|
+
partId?: string;
|
|
17
|
+
actionRef?: string;
|
|
18
|
+
label?: string;
|
|
19
|
+
};
|
|
20
|
+
export type ContextPartChunkDescriptor = {
|
|
21
|
+
providerPartId: string;
|
|
22
|
+
partType: ContextStreamPartType;
|
|
23
|
+
partSlot: ContextStreamPartSlot;
|
|
24
|
+
};
|
|
25
|
+
export type ContextPartChunkIdentity = ContextPartChunkDescriptor & {
|
|
26
|
+
partId: string;
|
|
27
|
+
};
|
|
28
|
+
export declare function uuidV5(name: string, namespace?: string): string;
|
|
29
|
+
export declare function resolveContextStreamPartType(chunkType: ContextStreamChunkType | string): ContextStreamPartType | undefined;
|
|
30
|
+
export declare function resolveContextStreamPartSlot(chunkType: ContextStreamChunkType | string, partType?: "message" | "reasoning" | "source" | "action" | undefined): ContextStreamPartSlot | undefined;
|
|
31
|
+
export declare function resolveContextPartChunkDescriptor(input: ContextPartChunkIdentityInput): ContextPartChunkDescriptor | undefined;
|
|
32
|
+
export declare function resolveContextPartId(input: {
|
|
33
|
+
stepId: string;
|
|
34
|
+
provider: string;
|
|
35
|
+
providerPartId: string;
|
|
36
|
+
partType: string;
|
|
37
|
+
partSlot: string;
|
|
38
|
+
}): string;
|
|
39
|
+
export declare function resolveContextPartChunkIdentity(input: ContextPartChunkIdentityInput): ContextPartChunkIdentity | undefined;
|
|
40
|
+
export declare function assertValidContextPartChunkIdentity(input: ContextPartChunkValidationInput): void;
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
export const CONTEXT_PART_ID_NAMESPACE = "8be4c3a0-9e67-4f26-b60f-52b5b04d4b8d";
|
|
2
|
+
export const CONTEXT_PART_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-5[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
3
|
+
export const CONTEXT_STREAM_PART_TYPES = [
|
|
4
|
+
"message",
|
|
5
|
+
"reasoning",
|
|
6
|
+
"source",
|
|
7
|
+
"action",
|
|
8
|
+
];
|
|
9
|
+
const TEXT_ENCODER = new TextEncoder();
|
|
10
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
11
|
+
const ID_SEPARATOR = "\u001f";
|
|
12
|
+
function normalizeIdentityField(value) {
|
|
13
|
+
return typeof value === "string" ? value.trim() : "";
|
|
14
|
+
}
|
|
15
|
+
function fieldLabel(label, field) {
|
|
16
|
+
return `${label}.${field}`;
|
|
17
|
+
}
|
|
18
|
+
function assertMissingPartIdentityField(value, label) {
|
|
19
|
+
if (typeof value !== "undefined") {
|
|
20
|
+
throw new Error(`Invalid ${label}: lifecycle/metadata chunks cannot carry part identity.`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function assertPartIdentityString(value, label) {
|
|
24
|
+
const normalized = normalizeIdentityField(value);
|
|
25
|
+
if (!normalized) {
|
|
26
|
+
throw new Error(`Invalid ${label}: expected non-empty string.`);
|
|
27
|
+
}
|
|
28
|
+
return normalized;
|
|
29
|
+
}
|
|
30
|
+
function rotateLeft(value, bits) {
|
|
31
|
+
return ((value << bits) | (value >>> (32 - bits))) >>> 0;
|
|
32
|
+
}
|
|
33
|
+
function sha1(bytes) {
|
|
34
|
+
const bitLength = bytes.length * 8;
|
|
35
|
+
const totalLength = Math.ceil((bytes.length + 1 + 8) / 64) * 64;
|
|
36
|
+
const message = new Uint8Array(totalLength);
|
|
37
|
+
message.set(bytes);
|
|
38
|
+
message[bytes.length] = 0x80;
|
|
39
|
+
const view = new DataView(message.buffer);
|
|
40
|
+
view.setUint32(totalLength - 8, Math.floor(bitLength / 0x100000000), false);
|
|
41
|
+
view.setUint32(totalLength - 4, bitLength >>> 0, false);
|
|
42
|
+
let h0 = 0x67452301;
|
|
43
|
+
let h1 = 0xefcdab89;
|
|
44
|
+
let h2 = 0x98badcfe;
|
|
45
|
+
let h3 = 0x10325476;
|
|
46
|
+
let h4 = 0xc3d2e1f0;
|
|
47
|
+
const words = new Uint32Array(80);
|
|
48
|
+
for (let offset = 0; offset < totalLength; offset += 64) {
|
|
49
|
+
for (let i = 0; i < 16; i += 1) {
|
|
50
|
+
words[i] = view.getUint32(offset + i * 4, false);
|
|
51
|
+
}
|
|
52
|
+
for (let i = 16; i < 80; i += 1) {
|
|
53
|
+
words[i] = rotateLeft(words[i - 3] ^ words[i - 8] ^ words[i - 14] ^ words[i - 16], 1);
|
|
54
|
+
}
|
|
55
|
+
let a = h0;
|
|
56
|
+
let b = h1;
|
|
57
|
+
let c = h2;
|
|
58
|
+
let d = h3;
|
|
59
|
+
let e = h4;
|
|
60
|
+
for (let i = 0; i < 80; i += 1) {
|
|
61
|
+
let f;
|
|
62
|
+
let k;
|
|
63
|
+
if (i < 20) {
|
|
64
|
+
f = (b & c) | (~b & d);
|
|
65
|
+
k = 0x5a827999;
|
|
66
|
+
}
|
|
67
|
+
else if (i < 40) {
|
|
68
|
+
f = b ^ c ^ d;
|
|
69
|
+
k = 0x6ed9eba1;
|
|
70
|
+
}
|
|
71
|
+
else if (i < 60) {
|
|
72
|
+
f = (b & c) | (b & d) | (c & d);
|
|
73
|
+
k = 0x8f1bbcdc;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
f = b ^ c ^ d;
|
|
77
|
+
k = 0xca62c1d6;
|
|
78
|
+
}
|
|
79
|
+
const temp = (rotateLeft(a, 5) + f + e + k + words[i]) >>> 0;
|
|
80
|
+
e = d;
|
|
81
|
+
d = c;
|
|
82
|
+
c = rotateLeft(b, 30);
|
|
83
|
+
b = a;
|
|
84
|
+
a = temp;
|
|
85
|
+
}
|
|
86
|
+
h0 = (h0 + a) >>> 0;
|
|
87
|
+
h1 = (h1 + b) >>> 0;
|
|
88
|
+
h2 = (h2 + c) >>> 0;
|
|
89
|
+
h3 = (h3 + d) >>> 0;
|
|
90
|
+
h4 = (h4 + e) >>> 0;
|
|
91
|
+
}
|
|
92
|
+
const out = new Uint8Array(20);
|
|
93
|
+
const outView = new DataView(out.buffer);
|
|
94
|
+
outView.setUint32(0, h0, false);
|
|
95
|
+
outView.setUint32(4, h1, false);
|
|
96
|
+
outView.setUint32(8, h2, false);
|
|
97
|
+
outView.setUint32(12, h3, false);
|
|
98
|
+
outView.setUint32(16, h4, false);
|
|
99
|
+
return out;
|
|
100
|
+
}
|
|
101
|
+
function uuidToBytes(uuid) {
|
|
102
|
+
const normalized = uuid.trim().toLowerCase();
|
|
103
|
+
if (!UUID_RE.test(normalized)) {
|
|
104
|
+
throw new Error(`Invalid UUID namespace: ${uuid}`);
|
|
105
|
+
}
|
|
106
|
+
const hex = normalized.replace(/-/g, "");
|
|
107
|
+
const bytes = new Uint8Array(16);
|
|
108
|
+
for (let i = 0; i < bytes.length; i += 1) {
|
|
109
|
+
bytes[i] = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
110
|
+
}
|
|
111
|
+
return bytes;
|
|
112
|
+
}
|
|
113
|
+
function formatUuid(bytes) {
|
|
114
|
+
const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
115
|
+
return [
|
|
116
|
+
hex.slice(0, 8),
|
|
117
|
+
hex.slice(8, 12),
|
|
118
|
+
hex.slice(12, 16),
|
|
119
|
+
hex.slice(16, 20),
|
|
120
|
+
hex.slice(20, 32),
|
|
121
|
+
].join("-");
|
|
122
|
+
}
|
|
123
|
+
export function uuidV5(name, namespace = CONTEXT_PART_ID_NAMESPACE) {
|
|
124
|
+
const namespaceBytes = uuidToBytes(namespace);
|
|
125
|
+
const nameBytes = TEXT_ENCODER.encode(name);
|
|
126
|
+
const input = new Uint8Array(namespaceBytes.length + nameBytes.length);
|
|
127
|
+
input.set(namespaceBytes);
|
|
128
|
+
input.set(nameBytes, namespaceBytes.length);
|
|
129
|
+
const bytes = sha1(input).slice(0, 16);
|
|
130
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x50;
|
|
131
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80;
|
|
132
|
+
return formatUuid(bytes);
|
|
133
|
+
}
|
|
134
|
+
export function resolveContextStreamPartType(chunkType) {
|
|
135
|
+
if (chunkType === "chunk.text_start" ||
|
|
136
|
+
chunkType === "chunk.text_delta" ||
|
|
137
|
+
chunkType === "chunk.text_end" ||
|
|
138
|
+
chunkType === "chunk.file") {
|
|
139
|
+
return "message";
|
|
140
|
+
}
|
|
141
|
+
if (chunkType === "chunk.reasoning_start" ||
|
|
142
|
+
chunkType === "chunk.reasoning_delta" ||
|
|
143
|
+
chunkType === "chunk.reasoning_end") {
|
|
144
|
+
return "reasoning";
|
|
145
|
+
}
|
|
146
|
+
if (chunkType === "chunk.source_url" || chunkType === "chunk.source_document") {
|
|
147
|
+
return "source";
|
|
148
|
+
}
|
|
149
|
+
if (chunkType === "chunk.action_started" ||
|
|
150
|
+
chunkType === "chunk.action_input_delta" ||
|
|
151
|
+
chunkType === "chunk.action_completed" ||
|
|
152
|
+
chunkType === "chunk.action_failed") {
|
|
153
|
+
return "action";
|
|
154
|
+
}
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
export function resolveContextStreamPartSlot(chunkType, partType = resolveContextStreamPartType(chunkType)) {
|
|
158
|
+
if (partType === "message")
|
|
159
|
+
return "message";
|
|
160
|
+
if (partType === "reasoning")
|
|
161
|
+
return "reasoning";
|
|
162
|
+
if (partType === "source")
|
|
163
|
+
return "source";
|
|
164
|
+
if (partType === "action") {
|
|
165
|
+
if (chunkType === "chunk.action_failed")
|
|
166
|
+
return "action:failed";
|
|
167
|
+
if (chunkType === "chunk.action_completed")
|
|
168
|
+
return "action:completed";
|
|
169
|
+
return "action:started";
|
|
170
|
+
}
|
|
171
|
+
return undefined;
|
|
172
|
+
}
|
|
173
|
+
export function resolveContextPartChunkDescriptor(input) {
|
|
174
|
+
const providerPartId = normalizeIdentityField(input.providerPartId);
|
|
175
|
+
if (!providerPartId)
|
|
176
|
+
return undefined;
|
|
177
|
+
const inferredPartType = resolveContextStreamPartType(input.chunkType);
|
|
178
|
+
const partType = normalizeIdentityField(input.partType || inferredPartType);
|
|
179
|
+
if (!CONTEXT_STREAM_PART_TYPES.includes(partType)) {
|
|
180
|
+
return undefined;
|
|
181
|
+
}
|
|
182
|
+
const partSlot = normalizeIdentityField(input.partSlot || resolveContextStreamPartSlot(input.chunkType, partType));
|
|
183
|
+
if (!partSlot)
|
|
184
|
+
return undefined;
|
|
185
|
+
return {
|
|
186
|
+
providerPartId,
|
|
187
|
+
partType,
|
|
188
|
+
partSlot,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
export function resolveContextPartId(input) {
|
|
192
|
+
const name = [
|
|
193
|
+
"context-part:v1",
|
|
194
|
+
input.stepId,
|
|
195
|
+
input.provider,
|
|
196
|
+
input.providerPartId,
|
|
197
|
+
input.partType,
|
|
198
|
+
input.partSlot,
|
|
199
|
+
].join(ID_SEPARATOR);
|
|
200
|
+
return uuidV5(name);
|
|
201
|
+
}
|
|
202
|
+
export function resolveContextPartChunkIdentity(input) {
|
|
203
|
+
const descriptor = resolveContextPartChunkDescriptor(input);
|
|
204
|
+
const stepId = normalizeIdentityField(input.stepId);
|
|
205
|
+
if (!descriptor || !stepId)
|
|
206
|
+
return undefined;
|
|
207
|
+
const provider = normalizeIdentityField(input.provider) || "unknown";
|
|
208
|
+
return {
|
|
209
|
+
...descriptor,
|
|
210
|
+
partId: resolveContextPartId({
|
|
211
|
+
stepId,
|
|
212
|
+
provider,
|
|
213
|
+
providerPartId: descriptor.providerPartId,
|
|
214
|
+
partType: descriptor.partType,
|
|
215
|
+
partSlot: descriptor.partSlot,
|
|
216
|
+
}),
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
export function assertValidContextPartChunkIdentity(input) {
|
|
220
|
+
const label = normalizeIdentityField(input.label) || "context stream chunk";
|
|
221
|
+
const expectedPartType = resolveContextStreamPartType(input.chunkType);
|
|
222
|
+
if (!expectedPartType) {
|
|
223
|
+
assertMissingPartIdentityField(input.partId, fieldLabel(label, "partId"));
|
|
224
|
+
assertMissingPartIdentityField(input.providerPartId, fieldLabel(label, "providerPartId"));
|
|
225
|
+
assertMissingPartIdentityField(input.partType, fieldLabel(label, "partType"));
|
|
226
|
+
assertMissingPartIdentityField(input.partSlot, fieldLabel(label, "partSlot"));
|
|
227
|
+
if (typeof input.actionRef !== "undefined") {
|
|
228
|
+
throw new Error(`Invalid ${fieldLabel(label, "actionRef")}: only action chunks can carry actionRef.`);
|
|
229
|
+
}
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
const expectedPartSlot = resolveContextStreamPartSlot(input.chunkType, expectedPartType);
|
|
233
|
+
const partId = assertPartIdentityString(input.partId, fieldLabel(label, "partId"));
|
|
234
|
+
if (!CONTEXT_PART_UUID_RE.test(partId)) {
|
|
235
|
+
throw new Error(`Invalid ${fieldLabel(label, "partId")}: expected deterministic UUID v5.`);
|
|
236
|
+
}
|
|
237
|
+
const provider = assertPartIdentityString(input.provider, fieldLabel(label, "provider"));
|
|
238
|
+
const providerPartId = assertPartIdentityString(input.providerPartId, fieldLabel(label, "providerPartId"));
|
|
239
|
+
const partType = assertPartIdentityString(input.partType, fieldLabel(label, "partType"));
|
|
240
|
+
const partSlot = assertPartIdentityString(input.partSlot, fieldLabel(label, "partSlot"));
|
|
241
|
+
if (partType !== expectedPartType) {
|
|
242
|
+
throw new Error(`Invalid ${fieldLabel(label, "partType")}: ${String(input.chunkType)} requires ${expectedPartType}.`);
|
|
243
|
+
}
|
|
244
|
+
if (partSlot !== expectedPartSlot) {
|
|
245
|
+
throw new Error(`Invalid ${fieldLabel(label, "partSlot")}: ${String(input.chunkType)} requires ${expectedPartSlot}.`);
|
|
246
|
+
}
|
|
247
|
+
const isActionChunk = expectedPartType === "action";
|
|
248
|
+
if (!isActionChunk && typeof input.actionRef !== "undefined") {
|
|
249
|
+
throw new Error(`Invalid ${fieldLabel(label, "actionRef")}: only action chunks can carry actionRef.`);
|
|
250
|
+
}
|
|
251
|
+
if (isActionChunk) {
|
|
252
|
+
const actionRef = assertPartIdentityString(input.actionRef, fieldLabel(label, "actionRef"));
|
|
253
|
+
if (actionRef !== providerPartId) {
|
|
254
|
+
throw new Error(`Invalid ${fieldLabel(label, "actionRef")}: action chunks require actionRef to match providerPartId.`);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
const stepId = normalizeIdentityField(input.stepId);
|
|
258
|
+
if (!stepId)
|
|
259
|
+
return;
|
|
260
|
+
const expectedPartId = resolveContextPartId({
|
|
261
|
+
stepId,
|
|
262
|
+
provider,
|
|
263
|
+
providerPartId,
|
|
264
|
+
partType,
|
|
265
|
+
partSlot,
|
|
266
|
+
});
|
|
267
|
+
if (partId !== expectedPartId) {
|
|
268
|
+
throw new Error(`Invalid ${fieldLabel(label, "partId")}: expected ${expectedPartId} for deterministic part identity.`);
|
|
269
|
+
}
|
|
270
|
+
}
|