@ekairos/events 1.22.4-beta.development.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 +115 -0
- package/dist/codex.d.ts +95 -0
- package/dist/codex.js +91 -0
- package/dist/context.builder.d.ts +62 -0
- package/dist/context.builder.js +143 -0
- package/dist/context.config.d.ts +9 -0
- package/dist/context.config.js +30 -0
- package/dist/context.contract.d.ts +47 -0
- package/dist/context.contract.js +132 -0
- package/dist/context.d.ts +4 -0
- package/dist/context.durable.d.ts +5 -0
- package/dist/context.durable.js +13 -0
- package/dist/context.engine.d.ts +216 -0
- package/dist/context.engine.js +1098 -0
- package/dist/context.events.d.ts +55 -0
- package/dist/context.events.js +431 -0
- package/dist/context.hooks.d.ts +21 -0
- package/dist/context.hooks.js +31 -0
- package/dist/context.js +3 -0
- package/dist/context.parts.d.ts +241 -0
- package/dist/context.parts.js +360 -0
- package/dist/context.reactor.d.ts +3 -0
- package/dist/context.reactor.js +2 -0
- package/dist/context.registry.d.ts +13 -0
- package/dist/context.registry.js +30 -0
- package/dist/context.skill.d.ts +9 -0
- package/dist/context.skill.js +1 -0
- package/dist/context.step-stream.d.ts +26 -0
- package/dist/context.step-stream.js +59 -0
- package/dist/context.store.d.ts +85 -0
- package/dist/context.store.js +1 -0
- package/dist/context.stream.d.ts +148 -0
- package/dist/context.stream.js +141 -0
- package/dist/context.toolcalls.d.ts +60 -0
- package/dist/context.toolcalls.js +117 -0
- package/dist/env.d.ts +3 -0
- package/dist/env.js +53 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +11 -0
- package/dist/mcp.d.ts +1 -0
- package/dist/mcp.js +1 -0
- package/dist/mirror.d.ts +41 -0
- package/dist/mirror.js +1 -0
- package/dist/oidc.d.ts +7 -0
- package/dist/oidc.js +25 -0
- package/dist/polyfills/dom-events.d.ts +1 -0
- package/dist/polyfills/dom-events.js +89 -0
- package/dist/react.d.ts +42 -0
- package/dist/react.js +88 -0
- 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.d.ts +33 -0
- package/dist/reactors/ai-sdk.reactor.js +65 -0
- package/dist/reactors/ai-sdk.step.d.ts +48 -0
- package/dist/reactors/ai-sdk.step.js +343 -0
- package/dist/reactors/scripted.reactor.d.ts +17 -0
- package/dist/reactors/scripted.reactor.js +51 -0
- package/dist/reactors/types.d.ts +52 -0
- package/dist/reactors/types.js +1 -0
- package/dist/runtime.d.ts +19 -0
- package/dist/runtime.js +26 -0
- package/dist/runtime.step.d.ts +9 -0
- package/dist/runtime.step.js +7 -0
- package/dist/schema.d.ts +2 -0
- package/dist/schema.js +191 -0
- package/dist/steps/do-context-stream-step.d.ts +34 -0
- package/dist/steps/do-context-stream-step.js +96 -0
- package/dist/steps/mirror.steps.d.ts +6 -0
- package/dist/steps/mirror.steps.js +48 -0
- package/dist/steps/store.steps.d.ts +96 -0
- package/dist/steps/store.steps.js +595 -0
- package/dist/steps/stream.steps.d.ts +86 -0
- package/dist/steps/stream.steps.js +270 -0
- package/dist/steps/trace.steps.d.ts +38 -0
- package/dist/steps/trace.steps.js +270 -0
- package/dist/stores/instant.document-parser.d.ts +6 -0
- package/dist/stores/instant.document-parser.js +210 -0
- package/dist/stores/instant.documents.d.ts +16 -0
- package/dist/stores/instant.documents.js +152 -0
- package/dist/stores/instant.store.d.ts +66 -0
- package/dist/stores/instant.store.js +575 -0
- package/dist/tools-to-model-tools.d.ts +19 -0
- package/dist/tools-to-model-tools.js +21 -0
- package/package.json +142 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { type ModelMessage, type UIMessage } from "ai";
|
|
2
|
+
import type { ContextItem } from "./context.store.js";
|
|
3
|
+
export declare const INPUT_ITEM_TYPE = "input";
|
|
4
|
+
export declare const OUTPUT_ITEM_TYPE = "output";
|
|
5
|
+
export declare const INPUT_TEXT_ITEM_TYPE = "input";
|
|
6
|
+
export declare const WEB_CHANNEL = "web";
|
|
7
|
+
export declare const AGENT_CHANNEL = "whatsapp";
|
|
8
|
+
export declare const EMAIL_CHANNEL = "email";
|
|
9
|
+
export type ContextOutputContentPart = {
|
|
10
|
+
type: "text";
|
|
11
|
+
text: string;
|
|
12
|
+
} | ({
|
|
13
|
+
type: "image-data";
|
|
14
|
+
data: string;
|
|
15
|
+
mediaType: string;
|
|
16
|
+
filename?: string;
|
|
17
|
+
} & Record<string, unknown>) | ({
|
|
18
|
+
type: string;
|
|
19
|
+
} & Record<string, unknown>);
|
|
20
|
+
export type ContextOutputPart = {
|
|
21
|
+
type: "json";
|
|
22
|
+
value: unknown;
|
|
23
|
+
} | {
|
|
24
|
+
type: "content";
|
|
25
|
+
value: ContextOutputContentPart[];
|
|
26
|
+
};
|
|
27
|
+
export declare function isContextOutputPart(value: unknown): value is ContextOutputPart;
|
|
28
|
+
export declare function normalizeContextOutputPart(value: unknown): ContextOutputPart;
|
|
29
|
+
export declare function createUserItemFromUIMessages(messages: UIMessage[]): ContextItem;
|
|
30
|
+
export declare function createAssistantItemFromUIMessages(itemId: string, messages: UIMessage[]): ContextItem;
|
|
31
|
+
export declare function convertToUIMessage(item: ContextItem): UIMessage;
|
|
32
|
+
/**
|
|
33
|
+
* Converts stored ContextItems to AI SDK ModelMessages.
|
|
34
|
+
*
|
|
35
|
+
* IMPORTANT:
|
|
36
|
+
* - Store-agnostic and workflow-safe.
|
|
37
|
+
* - Attachment/document handling MUST happen in the store boundary:
|
|
38
|
+
* `ContextStore.itemsToModelMessages(items)`.
|
|
39
|
+
*/
|
|
40
|
+
export declare function convertItemsToModelMessages(items: ContextItem[]): Promise<ModelMessage[]>;
|
|
41
|
+
export declare function convertItemToModelMessages(item: ContextItem): Promise<ModelMessage[]>;
|
|
42
|
+
export type AIMessage = {
|
|
43
|
+
id: string;
|
|
44
|
+
role: "user" | "assistant" | "system";
|
|
45
|
+
content: string;
|
|
46
|
+
createdAt: Date;
|
|
47
|
+
};
|
|
48
|
+
export type ResponseMessage = {
|
|
49
|
+
id: string;
|
|
50
|
+
timestamp: Date;
|
|
51
|
+
modelId: string;
|
|
52
|
+
headers?: Record<string, string>;
|
|
53
|
+
message: ModelMessage;
|
|
54
|
+
};
|
|
55
|
+
export declare function convertModelMessageToItem(itemId: string, message: ResponseMessage): ContextItem;
|
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
import { convertToModelMessages } from "ai";
|
|
2
|
+
import { isContextPartEnvelope, normalizePartsForPersistence, } from "./context.parts.js";
|
|
3
|
+
export const INPUT_ITEM_TYPE = "input";
|
|
4
|
+
export const OUTPUT_ITEM_TYPE = "output";
|
|
5
|
+
export const INPUT_TEXT_ITEM_TYPE = INPUT_ITEM_TYPE;
|
|
6
|
+
export const WEB_CHANNEL = "web";
|
|
7
|
+
export const AGENT_CHANNEL = "whatsapp";
|
|
8
|
+
export const EMAIL_CHANNEL = "email";
|
|
9
|
+
function asRecord(value) {
|
|
10
|
+
if (!value || typeof value !== "object")
|
|
11
|
+
return null;
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
function isContextOutputContentPart(value) {
|
|
15
|
+
const record = asRecord(value);
|
|
16
|
+
return Boolean(record && typeof record.type === "string");
|
|
17
|
+
}
|
|
18
|
+
export function isContextOutputPart(value) {
|
|
19
|
+
const record = asRecord(value);
|
|
20
|
+
if (!record || typeof record.type !== "string") {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
if (record.type === "json") {
|
|
24
|
+
return "value" in record;
|
|
25
|
+
}
|
|
26
|
+
if (record.type === "content") {
|
|
27
|
+
return Array.isArray(record.value) && record.value.every(isContextOutputContentPart);
|
|
28
|
+
}
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
export function normalizeContextOutputPart(value) {
|
|
32
|
+
if (isContextOutputPart(value)) {
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
type: "json",
|
|
37
|
+
value,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function isToolUIPart(value) {
|
|
41
|
+
const record = asRecord(value);
|
|
42
|
+
return Boolean(record && typeof record.type === "string" && record.type.startsWith("tool-"));
|
|
43
|
+
}
|
|
44
|
+
function readToolNameFromPart(part) {
|
|
45
|
+
return String(part.type).split("-").slice(1).join("-");
|
|
46
|
+
}
|
|
47
|
+
function stripDataUrlPrefix(value) {
|
|
48
|
+
return value.replace(/^data:[^;]+;base64,/i, "");
|
|
49
|
+
}
|
|
50
|
+
function asCanonicalParts(parts) {
|
|
51
|
+
return normalizePartsForPersistence(parts);
|
|
52
|
+
}
|
|
53
|
+
function contentBlockToPrimaryUiParts(block) {
|
|
54
|
+
if (block.type === "text") {
|
|
55
|
+
return [{ type: "text", text: block.text }];
|
|
56
|
+
}
|
|
57
|
+
if (block.type === "file") {
|
|
58
|
+
const url = typeof block.url === "string" && block.url.length > 0
|
|
59
|
+
? block.url
|
|
60
|
+
: typeof block.data === "string" && block.data.length > 0
|
|
61
|
+
? block.data.startsWith("data:")
|
|
62
|
+
? block.data
|
|
63
|
+
: `data:${block.mediaType};base64,${block.data}`
|
|
64
|
+
: typeof block.fileId === "string" && block.fileId.length > 0
|
|
65
|
+
? block.fileId
|
|
66
|
+
: "";
|
|
67
|
+
if (!url) {
|
|
68
|
+
return [];
|
|
69
|
+
}
|
|
70
|
+
return [
|
|
71
|
+
{
|
|
72
|
+
type: "file",
|
|
73
|
+
mediaType: block.mediaType,
|
|
74
|
+
filename: block.filename,
|
|
75
|
+
url,
|
|
76
|
+
},
|
|
77
|
+
];
|
|
78
|
+
}
|
|
79
|
+
if (block.type === "json") {
|
|
80
|
+
return [
|
|
81
|
+
{
|
|
82
|
+
type: "text",
|
|
83
|
+
text: JSON.stringify(block.value, null, 2),
|
|
84
|
+
},
|
|
85
|
+
];
|
|
86
|
+
}
|
|
87
|
+
if (block.type === "source-url") {
|
|
88
|
+
return [
|
|
89
|
+
{
|
|
90
|
+
type: "source-url",
|
|
91
|
+
sourceId: block.sourceId,
|
|
92
|
+
url: block.url,
|
|
93
|
+
title: block.title,
|
|
94
|
+
},
|
|
95
|
+
];
|
|
96
|
+
}
|
|
97
|
+
if (block.type === "source-document") {
|
|
98
|
+
return [
|
|
99
|
+
{
|
|
100
|
+
type: "source-document",
|
|
101
|
+
sourceId: block.sourceId,
|
|
102
|
+
mediaType: block.mediaType,
|
|
103
|
+
title: block.title,
|
|
104
|
+
filename: block.filename,
|
|
105
|
+
},
|
|
106
|
+
];
|
|
107
|
+
}
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
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
|
+
function canonicalPartsToPrimaryUiParts(parts) {
|
|
124
|
+
const uiParts = [];
|
|
125
|
+
for (const part of parts) {
|
|
126
|
+
if (part.type === "content") {
|
|
127
|
+
uiParts.push(...part.content.flatMap((block) => contentBlockToPrimaryUiParts(block)));
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
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()) {
|
|
136
|
+
uiParts.push({
|
|
137
|
+
type: "reasoning",
|
|
138
|
+
text,
|
|
139
|
+
state: part.state,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (part.type === "source") {
|
|
145
|
+
uiParts.push(...part.content.flatMap((block) => contentBlockToPrimaryUiParts(block)));
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
if (part.type === "tool-call") {
|
|
149
|
+
uiParts.push({
|
|
150
|
+
type: `tool-${part.toolName}`,
|
|
151
|
+
toolCallId: part.toolCallId,
|
|
152
|
+
state: part.state ?? "input-available",
|
|
153
|
+
input: toolCallContentToInput(part.content),
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return uiParts;
|
|
158
|
+
}
|
|
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
|
+
function canonicalToolPartsToModelMessages(parts) {
|
|
200
|
+
const toolInputs = new Map();
|
|
201
|
+
const toolResults = [];
|
|
202
|
+
for (const part of parts) {
|
|
203
|
+
if (part.type === "tool-call") {
|
|
204
|
+
toolInputs.set(part.toolCallId, toolCallContentToInput(part.content));
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
if (part.type !== "tool-result") {
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
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");
|
|
215
|
+
toolResults.push({
|
|
216
|
+
type: "tool-error",
|
|
217
|
+
toolCallId: part.toolCallId,
|
|
218
|
+
toolName: part.toolName,
|
|
219
|
+
input: toolInputs.get(part.toolCallId),
|
|
220
|
+
error: text || "Tool execution failed.",
|
|
221
|
+
});
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
toolResults.push({
|
|
225
|
+
type: "tool-result",
|
|
226
|
+
toolCallId: part.toolCallId,
|
|
227
|
+
toolName: part.toolName,
|
|
228
|
+
output: canonicalToolResultContentToOutput(part.content),
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
if (toolResults.length === 0) {
|
|
232
|
+
return [];
|
|
233
|
+
}
|
|
234
|
+
return [
|
|
235
|
+
{
|
|
236
|
+
role: "tool",
|
|
237
|
+
content: toolResults,
|
|
238
|
+
},
|
|
239
|
+
];
|
|
240
|
+
}
|
|
241
|
+
function canonicalPartsToModelMessages(role, parts) {
|
|
242
|
+
const uiMessage = {
|
|
243
|
+
id: "canonical-item",
|
|
244
|
+
role,
|
|
245
|
+
parts: canonicalPartsToPrimaryUiParts(parts),
|
|
246
|
+
};
|
|
247
|
+
return removeEmptyToolMessages(convertToModelMessages([uiMessage]));
|
|
248
|
+
}
|
|
249
|
+
function normalizeAssistantPartsForModel(parts) {
|
|
250
|
+
return parts
|
|
251
|
+
.map((part) => {
|
|
252
|
+
if (!isToolUIPart(part)) {
|
|
253
|
+
return part;
|
|
254
|
+
}
|
|
255
|
+
const next = {
|
|
256
|
+
...part,
|
|
257
|
+
state: part.state === "output-available" || part.state === "output-error"
|
|
258
|
+
? "input-available"
|
|
259
|
+
: part.state,
|
|
260
|
+
};
|
|
261
|
+
delete next.output;
|
|
262
|
+
delete next.errorText;
|
|
263
|
+
return next;
|
|
264
|
+
})
|
|
265
|
+
.filter(Boolean);
|
|
266
|
+
}
|
|
267
|
+
function buildToolResultContent(parts) {
|
|
268
|
+
const toolContent = [];
|
|
269
|
+
for (const part of parts) {
|
|
270
|
+
if (!isToolUIPart(part)) {
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
const toolCallId = typeof part.toolCallId === "string" ? part.toolCallId : "";
|
|
274
|
+
const toolName = readToolNameFromPart(part);
|
|
275
|
+
if (!toolCallId || !toolName) {
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
if (part.state === "output-available") {
|
|
279
|
+
toolContent.push({
|
|
280
|
+
type: "tool-result",
|
|
281
|
+
toolCallId,
|
|
282
|
+
toolName,
|
|
283
|
+
output: normalizeContextOutputPart(part.output),
|
|
284
|
+
});
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
287
|
+
if (part.state === "output-error") {
|
|
288
|
+
toolContent.push({
|
|
289
|
+
type: "tool-error",
|
|
290
|
+
toolCallId,
|
|
291
|
+
toolName,
|
|
292
|
+
input: part.input,
|
|
293
|
+
error: typeof part.errorText === "string" && part.errorText.trim().length > 0
|
|
294
|
+
? part.errorText
|
|
295
|
+
: "Tool execution failed.",
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return toolContent;
|
|
300
|
+
}
|
|
301
|
+
function removeEmptyToolMessages(messages) {
|
|
302
|
+
return messages.filter((message) => {
|
|
303
|
+
if (message.role !== "tool") {
|
|
304
|
+
return true;
|
|
305
|
+
}
|
|
306
|
+
return Array.isArray(message.content) ? message.content.length > 0 : true;
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
export function createUserItemFromUIMessages(messages) {
|
|
310
|
+
if (!Array.isArray(messages) || messages.length === 0) {
|
|
311
|
+
throw new Error("Missing messages to create item");
|
|
312
|
+
}
|
|
313
|
+
const lastMessage = messages[messages.length - 1];
|
|
314
|
+
return {
|
|
315
|
+
id: lastMessage.id,
|
|
316
|
+
type: INPUT_ITEM_TYPE,
|
|
317
|
+
channel: WEB_CHANNEL,
|
|
318
|
+
content: {
|
|
319
|
+
parts: asCanonicalParts(lastMessage.parts),
|
|
320
|
+
},
|
|
321
|
+
createdAt: new Date().toISOString(),
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
export function createAssistantItemFromUIMessages(itemId, messages) {
|
|
325
|
+
if (!Array.isArray(messages) || messages.length === 0) {
|
|
326
|
+
throw new Error("Missing messages to create item");
|
|
327
|
+
}
|
|
328
|
+
const lastMessage = messages[messages.length - 1];
|
|
329
|
+
return {
|
|
330
|
+
id: itemId,
|
|
331
|
+
type: OUTPUT_ITEM_TYPE,
|
|
332
|
+
channel: WEB_CHANNEL,
|
|
333
|
+
content: {
|
|
334
|
+
parts: asCanonicalParts(lastMessage.parts),
|
|
335
|
+
},
|
|
336
|
+
createdAt: new Date().toISOString(),
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
export function convertToUIMessage(item) {
|
|
340
|
+
const role = item.type === INPUT_ITEM_TYPE ? "user" : "assistant";
|
|
341
|
+
const rawParts = Array.isArray(item.content.parts) ? item.content.parts : [];
|
|
342
|
+
const parts = rawParts.every(isContextPartEnvelope)
|
|
343
|
+
? canonicalPartsToPrimaryUiParts(rawParts)
|
|
344
|
+
: rawParts;
|
|
345
|
+
return {
|
|
346
|
+
id: item.id,
|
|
347
|
+
role,
|
|
348
|
+
parts,
|
|
349
|
+
metadata: {
|
|
350
|
+
channel: item.channel,
|
|
351
|
+
type: item.type,
|
|
352
|
+
createdAt: item.createdAt,
|
|
353
|
+
},
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Converts stored ContextItems to AI SDK ModelMessages.
|
|
358
|
+
*
|
|
359
|
+
* IMPORTANT:
|
|
360
|
+
* - Store-agnostic and workflow-safe.
|
|
361
|
+
* - Attachment/document handling MUST happen in the store boundary:
|
|
362
|
+
* `ContextStore.itemsToModelMessages(items)`.
|
|
363
|
+
*/
|
|
364
|
+
export async function convertItemsToModelMessages(items) {
|
|
365
|
+
const results = [];
|
|
366
|
+
for (const item of items) {
|
|
367
|
+
results.push(await convertItemToModelMessages(item));
|
|
368
|
+
}
|
|
369
|
+
return results.flat();
|
|
370
|
+
}
|
|
371
|
+
export async function convertItemToModelMessages(item) {
|
|
372
|
+
const role = item.type === INPUT_ITEM_TYPE ? "user" : "assistant";
|
|
373
|
+
const rawParts = Array.isArray(item.content.parts) ? item.content.parts : [];
|
|
374
|
+
const canonicalParts = asCanonicalParts(rawParts);
|
|
375
|
+
if (canonicalParts.length > 0) {
|
|
376
|
+
const primary = await canonicalPartsToModelMessages(role, canonicalParts);
|
|
377
|
+
if (role !== "assistant") {
|
|
378
|
+
return primary;
|
|
379
|
+
}
|
|
380
|
+
return [
|
|
381
|
+
...primary,
|
|
382
|
+
...canonicalToolPartsToModelMessages(canonicalParts),
|
|
383
|
+
];
|
|
384
|
+
}
|
|
385
|
+
const assistantParts = normalizeAssistantPartsForModel(rawParts);
|
|
386
|
+
const message = {
|
|
387
|
+
id: item.id,
|
|
388
|
+
role,
|
|
389
|
+
parts: assistantParts,
|
|
390
|
+
};
|
|
391
|
+
const modelMessages = removeEmptyToolMessages(await convertToModelMessages([message]));
|
|
392
|
+
if (role !== "assistant") {
|
|
393
|
+
return modelMessages;
|
|
394
|
+
}
|
|
395
|
+
const toolContent = buildToolResultContent(rawParts);
|
|
396
|
+
if (toolContent.length === 0) {
|
|
397
|
+
return modelMessages;
|
|
398
|
+
}
|
|
399
|
+
return [
|
|
400
|
+
...modelMessages,
|
|
401
|
+
{
|
|
402
|
+
role: "tool",
|
|
403
|
+
content: toolContent,
|
|
404
|
+
},
|
|
405
|
+
];
|
|
406
|
+
}
|
|
407
|
+
function normalizeModelMessageContentToParts(content) {
|
|
408
|
+
if (Array.isArray(content))
|
|
409
|
+
return content;
|
|
410
|
+
if (typeof content === "string") {
|
|
411
|
+
if (!content.trim())
|
|
412
|
+
return [];
|
|
413
|
+
return [{ type: "text", text: content }];
|
|
414
|
+
}
|
|
415
|
+
if (content === null || content === undefined)
|
|
416
|
+
return [];
|
|
417
|
+
return [content];
|
|
418
|
+
}
|
|
419
|
+
export function convertModelMessageToItem(itemId, message) {
|
|
420
|
+
const role = message.message.role;
|
|
421
|
+
const type = role === "user" ? INPUT_ITEM_TYPE : OUTPUT_ITEM_TYPE;
|
|
422
|
+
return {
|
|
423
|
+
id: itemId,
|
|
424
|
+
type,
|
|
425
|
+
channel: WEB_CHANNEL,
|
|
426
|
+
content: {
|
|
427
|
+
parts: normalizeModelMessageContentToParts(message.message.content),
|
|
428
|
+
},
|
|
429
|
+
createdAt: message.timestamp.toISOString(),
|
|
430
|
+
};
|
|
431
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare function getClientResumeHookUrl(): string | undefined;
|
|
2
|
+
/**
|
|
3
|
+
* Deterministic hook token for approving an `auto: false` tool call.
|
|
4
|
+
*
|
|
5
|
+
* External systems can resume the hook with:
|
|
6
|
+
* `resumeHook(toolApprovalHookToken({ executionId, toolCallId }), { approved: true })`
|
|
7
|
+
*/
|
|
8
|
+
export declare function toolApprovalHookToken(params: {
|
|
9
|
+
executionId: string;
|
|
10
|
+
toolCallId: string;
|
|
11
|
+
}): string;
|
|
12
|
+
/**
|
|
13
|
+
* Deterministic webhook token for approving an `auto: false` tool call.
|
|
14
|
+
*
|
|
15
|
+
* When using Workflow DevKit, the webhook is available at:
|
|
16
|
+
* `/.well-known/workflow/v1/webhook/:token`
|
|
17
|
+
*/
|
|
18
|
+
export declare function toolApprovalWebhookToken(params: {
|
|
19
|
+
executionId: string;
|
|
20
|
+
toolCallId: string;
|
|
21
|
+
}): string;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
function stripTrailingSlash(value) {
|
|
2
|
+
return value.replace(/\/$/, "");
|
|
3
|
+
}
|
|
4
|
+
export function getClientResumeHookUrl() {
|
|
5
|
+
const direct = process.env.EKAIROS_CLIENT_RESUME_HOOK_URL;
|
|
6
|
+
if (typeof direct === "string" && direct.trim())
|
|
7
|
+
return direct.trim();
|
|
8
|
+
const base = process.env.EKAIROS_CLIENT_BASE_URL;
|
|
9
|
+
if (typeof base === "string" && base.trim()) {
|
|
10
|
+
return `${stripTrailingSlash(base.trim())}/api/ekairos/resume-hook`;
|
|
11
|
+
}
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Deterministic hook token for approving an `auto: false` tool call.
|
|
16
|
+
*
|
|
17
|
+
* External systems can resume the hook with:
|
|
18
|
+
* `resumeHook(toolApprovalHookToken({ executionId, toolCallId }), { approved: true })`
|
|
19
|
+
*/
|
|
20
|
+
export function toolApprovalHookToken(params) {
|
|
21
|
+
return `ekairos_context:tool-approval:${params.executionId}:${params.toolCallId}`;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Deterministic webhook token for approving an `auto: false` tool call.
|
|
25
|
+
*
|
|
26
|
+
* When using Workflow DevKit, the webhook is available at:
|
|
27
|
+
* `/.well-known/workflow/v1/webhook/:token`
|
|
28
|
+
*/
|
|
29
|
+
export function toolApprovalWebhookToken(params) {
|
|
30
|
+
return `ekairos_context:tool-approval-webhook:${params.executionId}:${params.toolCallId}`;
|
|
31
|
+
}
|
package/dist/context.js
ADDED