@ekairos/events 1.22.35-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.
Files changed (73) hide show
  1. package/README.md +5 -3
  2. package/dist/codex.d.ts +11 -2
  3. package/dist/codex.js +16 -8
  4. package/dist/context.action-calls.d.ts +48 -0
  5. package/dist/context.action-calls.js +123 -0
  6. package/dist/context.action.d.ts +55 -0
  7. package/dist/context.action.js +25 -0
  8. package/dist/context.builder.d.ts +71 -43
  9. package/dist/context.builder.js +123 -28
  10. package/dist/context.config.d.ts +2 -1
  11. package/dist/context.config.js +8 -3
  12. package/dist/context.contract.d.ts +2 -4
  13. package/dist/context.contract.js +3 -9
  14. package/dist/context.d.ts +3 -2
  15. package/dist/context.engine.d.ts +60 -52
  16. package/dist/context.engine.js +506 -297
  17. package/dist/context.events.js +28 -87
  18. package/dist/context.js +1 -0
  19. package/dist/context.part-identity.d.ts +40 -0
  20. package/dist/context.part-identity.js +270 -0
  21. package/dist/context.parts.d.ts +389 -164
  22. package/dist/context.parts.js +343 -218
  23. package/dist/context.registry.d.ts +1 -1
  24. package/dist/context.runtime.d.ts +14 -4
  25. package/dist/context.runtime.js +21 -3
  26. package/dist/context.step-stream.d.ts +16 -2
  27. package/dist/context.step-stream.js +58 -16
  28. package/dist/context.store.d.ts +55 -10
  29. package/dist/context.stream.d.ts +14 -4
  30. package/dist/context.stream.js +31 -3
  31. package/dist/domain.d.ts +1 -0
  32. package/dist/domain.js +1 -0
  33. package/dist/index.d.ts +13 -10
  34. package/dist/index.js +7 -6
  35. package/dist/react.context-event-parts.d.ts +18 -0
  36. package/dist/react.context-event-parts.js +509 -0
  37. package/dist/react.d.ts +7 -42
  38. package/dist/react.js +4 -87
  39. package/dist/react.step-stream.d.ts +39 -0
  40. package/dist/react.step-stream.js +625 -0
  41. package/dist/react.types.d.ts +121 -0
  42. package/dist/react.types.js +2 -0
  43. package/dist/react.use-context.d.ts +7 -0
  44. package/dist/react.use-context.js +867 -0
  45. package/dist/reactors/ai-sdk.chunk-map.d.ts +1 -0
  46. package/dist/reactors/ai-sdk.chunk-map.js +56 -5
  47. package/dist/reactors/ai-sdk.reactor.d.ts +8 -9
  48. package/dist/reactors/ai-sdk.reactor.js +6 -9
  49. package/dist/reactors/ai-sdk.step.d.ts +4 -5
  50. package/dist/reactors/ai-sdk.step.js +24 -17
  51. package/dist/reactors/scripted.reactor.d.ts +7 -4
  52. package/dist/reactors/types.d.ts +19 -10
  53. package/dist/runtime.d.ts +6 -0
  54. package/dist/runtime.js +9 -0
  55. package/dist/runtime.step.js +1 -1
  56. package/dist/schema.d.ts +268 -2
  57. package/dist/schema.js +4 -9
  58. package/dist/steps/do-context-stream-step.js +4 -4
  59. package/dist/steps/durable.steps.d.ts +28 -0
  60. package/dist/steps/durable.steps.js +34 -0
  61. package/dist/steps/store.steps.d.ts +64 -22
  62. package/dist/steps/store.steps.js +192 -35
  63. package/dist/steps/stream.steps.d.ts +32 -0
  64. package/dist/steps/stream.steps.js +124 -6
  65. package/dist/steps/trace.steps.d.ts +4 -4
  66. package/dist/steps/trace.steps.js +21 -6
  67. package/dist/stores/instant.store.d.ts +11 -11
  68. package/dist/stores/instant.store.js +136 -6
  69. package/dist/tools-to-model-tools.d.ts +4 -2
  70. package/dist/tools-to-model-tools.js +30 -11
  71. package/package.json +18 -7
  72. package/dist/context.toolcalls.d.ts +0 -60
  73. package/dist/context.toolcalls.js +0 -117
@@ -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 === "content") {
127
- uiParts.push(...part.content.flatMap((block) => contentBlockToPrimaryUiParts(block)));
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
- const text = part.content
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 === "tool-call") {
133
+ if (part.type === "action" && part.content.status === "started") {
149
134
  uiParts.push({
150
- type: `tool-${part.toolName}`,
151
- toolCallId: part.toolCallId,
152
- state: part.state ?? "input-available",
153
- input: toolCallContentToInput(part.content),
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 toolInputs = new Map();
145
+ const actionInputs = new Map();
201
146
  const toolResults = [];
202
147
  for (const part of parts) {
203
- if (part.type === "tool-call") {
204
- toolInputs.set(part.toolCallId, toolCallContentToInput(part.content));
148
+ if (part.type !== "action") {
205
149
  continue;
206
150
  }
207
- if (part.type !== "tool-result") {
151
+ if (part.content.status === "started") {
152
+ actionInputs.set(part.content.actionCallId, part.content.input);
208
153
  continue;
209
154
  }
210
- if (part.state === "output-error") {
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.toolCallId,
218
- toolName: part.toolName,
219
- input: toolInputs.get(part.toolCallId),
220
- error: text || "Tool execution failed.",
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.toolCallId,
227
- toolName: part.toolName,
228
- output: canonicalToolResultContentToOutput(part.content),
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
+ }