@cognipeer/agent-sdk 0.10.4 → 0.10.6
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/dist/index.cjs +1011 -288
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +846 -659
- package/dist/index.d.ts +846 -659
- package/dist/index.mjs +1006 -288
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -28,6 +28,238 @@ var __export = (target, all) => {
|
|
|
28
28
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
29
29
|
};
|
|
30
30
|
|
|
31
|
+
// src/utils/content.ts
|
|
32
|
+
function isRecord(value) {
|
|
33
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
34
|
+
}
|
|
35
|
+
function nonEmpty(value) {
|
|
36
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
37
|
+
}
|
|
38
|
+
function kindFromMediaType(mediaType) {
|
|
39
|
+
const top = mediaType?.split("/")[0];
|
|
40
|
+
return top === "image" || top === "audio" || top === "video" ? top : "file";
|
|
41
|
+
}
|
|
42
|
+
function inlineDataOf(part) {
|
|
43
|
+
const inline = part.inlineData ?? part.inline_data ?? part.fileData ?? part.file_data;
|
|
44
|
+
return isRecord(inline) ? inline : void 0;
|
|
45
|
+
}
|
|
46
|
+
function mediaKindOf(part) {
|
|
47
|
+
if (!isRecord(part)) return void 0;
|
|
48
|
+
const type = nonEmpty(part.type);
|
|
49
|
+
if (type) return MEDIA_PART_KINDS[type];
|
|
50
|
+
const inline = inlineDataOf(part);
|
|
51
|
+
if (inline) return kindFromMediaType(nonEmpty(inline.mimeType) ?? nonEmpty(inline.mime_type));
|
|
52
|
+
return void 0;
|
|
53
|
+
}
|
|
54
|
+
function hasMediaPart(content) {
|
|
55
|
+
return Array.isArray(content) && content.some((part) => mediaKindOf(part) !== void 0);
|
|
56
|
+
}
|
|
57
|
+
function urlOfPart(part) {
|
|
58
|
+
const image = part.image_url;
|
|
59
|
+
const video = part.video_url;
|
|
60
|
+
return nonEmpty(typeof image === "string" ? image : image?.url) ?? nonEmpty(typeof video === "string" ? video : video?.url) ?? nonEmpty(part.url) ?? nonEmpty(part.source?.url) ?? nonEmpty(inlineDataOf(part)?.fileUri) ?? nonEmpty(inlineDataOf(part)?.file_uri);
|
|
61
|
+
}
|
|
62
|
+
function mediaTypeOfPart(part) {
|
|
63
|
+
const image = isRecord(part.image_url) ? part.image_url : void 0;
|
|
64
|
+
const source = isRecord(part.source) ? part.source : void 0;
|
|
65
|
+
const inline = inlineDataOf(part);
|
|
66
|
+
const audioFormat = nonEmpty(part.input_audio?.format);
|
|
67
|
+
const fromDataUrl = /^data:([^;,]+)/i.exec(urlOfPart(part) ?? "")?.[1];
|
|
68
|
+
return nonEmpty(part.mediaType) ?? nonEmpty(part.media_type) ?? nonEmpty(part.mimeType) ?? nonEmpty(part.mime_type) ?? nonEmpty(source?.mediaType) ?? nonEmpty(source?.media_type) ?? nonEmpty(image?.mediaType) ?? nonEmpty(image?.media_type) ?? nonEmpty(inline?.mimeType) ?? nonEmpty(inline?.mime_type) ?? nonEmpty(fromDataUrl) ?? (audioFormat ? `audio/${audioFormat}` : void 0);
|
|
69
|
+
}
|
|
70
|
+
function nameOfPart(part) {
|
|
71
|
+
const file = isRecord(part.file) ? part.file : void 0;
|
|
72
|
+
const image = isRecord(part.image_url) ? part.image_url : void 0;
|
|
73
|
+
const source = isRecord(part.source) ? part.source : void 0;
|
|
74
|
+
return nonEmpty(part.name) ?? nonEmpty(part.fileName) ?? nonEmpty(part.filename) ?? nonEmpty(part.file_name) ?? nonEmpty(file?.filename) ?? nonEmpty(file?.fileName) ?? nonEmpty(image?.name) ?? nonEmpty(source?.fileName) ?? nonEmpty(source?.filename) ?? nonEmpty(part.fileId) ?? nonEmpty(part.file_id) ?? nonEmpty(file?.file_id) ?? nonEmpty(file?.fileId) ?? nonEmpty(image?.fileId) ?? nonEmpty(image?.file_id) ?? nonEmpty(part.image_file?.file_id);
|
|
75
|
+
}
|
|
76
|
+
function labelFromUrl(url) {
|
|
77
|
+
if (!url || url.startsWith("data:")) return void 0;
|
|
78
|
+
try {
|
|
79
|
+
const parsed = new URL(url);
|
|
80
|
+
if (parsed.protocol === "session-file:") return nonEmpty(parsed.hostname) ?? nonEmpty(parsed.pathname.replace(/^\/+/, ""));
|
|
81
|
+
if (parsed.protocol === "http:" || parsed.protocol === "https:") {
|
|
82
|
+
return nonEmpty(decodeURIComponent(parsed.pathname.split("/").filter(Boolean).pop() ?? ""));
|
|
83
|
+
}
|
|
84
|
+
} catch {
|
|
85
|
+
}
|
|
86
|
+
return void 0;
|
|
87
|
+
}
|
|
88
|
+
function describeContentPart(part) {
|
|
89
|
+
const kind = mediaKindOf(part);
|
|
90
|
+
if (!kind || !isRecord(part)) return void 0;
|
|
91
|
+
const label = nameOfPart(part) ?? mediaTypeOfPart(part) ?? labelFromUrl(urlOfPart(part));
|
|
92
|
+
if (!label) return `[${kind}]`;
|
|
93
|
+
const clean = label.replace(/[\r\n\]]+/g, " ").slice(0, PLACEHOLDER_LABEL_MAX);
|
|
94
|
+
return `[${kind}: ${clean}]`;
|
|
95
|
+
}
|
|
96
|
+
function contentPartToText(part, fallback) {
|
|
97
|
+
if (typeof part === "string") return part;
|
|
98
|
+
if (!isRecord(part)) return part == null ? "" : String(part);
|
|
99
|
+
const media = describeContentPart(part);
|
|
100
|
+
if (media) return media;
|
|
101
|
+
if (typeof part.text === "string") return part.text;
|
|
102
|
+
if (typeof part.content === "string") return part.content;
|
|
103
|
+
if (fallback) return fallback(part);
|
|
104
|
+
try {
|
|
105
|
+
return JSON.stringify(part);
|
|
106
|
+
} catch {
|
|
107
|
+
return String(part);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function contentToString(content) {
|
|
111
|
+
try {
|
|
112
|
+
if (content == null) return "";
|
|
113
|
+
if (typeof content === "string") return content;
|
|
114
|
+
if (Array.isArray(content)) {
|
|
115
|
+
return content.map((p) => {
|
|
116
|
+
if (!p || typeof p !== "object") return String(p);
|
|
117
|
+
if (p.type === "text") return String(p.text ?? "");
|
|
118
|
+
if (p.type === "image_url") {
|
|
119
|
+
const img = p.image_url;
|
|
120
|
+
const url = typeof img === "string" ? img : img?.url;
|
|
121
|
+
if (typeof url === "string" && /^https?:\/\//i.test(url)) {
|
|
122
|
+
const detail = typeof img === "string" ? void 0 : img?.detail;
|
|
123
|
+
return `[image:${url}${detail ? ` detail=${detail}` : ""}]`;
|
|
124
|
+
}
|
|
125
|
+
return describeContentPart(p) ?? "[image]";
|
|
126
|
+
}
|
|
127
|
+
const media = describeContentPart(p);
|
|
128
|
+
if (media) return media;
|
|
129
|
+
return JSON.stringify(p);
|
|
130
|
+
}).join("\n");
|
|
131
|
+
}
|
|
132
|
+
return describeContentPart(content) ?? JSON.stringify(content);
|
|
133
|
+
} catch {
|
|
134
|
+
return String(content);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function mergeContentsToString(contents) {
|
|
138
|
+
return contents.map((c) => contentToString(c)).join("\n");
|
|
139
|
+
}
|
|
140
|
+
function safeStringify(value, pretty = false) {
|
|
141
|
+
if (value == null) return "";
|
|
142
|
+
if (typeof value === "string") return value;
|
|
143
|
+
try {
|
|
144
|
+
return JSON.stringify(value, null, pretty ? 2 : void 0) ?? String(value);
|
|
145
|
+
} catch {
|
|
146
|
+
return String(value);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function extractMessageText(message) {
|
|
150
|
+
if (!message) return "";
|
|
151
|
+
const content = message.content;
|
|
152
|
+
if (typeof content === "string") return content;
|
|
153
|
+
if (Array.isArray(content)) {
|
|
154
|
+
return content.map((part) => typeof part === "string" ? part : part?.text ?? part?.content ?? "").join("");
|
|
155
|
+
}
|
|
156
|
+
return "";
|
|
157
|
+
}
|
|
158
|
+
function textFromContent(content) {
|
|
159
|
+
if (typeof content === "string") return content;
|
|
160
|
+
if (!Array.isArray(content)) return "";
|
|
161
|
+
return content.filter((part) => isTextPart(part)).map((part) => part.text ?? "").join("\n");
|
|
162
|
+
}
|
|
163
|
+
function isTextPart(part) {
|
|
164
|
+
return !!part && typeof part === "object" && part.type === "text";
|
|
165
|
+
}
|
|
166
|
+
function mapTextParts(content, fn) {
|
|
167
|
+
if (typeof content === "string") return fn(content);
|
|
168
|
+
if (!Array.isArray(content)) return content;
|
|
169
|
+
return content.map((part) => isTextPart(part) ? { ...part, text: fn(part.text) } : part);
|
|
170
|
+
}
|
|
171
|
+
function replaceTextContent(content, text) {
|
|
172
|
+
if (typeof content === "string" || content == null) return text;
|
|
173
|
+
if (!Array.isArray(content)) return text;
|
|
174
|
+
const textIndexes = content.reduce((acc, part, index) => {
|
|
175
|
+
if (isTextPart(part)) acc.push(index);
|
|
176
|
+
return acc;
|
|
177
|
+
}, []);
|
|
178
|
+
if (textIndexes.length === 0) {
|
|
179
|
+
return text.length > 0 ? [{ type: "text", text }, ...content] : content;
|
|
180
|
+
}
|
|
181
|
+
const [first, ...rest] = textIndexes;
|
|
182
|
+
const dropped = new Set(rest);
|
|
183
|
+
return content.map((part, index) => index === first ? { ...part, text } : part).filter((_part, index) => !dropped.has(index));
|
|
184
|
+
}
|
|
185
|
+
function normalizeSource(source) {
|
|
186
|
+
if (!source || typeof source !== "object") return {};
|
|
187
|
+
const src = source;
|
|
188
|
+
if (src.type === "base64" && typeof src.data === "string") {
|
|
189
|
+
return {
|
|
190
|
+
sourceType: "base64",
|
|
191
|
+
mediaType: typeof src.mediaType === "string" ? src.mediaType : void 0,
|
|
192
|
+
// base64 encodes 3 bytes per 4 characters; padding makes this an upper bound.
|
|
193
|
+
approxBytes: Math.floor(src.data.length * 3 / 4)
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
if (src.type === "url" && typeof src.url === "string") {
|
|
197
|
+
return {
|
|
198
|
+
sourceType: "url",
|
|
199
|
+
url: src.url,
|
|
200
|
+
mediaType: typeof src.mediaType === "string" ? src.mediaType : void 0
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
return {};
|
|
204
|
+
}
|
|
205
|
+
function collectAttachments(content) {
|
|
206
|
+
if (!Array.isArray(content)) return [];
|
|
207
|
+
const attachments = [];
|
|
208
|
+
content.forEach((part, index) => {
|
|
209
|
+
if (!part || typeof part !== "object") return;
|
|
210
|
+
const type = part.type;
|
|
211
|
+
if (!type || type === "text") return;
|
|
212
|
+
if (type === "image" || type === "audio" || type === "video" || type === "file") {
|
|
213
|
+
attachments.push({
|
|
214
|
+
index,
|
|
215
|
+
kind: type,
|
|
216
|
+
fileName: typeof part.fileName === "string" ? part.fileName : void 0,
|
|
217
|
+
...normalizeSource(part.source)
|
|
218
|
+
});
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
if (type === "image_url") {
|
|
222
|
+
const image = part.image_url;
|
|
223
|
+
const url = typeof image === "string" ? image : image?.url;
|
|
224
|
+
if (typeof url === "string" && url.startsWith("data:")) {
|
|
225
|
+
const comma = url.indexOf(",");
|
|
226
|
+
const header = url.slice(5, comma);
|
|
227
|
+
attachments.push({
|
|
228
|
+
index,
|
|
229
|
+
kind: "image",
|
|
230
|
+
sourceType: "base64",
|
|
231
|
+
mediaType: header.split(";")[0] || void 0,
|
|
232
|
+
approxBytes: Math.floor((url.length - comma - 1) * 3 / 4)
|
|
233
|
+
});
|
|
234
|
+
} else {
|
|
235
|
+
attachments.push({ index, kind: "image", sourceType: "url", url });
|
|
236
|
+
}
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
attachments.push({ index, kind: "unknown" });
|
|
240
|
+
});
|
|
241
|
+
return attachments;
|
|
242
|
+
}
|
|
243
|
+
var MEDIA_PART_KINDS, PLACEHOLDER_LABEL_MAX;
|
|
244
|
+
var init_content = __esm({
|
|
245
|
+
"src/utils/content.ts"() {
|
|
246
|
+
MEDIA_PART_KINDS = {
|
|
247
|
+
image: "image",
|
|
248
|
+
image_url: "image",
|
|
249
|
+
input_image: "image",
|
|
250
|
+
image_file: "image",
|
|
251
|
+
audio: "audio",
|
|
252
|
+
input_audio: "audio",
|
|
253
|
+
video: "video",
|
|
254
|
+
video_url: "video",
|
|
255
|
+
file: "file",
|
|
256
|
+
input_file: "file",
|
|
257
|
+
document: "file"
|
|
258
|
+
};
|
|
259
|
+
PLACEHOLDER_LABEL_MAX = 80;
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
|
|
31
263
|
// src/utils/utilTokens.ts
|
|
32
264
|
var utilTokens_exports = {};
|
|
33
265
|
__export(utilTokens_exports, {
|
|
@@ -52,7 +284,7 @@ function getTokenCounter() {
|
|
|
52
284
|
function countApproxTokens(text) {
|
|
53
285
|
return activeTokenCounter(text || "");
|
|
54
286
|
}
|
|
55
|
-
function
|
|
287
|
+
function extractMessageText2(m) {
|
|
56
288
|
if (!m) return "";
|
|
57
289
|
const parts = [];
|
|
58
290
|
parts.push(m.role || "");
|
|
@@ -62,6 +294,7 @@ function extractMessageText(m) {
|
|
|
62
294
|
} else if (Array.isArray(m.content)) {
|
|
63
295
|
for (const c of m.content) {
|
|
64
296
|
if (typeof c === "string") parts.push(c);
|
|
297
|
+
else if (describeContentPart(c)) parts.push(describeContentPart(c));
|
|
65
298
|
else if (c?.text) parts.push(c.text);
|
|
66
299
|
else if (c?.content) parts.push(c.content);
|
|
67
300
|
else if (c?.type === "tool_use" && c?.input) {
|
|
@@ -72,7 +305,7 @@ function extractMessageText(m) {
|
|
|
72
305
|
}
|
|
73
306
|
}
|
|
74
307
|
} else if (m.content != null && typeof m.content === "object") {
|
|
75
|
-
parts.push(JSON.stringify(m.content));
|
|
308
|
+
parts.push(describeContentPart(m.content) ?? JSON.stringify(m.content));
|
|
76
309
|
}
|
|
77
310
|
if (Array.isArray(m.tool_calls)) {
|
|
78
311
|
for (const tc of m.tool_calls) {
|
|
@@ -102,12 +335,13 @@ function extractMessageText(m) {
|
|
|
102
335
|
}
|
|
103
336
|
function countMessagesTokens(messages) {
|
|
104
337
|
if (!Array.isArray(messages) || messages.length === 0) return 0;
|
|
105
|
-
const allText = messages.map(
|
|
338
|
+
const allText = messages.map(extractMessageText2).join("\n");
|
|
106
339
|
return countApproxTokens(allText) + messages.length * 4;
|
|
107
340
|
}
|
|
108
341
|
var activeTokenCounter;
|
|
109
342
|
var init_utilTokens = __esm({
|
|
110
343
|
"src/utils/utilTokens.ts"() {
|
|
344
|
+
init_content();
|
|
111
345
|
activeTokenCounter = defaultTokenCounter;
|
|
112
346
|
}
|
|
113
347
|
});
|
|
@@ -568,6 +802,125 @@ function isOpenAIHostedEndpoint(lcModel) {
|
|
|
568
802
|
}
|
|
569
803
|
}
|
|
570
804
|
|
|
805
|
+
// src/utils/abort.ts
|
|
806
|
+
var POLL_INTERVAL_MS = 100;
|
|
807
|
+
var NOOP = () => void 0;
|
|
808
|
+
function isObject(value) {
|
|
809
|
+
return value !== null && typeof value === "object";
|
|
810
|
+
}
|
|
811
|
+
function isRealSignal(value) {
|
|
812
|
+
return typeof AbortSignal !== "undefined" && value instanceof AbortSignal;
|
|
813
|
+
}
|
|
814
|
+
function isCancellationRequested(source) {
|
|
815
|
+
if (!source) return false;
|
|
816
|
+
for (const candidate of [source.signal, source.cancellationToken]) {
|
|
817
|
+
if (!isObject(candidate)) continue;
|
|
818
|
+
if (candidate.aborted === true || candidate.isCancellationRequested === true) return true;
|
|
819
|
+
}
|
|
820
|
+
return false;
|
|
821
|
+
}
|
|
822
|
+
function linkAbortSignal(source) {
|
|
823
|
+
if (!source) return { signal: void 0, dispose: NOOP };
|
|
824
|
+
const candidates = [];
|
|
825
|
+
for (const candidate of [source.signal, source.cancellationToken]) {
|
|
826
|
+
if (isObject(candidate) && !candidates.includes(candidate)) candidates.push(candidate);
|
|
827
|
+
}
|
|
828
|
+
if (candidates.length === 0) return { signal: void 0, dispose: NOOP };
|
|
829
|
+
const real = candidates.filter(isRealSignal);
|
|
830
|
+
if (candidates.length === 1 && real.length === 1) {
|
|
831
|
+
return { signal: real[0], dispose: NOOP };
|
|
832
|
+
}
|
|
833
|
+
const controller = new AbortController();
|
|
834
|
+
const cleanups = [];
|
|
835
|
+
let polled = [];
|
|
836
|
+
let timer;
|
|
837
|
+
const fire = (reason) => {
|
|
838
|
+
if (controller.signal.aborted) return;
|
|
839
|
+
try {
|
|
840
|
+
controller.abort(reason);
|
|
841
|
+
} catch {
|
|
842
|
+
controller.abort();
|
|
843
|
+
}
|
|
844
|
+
};
|
|
845
|
+
const dispose = () => {
|
|
846
|
+
if (timer !== void 0) {
|
|
847
|
+
clearInterval(timer);
|
|
848
|
+
timer = void 0;
|
|
849
|
+
}
|
|
850
|
+
polled = [];
|
|
851
|
+
for (const cleanup of cleanups.splice(0)) {
|
|
852
|
+
try {
|
|
853
|
+
cleanup();
|
|
854
|
+
} catch {
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
};
|
|
858
|
+
for (const candidate of candidates) {
|
|
859
|
+
if (candidate.aborted === true || candidate.isCancellationRequested === true) {
|
|
860
|
+
fire(isRealSignal(candidate) ? candidate.reason : void 0);
|
|
861
|
+
return { signal: controller.signal, dispose };
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
for (const candidate of candidates) {
|
|
865
|
+
if (typeof candidate.addEventListener === "function") {
|
|
866
|
+
const onAbort = () => fire(isRealSignal(candidate) ? candidate.reason : void 0);
|
|
867
|
+
candidate.addEventListener("abort", onAbort, { once: true });
|
|
868
|
+
cleanups.push(() => candidate.removeEventListener?.("abort", onAbort));
|
|
869
|
+
continue;
|
|
870
|
+
}
|
|
871
|
+
if (typeof candidate.onCancellationRequested === "function") {
|
|
872
|
+
let handle;
|
|
873
|
+
try {
|
|
874
|
+
handle = candidate.onCancellationRequested(() => fire());
|
|
875
|
+
} catch {
|
|
876
|
+
handle = void 0;
|
|
877
|
+
}
|
|
878
|
+
if (isObject(handle) && typeof handle.dispose === "function") {
|
|
879
|
+
cleanups.push(() => handle.dispose());
|
|
880
|
+
}
|
|
881
|
+
polled.push(candidate);
|
|
882
|
+
continue;
|
|
883
|
+
}
|
|
884
|
+
if ("isCancellationRequested" in candidate || "aborted" in candidate) {
|
|
885
|
+
polled.push(candidate);
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
if (polled.length > 0) {
|
|
889
|
+
timer = setInterval(() => {
|
|
890
|
+
for (const candidate of polled) {
|
|
891
|
+
if (candidate.aborted === true || candidate.isCancellationRequested === true) {
|
|
892
|
+
fire();
|
|
893
|
+
dispose();
|
|
894
|
+
return;
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
}, POLL_INTERVAL_MS);
|
|
898
|
+
timer.unref?.();
|
|
899
|
+
}
|
|
900
|
+
return { signal: controller.signal, dispose };
|
|
901
|
+
}
|
|
902
|
+
function abortableSleep(ms, signal) {
|
|
903
|
+
if (!signal) return new Promise((resolve) => setTimeout(resolve, ms));
|
|
904
|
+
if (signal.aborted) return Promise.reject(abortReason(signal));
|
|
905
|
+
return new Promise((resolve, reject) => {
|
|
906
|
+
const onAbort = () => {
|
|
907
|
+
clearTimeout(timer);
|
|
908
|
+
reject(abortReason(signal));
|
|
909
|
+
};
|
|
910
|
+
const timer = setTimeout(() => {
|
|
911
|
+
signal.removeEventListener("abort", onAbort);
|
|
912
|
+
resolve();
|
|
913
|
+
}, ms);
|
|
914
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
915
|
+
});
|
|
916
|
+
}
|
|
917
|
+
function abortReason(signal) {
|
|
918
|
+
if (signal.reason !== void 0) return signal.reason;
|
|
919
|
+
const error = new Error("This operation was aborted");
|
|
920
|
+
error.name = "AbortError";
|
|
921
|
+
return error;
|
|
922
|
+
}
|
|
923
|
+
|
|
571
924
|
// src/model.ts
|
|
572
925
|
function isSmartModel(m) {
|
|
573
926
|
return !!m && typeof m === "object" && typeof m.invoke === "function";
|
|
@@ -576,6 +929,10 @@ function withTools(model, tools, options) {
|
|
|
576
929
|
if (model?.bindTools) return model.bindTools(tools, options);
|
|
577
930
|
return model;
|
|
578
931
|
}
|
|
932
|
+
function withLinkedSignal(options, signal) {
|
|
933
|
+
if (!signal || options?.signal === signal) return options;
|
|
934
|
+
return { ...options || {}, signal };
|
|
935
|
+
}
|
|
579
936
|
function fromLangchainModel(lcModel) {
|
|
580
937
|
if (!lcModel) throw new Error("fromLangchainModel: model is undefined/null");
|
|
581
938
|
const normalizeContent = (content) => {
|
|
@@ -611,7 +968,13 @@ function fromLangchainModel(lcModel) {
|
|
|
611
968
|
const adapted = {
|
|
612
969
|
invoke: async (messages, options) => {
|
|
613
970
|
const lcMessages = messages.map(toLC);
|
|
614
|
-
const
|
|
971
|
+
const link = linkAbortSignal(options);
|
|
972
|
+
let response;
|
|
973
|
+
try {
|
|
974
|
+
response = await lcModel.invoke(lcMessages, withLinkedSignal(options, link.signal));
|
|
975
|
+
} finally {
|
|
976
|
+
link.dispose();
|
|
977
|
+
}
|
|
615
978
|
if (response && typeof response === "object") {
|
|
616
979
|
const content = response.content ?? response.text ?? "";
|
|
617
980
|
return {
|
|
@@ -629,10 +992,15 @@ function fromLangchainModel(lcModel) {
|
|
|
629
992
|
stream: async function* (messages, options) {
|
|
630
993
|
if (typeof lcModel.stream !== "function") return;
|
|
631
994
|
const lcMessages = messages.map(toLC);
|
|
632
|
-
const
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
995
|
+
const link = linkAbortSignal(options);
|
|
996
|
+
try {
|
|
997
|
+
const streamResult = lcModel.stream(lcMessages, withLinkedSignal(options, link.signal));
|
|
998
|
+
const stream = typeof streamResult?.then === "function" ? await streamResult : streamResult;
|
|
999
|
+
for await (const chunk of stream) {
|
|
1000
|
+
yield chunk;
|
|
1001
|
+
}
|
|
1002
|
+
} finally {
|
|
1003
|
+
link.dispose();
|
|
636
1004
|
}
|
|
637
1005
|
},
|
|
638
1006
|
bindTools: (tools, options) => {
|
|
@@ -811,6 +1179,9 @@ function safe(v) {
|
|
|
811
1179
|
const n = Number(v);
|
|
812
1180
|
return Number.isFinite(n) && n >= 0 ? n : 0;
|
|
813
1181
|
}
|
|
1182
|
+
|
|
1183
|
+
// src/utils/tracing.ts
|
|
1184
|
+
init_content();
|
|
814
1185
|
var DEFAULT_COGNIPEER_URL = "https://console.cognipeer.com/api/client/v1/tracing/sessions";
|
|
815
1186
|
function fileSink(path2) {
|
|
816
1187
|
return { type: "file", path: path2 };
|
|
@@ -1555,6 +1926,12 @@ function buildMessageLabel(role, index) {
|
|
|
1555
1926
|
const base = `${normalized.charAt(0).toUpperCase()}${normalized.slice(1)} Message`;
|
|
1556
1927
|
return index > 1 ? `${base} #${index}` : base;
|
|
1557
1928
|
}
|
|
1929
|
+
function structuredMessageParts(content) {
|
|
1930
|
+
if (!hasMediaPart(content)) return void 0;
|
|
1931
|
+
const cloned = sanitizeTracePayload(content);
|
|
1932
|
+
if (!Array.isArray(cloned)) return void 0;
|
|
1933
|
+
return cloned.map((part) => typeof part === "string" ? { type: "text", text: part } : part);
|
|
1934
|
+
}
|
|
1558
1935
|
function toDisplayString(value) {
|
|
1559
1936
|
const sanitized = sanitizeTracePayload(value);
|
|
1560
1937
|
if (sanitized == null) return "";
|
|
@@ -1563,7 +1940,9 @@ function toDisplayString(value) {
|
|
|
1563
1940
|
return sanitized.map((item) => toDisplayString(item)).filter((part) => part && part.trim().length > 0).join("\n");
|
|
1564
1941
|
}
|
|
1565
1942
|
if (typeof sanitized === "object") {
|
|
1566
|
-
|
|
1943
|
+
const media = describeContentPart(sanitized);
|
|
1944
|
+
if (media) return media;
|
|
1945
|
+
if (typeof sanitized.text === "string" && (Object.keys(sanitized).length === 1 || sanitized.type === "text")) {
|
|
1567
1946
|
return sanitized.text;
|
|
1568
1947
|
}
|
|
1569
1948
|
if (typeof sanitized.content === "string") {
|
|
@@ -1635,11 +2014,13 @@ function convertMessageListToSections(messageList) {
|
|
|
1635
2014
|
if (!content || !content.trim().length) continue;
|
|
1636
2015
|
}
|
|
1637
2016
|
}
|
|
2017
|
+
const parts = structuredMessageParts(message?.content);
|
|
1638
2018
|
sections.push({
|
|
1639
2019
|
kind: "message",
|
|
1640
2020
|
label: buildMessageLabel(role, next),
|
|
1641
2021
|
role,
|
|
1642
2022
|
content,
|
|
2023
|
+
...parts ? { parts } : {},
|
|
1643
2024
|
metadata: typeof message?.name === "string" ? { name: message.name } : void 0
|
|
1644
2025
|
});
|
|
1645
2026
|
}
|
|
@@ -2067,50 +2448,63 @@ function fromNativeProvider(provider, options) {
|
|
|
2067
2448
|
modelName,
|
|
2068
2449
|
capabilities: resolveCapabilities(provider.providerName),
|
|
2069
2450
|
invoke: async (messages, _invokeOptions) => {
|
|
2070
|
-
const
|
|
2071
|
-
|
|
2072
|
-
|
|
2451
|
+
const link = linkAbortSignal(_invokeOptions);
|
|
2452
|
+
try {
|
|
2453
|
+
const request = buildRequest(messages, boundTools, options, _invokeOptions);
|
|
2454
|
+
if (link.signal) request.signal = link.signal;
|
|
2455
|
+
const response = await provider.complete(request);
|
|
2456
|
+
return toBaseChatMessage(response);
|
|
2457
|
+
} finally {
|
|
2458
|
+
link.dispose();
|
|
2459
|
+
}
|
|
2073
2460
|
},
|
|
2074
2461
|
stream: async function* (messages, _invokeOptions) {
|
|
2075
|
-
const
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2462
|
+
const link = linkAbortSignal(_invokeOptions);
|
|
2463
|
+
try {
|
|
2464
|
+
const request = buildRequest(messages, boundTools, options, _invokeOptions);
|
|
2465
|
+
request.stream = true;
|
|
2466
|
+
if (link.signal) request.signal = link.signal;
|
|
2467
|
+
let fullContent = "";
|
|
2468
|
+
let allToolCalls = [];
|
|
2469
|
+
let lastUsage;
|
|
2470
|
+
let reasoningBlocks;
|
|
2471
|
+
const toolCallBuffers = /* @__PURE__ */ new Map();
|
|
2472
|
+
for await (const chunk of provider.completeStream(request)) {
|
|
2473
|
+
if (chunk.delta.content) {
|
|
2474
|
+
fullContent += chunk.delta.content;
|
|
2475
|
+
yield chunk.delta.content;
|
|
2476
|
+
}
|
|
2477
|
+
if (chunk.delta.reasoning?.blocks?.length) {
|
|
2478
|
+
reasoningBlocks = chunk.delta.reasoning.blocks;
|
|
2479
|
+
}
|
|
2480
|
+
if (chunk.delta.toolCalls) {
|
|
2481
|
+
for (const tc of chunk.delta.toolCalls) {
|
|
2482
|
+
if (tc.id) {
|
|
2483
|
+
const existing = toolCallBuffers.get(tc.id);
|
|
2484
|
+
if (existing) {
|
|
2485
|
+
if (tc.arguments) existing.arguments += tc.arguments;
|
|
2486
|
+
} else {
|
|
2487
|
+
toolCallBuffers.set(tc.id, {
|
|
2488
|
+
id: tc.id,
|
|
2489
|
+
name: tc.name ?? "",
|
|
2490
|
+
arguments: tc.arguments ?? ""
|
|
2491
|
+
});
|
|
2492
|
+
}
|
|
2102
2493
|
}
|
|
2103
2494
|
}
|
|
2104
2495
|
}
|
|
2496
|
+
if (chunk.usage) lastUsage = chunk.usage;
|
|
2105
2497
|
}
|
|
2106
|
-
if (
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2498
|
+
if (link.signal?.aborted) return;
|
|
2499
|
+
allToolCalls = [...toolCallBuffers.values()];
|
|
2500
|
+
const finalMessage = assembleMessage(fullContent, allToolCalls, lastUsage);
|
|
2501
|
+
if (reasoningBlocks?.length) {
|
|
2502
|
+
finalMessage.reasoning = { blocks: reasoningBlocks };
|
|
2503
|
+
}
|
|
2504
|
+
yield finalMessage;
|
|
2505
|
+
} finally {
|
|
2506
|
+
link.dispose();
|
|
2112
2507
|
}
|
|
2113
|
-
yield finalMessage;
|
|
2114
2508
|
},
|
|
2115
2509
|
bindTools: (tools, _bindOptions) => {
|
|
2116
2510
|
const strict = _bindOptions?.strict ?? false;
|
|
@@ -2573,136 +2967,7 @@ function resolveCapabilities(provider) {
|
|
|
2573
2967
|
|
|
2574
2968
|
// src/smart/toolResponses.ts
|
|
2575
2969
|
init_utilTokens();
|
|
2576
|
-
|
|
2577
|
-
// src/utils/content.ts
|
|
2578
|
-
function contentToString(content) {
|
|
2579
|
-
try {
|
|
2580
|
-
if (content == null) return "";
|
|
2581
|
-
if (typeof content === "string") return content;
|
|
2582
|
-
if (Array.isArray(content)) {
|
|
2583
|
-
return content.map((p) => {
|
|
2584
|
-
if (!p || typeof p !== "object") return String(p);
|
|
2585
|
-
if (p.type === "text") return String(p.text ?? "");
|
|
2586
|
-
if (p.type === "image_url") {
|
|
2587
|
-
const img = p.image_url;
|
|
2588
|
-
const url = typeof img === "string" ? img : img?.url;
|
|
2589
|
-
const detail = typeof img === "string" ? void 0 : img?.detail;
|
|
2590
|
-
return `[image:${url || "unknown"}${detail ? ` detail=${detail}` : ""}]`;
|
|
2591
|
-
}
|
|
2592
|
-
return JSON.stringify(p);
|
|
2593
|
-
}).join("\n");
|
|
2594
|
-
}
|
|
2595
|
-
return JSON.stringify(content);
|
|
2596
|
-
} catch {
|
|
2597
|
-
return String(content);
|
|
2598
|
-
}
|
|
2599
|
-
}
|
|
2600
|
-
function mergeContentsToString(contents) {
|
|
2601
|
-
return contents.map((c) => contentToString(c)).join("\n");
|
|
2602
|
-
}
|
|
2603
|
-
function safeStringify(value, pretty = false) {
|
|
2604
|
-
if (value == null) return "";
|
|
2605
|
-
if (typeof value === "string") return value;
|
|
2606
|
-
try {
|
|
2607
|
-
return JSON.stringify(value, null, pretty ? 2 : void 0) ?? String(value);
|
|
2608
|
-
} catch {
|
|
2609
|
-
return String(value);
|
|
2610
|
-
}
|
|
2611
|
-
}
|
|
2612
|
-
function extractMessageText2(message) {
|
|
2613
|
-
if (!message) return "";
|
|
2614
|
-
const content = message.content;
|
|
2615
|
-
if (typeof content === "string") return content;
|
|
2616
|
-
if (Array.isArray(content)) {
|
|
2617
|
-
return content.map((part) => typeof part === "string" ? part : part?.text ?? part?.content ?? "").join("");
|
|
2618
|
-
}
|
|
2619
|
-
return "";
|
|
2620
|
-
}
|
|
2621
|
-
function textFromContent(content) {
|
|
2622
|
-
if (typeof content === "string") return content;
|
|
2623
|
-
if (!Array.isArray(content)) return "";
|
|
2624
|
-
return content.filter((part) => isTextPart(part)).map((part) => part.text ?? "").join("\n");
|
|
2625
|
-
}
|
|
2626
|
-
function isTextPart(part) {
|
|
2627
|
-
return !!part && typeof part === "object" && part.type === "text";
|
|
2628
|
-
}
|
|
2629
|
-
function mapTextParts(content, fn) {
|
|
2630
|
-
if (typeof content === "string") return fn(content);
|
|
2631
|
-
if (!Array.isArray(content)) return content;
|
|
2632
|
-
return content.map((part) => isTextPart(part) ? { ...part, text: fn(part.text) } : part);
|
|
2633
|
-
}
|
|
2634
|
-
function replaceTextContent(content, text) {
|
|
2635
|
-
if (typeof content === "string" || content == null) return text;
|
|
2636
|
-
if (!Array.isArray(content)) return text;
|
|
2637
|
-
const textIndexes = content.reduce((acc, part, index) => {
|
|
2638
|
-
if (isTextPart(part)) acc.push(index);
|
|
2639
|
-
return acc;
|
|
2640
|
-
}, []);
|
|
2641
|
-
if (textIndexes.length === 0) {
|
|
2642
|
-
return text.length > 0 ? [{ type: "text", text }, ...content] : content;
|
|
2643
|
-
}
|
|
2644
|
-
const [first, ...rest] = textIndexes;
|
|
2645
|
-
const dropped = new Set(rest);
|
|
2646
|
-
return content.map((part, index) => index === first ? { ...part, text } : part).filter((_part, index) => !dropped.has(index));
|
|
2647
|
-
}
|
|
2648
|
-
function normalizeSource(source) {
|
|
2649
|
-
if (!source || typeof source !== "object") return {};
|
|
2650
|
-
const src = source;
|
|
2651
|
-
if (src.type === "base64" && typeof src.data === "string") {
|
|
2652
|
-
return {
|
|
2653
|
-
sourceType: "base64",
|
|
2654
|
-
mediaType: typeof src.mediaType === "string" ? src.mediaType : void 0,
|
|
2655
|
-
// base64 encodes 3 bytes per 4 characters; padding makes this an upper bound.
|
|
2656
|
-
approxBytes: Math.floor(src.data.length * 3 / 4)
|
|
2657
|
-
};
|
|
2658
|
-
}
|
|
2659
|
-
if (src.type === "url" && typeof src.url === "string") {
|
|
2660
|
-
return {
|
|
2661
|
-
sourceType: "url",
|
|
2662
|
-
url: src.url,
|
|
2663
|
-
mediaType: typeof src.mediaType === "string" ? src.mediaType : void 0
|
|
2664
|
-
};
|
|
2665
|
-
}
|
|
2666
|
-
return {};
|
|
2667
|
-
}
|
|
2668
|
-
function collectAttachments(content) {
|
|
2669
|
-
if (!Array.isArray(content)) return [];
|
|
2670
|
-
const attachments = [];
|
|
2671
|
-
content.forEach((part, index) => {
|
|
2672
|
-
if (!part || typeof part !== "object") return;
|
|
2673
|
-
const type = part.type;
|
|
2674
|
-
if (!type || type === "text") return;
|
|
2675
|
-
if (type === "image" || type === "audio" || type === "video" || type === "file") {
|
|
2676
|
-
attachments.push({
|
|
2677
|
-
index,
|
|
2678
|
-
kind: type,
|
|
2679
|
-
fileName: typeof part.fileName === "string" ? part.fileName : void 0,
|
|
2680
|
-
...normalizeSource(part.source)
|
|
2681
|
-
});
|
|
2682
|
-
return;
|
|
2683
|
-
}
|
|
2684
|
-
if (type === "image_url") {
|
|
2685
|
-
const image = part.image_url;
|
|
2686
|
-
const url = typeof image === "string" ? image : image?.url;
|
|
2687
|
-
if (typeof url === "string" && url.startsWith("data:")) {
|
|
2688
|
-
const comma = url.indexOf(",");
|
|
2689
|
-
const header = url.slice(5, comma);
|
|
2690
|
-
attachments.push({
|
|
2691
|
-
index,
|
|
2692
|
-
kind: "image",
|
|
2693
|
-
sourceType: "base64",
|
|
2694
|
-
mediaType: header.split(";")[0] || void 0,
|
|
2695
|
-
approxBytes: Math.floor((url.length - comma - 1) * 3 / 4)
|
|
2696
|
-
});
|
|
2697
|
-
} else {
|
|
2698
|
-
attachments.push({ index, kind: "image", sourceType: "url", url });
|
|
2699
|
-
}
|
|
2700
|
-
return;
|
|
2701
|
-
}
|
|
2702
|
-
attachments.push({ index, kind: "unknown" });
|
|
2703
|
-
});
|
|
2704
|
-
return attachments;
|
|
2705
|
-
}
|
|
2970
|
+
init_content();
|
|
2706
2971
|
|
|
2707
2972
|
// src/smart/toolArgCoercion.ts
|
|
2708
2973
|
var PLACEHOLDER_TEXT = /* @__PURE__ */ new Set(["", "null", "undefined", "none", "nil", "n/a", "na"]);
|
|
@@ -3591,6 +3856,7 @@ function detectVolatileContent(text, limit = 20) {
|
|
|
3591
3856
|
|
|
3592
3857
|
// src/smart/contextPilot/jsonCrusher.ts
|
|
3593
3858
|
init_utilTokens();
|
|
3859
|
+
init_content();
|
|
3594
3860
|
var CONTEXT_PILOT_JSON_MARKER_KEY = "__contextPilotDropped";
|
|
3595
3861
|
function findCompressibleArray(output, minItems) {
|
|
3596
3862
|
if (Array.isArray(output)) {
|
|
@@ -3803,6 +4069,7 @@ function compressSearchOutput(text, config, ccrStore) {
|
|
|
3803
4069
|
|
|
3804
4070
|
// src/smart/contextPilot/pipeline.ts
|
|
3805
4071
|
init_utilTokens();
|
|
4072
|
+
init_content();
|
|
3806
4073
|
function createContextPilotRuntime(config) {
|
|
3807
4074
|
return {
|
|
3808
4075
|
ccrStore: new CCRStore({ ttlMs: config.ccr.ttlMs, maxEntries: config.ccr.maxEntries }),
|
|
@@ -4176,6 +4443,8 @@ function createAgentCoreNode(opts) {
|
|
|
4176
4443
|
const streamingEnabled = Boolean(state.ctx?.__streaming);
|
|
4177
4444
|
const cancellationToken = state.ctx?.__cancellationToken;
|
|
4178
4445
|
const abortSignal = state.ctx?.__abortSignal;
|
|
4446
|
+
const onProgress = state.ctx?.__onProgress;
|
|
4447
|
+
const cancelRequested = () => isCancellationRequested({ signal: abortSignal, cancellationToken });
|
|
4179
4448
|
const resolvedForCachePilot = getResolvedSmartConfig(opts, runtime);
|
|
4180
4449
|
if (resolvedForCachePilot.contextPilot.enabled && resolvedForCachePilot.contextPilot.cacheAlignment.enabled) {
|
|
4181
4450
|
const ctxForCacheWarning = state.ctx = state.ctx || {};
|
|
@@ -4331,9 +4600,32 @@ ${append}`;
|
|
|
4331
4600
|
}
|
|
4332
4601
|
return merged;
|
|
4333
4602
|
};
|
|
4334
|
-
let response;
|
|
4335
|
-
let modelAttempt = 0;
|
|
4336
|
-
const maxModelRetries = host?.maxModelRetries ?? 0;
|
|
4603
|
+
let response;
|
|
4604
|
+
let modelAttempt = 0;
|
|
4605
|
+
const maxModelRetries = host?.maxModelRetries ?? 0;
|
|
4606
|
+
const finishCancelledTurn = (partialText) => {
|
|
4607
|
+
const reason = abortSignal?.aborted ? "aborted" : "cancelled";
|
|
4608
|
+
const ctx = state.ctx = state.ctx || {};
|
|
4609
|
+
ctx.__cancelled = { stage: "agent", reason, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
4610
|
+
recordTraceEvent(traceSession, {
|
|
4611
|
+
type: "ai_call",
|
|
4612
|
+
label: "Assistant Cancelled",
|
|
4613
|
+
actor: { scope: "agent", name: actorName, role: "assistant", version: actorVersion },
|
|
4614
|
+
// "skipped", not "error": the call did not fail, the caller ended it —
|
|
4615
|
+
// and an "error" would flip the whole session to error.
|
|
4616
|
+
status: "skipped",
|
|
4617
|
+
durationMs: Date.now() - start,
|
|
4618
|
+
requestBytes: promptBytes,
|
|
4619
|
+
model: getModelName(runtime.model || opts.model),
|
|
4620
|
+
provider: getProviderName(runtime.model || opts.model),
|
|
4621
|
+
messageList: state.messages,
|
|
4622
|
+
toolDefinitions: traceToolDefinitions
|
|
4623
|
+
});
|
|
4624
|
+
onEvent?.({ type: "cancelled", stage: "agent", reason });
|
|
4625
|
+
onProgress?.({ stage: "agent", message: "Cancelled", detail: { reason } });
|
|
4626
|
+
const partial = partialText.trim().length > 0 ? [{ role: "assistant", content: partialText }] : [];
|
|
4627
|
+
return { messages: [...state.messages, ...partial], usage: state.usage };
|
|
4628
|
+
};
|
|
4337
4629
|
while (true) {
|
|
4338
4630
|
start = Date.now();
|
|
4339
4631
|
if (shortCircuited !== void 0) {
|
|
@@ -4349,14 +4641,16 @@ ${append}`;
|
|
|
4349
4641
|
toolDefinitions: traceToolDefinitions
|
|
4350
4642
|
});
|
|
4351
4643
|
} else {
|
|
4644
|
+
let streamedText = "";
|
|
4352
4645
|
try {
|
|
4353
4646
|
const normalizedMessages = normalizeBedrockToolPairing([...wireMessages]);
|
|
4354
4647
|
debugToolPairing(normalizedMessages);
|
|
4355
4648
|
if (streamingEnabled && typeof modelWithTools.stream === "function") {
|
|
4356
|
-
let streamedText = "";
|
|
4357
4649
|
let streamedMessage;
|
|
4650
|
+
let cutByCancel = false;
|
|
4358
4651
|
for await (const chunk of modelWithTools.stream(normalizedMessages, invokeParams)) {
|
|
4359
|
-
if (
|
|
4652
|
+
if (cancelRequested()) {
|
|
4653
|
+
cutByCancel = true;
|
|
4360
4654
|
break;
|
|
4361
4655
|
}
|
|
4362
4656
|
if (chunk && typeof chunk === "object" && chunk.role) {
|
|
@@ -4370,6 +4664,7 @@ ${append}`;
|
|
|
4370
4664
|
onEvent?.({ type: "stream", text });
|
|
4371
4665
|
}
|
|
4372
4666
|
}
|
|
4667
|
+
if (cutByCancel) return finishCancelledTurn(streamedText);
|
|
4373
4668
|
if (streamedMessage) {
|
|
4374
4669
|
response = { ...streamedMessage };
|
|
4375
4670
|
if (response.content == null || response.content === "") {
|
|
@@ -4382,6 +4677,7 @@ ${append}`;
|
|
|
4382
4677
|
response = await modelWithTools.invoke(normalizedMessages, invokeParams);
|
|
4383
4678
|
}
|
|
4384
4679
|
} catch (err) {
|
|
4680
|
+
if (cancelRequested()) return finishCancelledTurn(streamedText);
|
|
4385
4681
|
const durationMs2 = Date.now() - start;
|
|
4386
4682
|
recordTraceEvent(traceSession, {
|
|
4387
4683
|
type: "ai_call",
|
|
@@ -4479,6 +4775,7 @@ ${append}`;
|
|
|
4479
4775
|
}
|
|
4480
4776
|
|
|
4481
4777
|
// src/utils/traceSections.ts
|
|
4778
|
+
init_content();
|
|
4482
4779
|
function truncate(text, max = 500) {
|
|
4483
4780
|
if (!text) return "";
|
|
4484
4781
|
return text.length > max ? `${text.slice(0, max)}\u2026` : text;
|
|
@@ -6369,6 +6666,9 @@ function isCompactedToolContent(content) {
|
|
|
6369
6666
|
return typeof content === "string" && (content === "SUMMARIZED" || content.startsWith("SUMMARIZED_TOOL_RESPONSE") || content.startsWith("ARCHIVED_TOOL_RESPONSE") || content.startsWith("STRUCTURED_TOOL_RESPONSE") || content.startsWith("DROPPED_TOOL_RESPONSE"));
|
|
6370
6667
|
}
|
|
6371
6668
|
|
|
6669
|
+
// src/agent.ts
|
|
6670
|
+
init_content();
|
|
6671
|
+
|
|
6372
6672
|
// src/structuredOutput/manager.ts
|
|
6373
6673
|
var StructuredOutputManager = class {
|
|
6374
6674
|
constructor(schema, strategy, config) {
|
|
@@ -6601,6 +6901,7 @@ function buildSubagentCatalogBlock(subagents, policy, toolNames) {
|
|
|
6601
6901
|
}
|
|
6602
6902
|
|
|
6603
6903
|
// src/plugins/host.ts
|
|
6904
|
+
init_content();
|
|
6604
6905
|
var DEFAULT_PRIORITY = 100;
|
|
6605
6906
|
var DEFAULT_TIMEOUT_MS = 1e4;
|
|
6606
6907
|
var HOOK_SPECS = {
|
|
@@ -7137,6 +7438,7 @@ function performanceNow() {
|
|
|
7137
7438
|
}
|
|
7138
7439
|
|
|
7139
7440
|
// src/plugins/session.ts
|
|
7441
|
+
init_content();
|
|
7140
7442
|
async function openPluginSession(runHost, params) {
|
|
7141
7443
|
let messages = params.messages;
|
|
7142
7444
|
const startGate = await runHost.runGate("sessionStart", {
|
|
@@ -7606,6 +7908,7 @@ function createAgent(opts) {
|
|
|
7606
7908
|
onProgress?.({ stage: "agent", message: "Invoking model" });
|
|
7607
7909
|
if (cancelIfRequested("before_agent")) break;
|
|
7608
7910
|
state = publish({ ...state, ...await agentCore(state) });
|
|
7911
|
+
if (state.ctx?.__cancelled) break;
|
|
7609
7912
|
onProgress?.({ stage: "agent", message: "Model response received" });
|
|
7610
7913
|
if (checkpointIfRequested("after_agent")) break;
|
|
7611
7914
|
const postGuardrails = getGuardrailConfig(state);
|
|
@@ -7676,7 +7979,7 @@ function createAgent(opts) {
|
|
|
7676
7979
|
if (toolCalls.length === 0) {
|
|
7677
7980
|
if (soManager && !state.ctx?.__finalizedDueToStructuredOutput && !state.ctx?.__structuredOutputForceFinalize && !state.ctx?.__guardrailBlocked) {
|
|
7678
7981
|
if (soManager.strategy.kind === "native") {
|
|
7679
|
-
const assistantText =
|
|
7982
|
+
const assistantText = extractMessageText(lastMsg);
|
|
7680
7983
|
if (assistantText) {
|
|
7681
7984
|
const parsed = soManager.parseFromContent(assistantText);
|
|
7682
7985
|
if (parsed.success) {
|
|
@@ -7732,7 +8035,7 @@ function createAgent(opts) {
|
|
|
7732
8035
|
if (soManager && !state.ctx?.__finalizedDueToStructuredOutput && !structuredFinalizeBlocked) {
|
|
7733
8036
|
const lastForParse = state.messages[state.messages.length - 1];
|
|
7734
8037
|
if (lastForParse?.role === "assistant") {
|
|
7735
|
-
const assistantText =
|
|
8038
|
+
const assistantText = extractMessageText(lastForParse);
|
|
7736
8039
|
if (assistantText) {
|
|
7737
8040
|
const parsed = soManager.parseFromContent(assistantText);
|
|
7738
8041
|
if (parsed.success) {
|
|
@@ -7994,7 +8297,7 @@ function createAgent(opts) {
|
|
|
7994
8297
|
const isTransientSummarizationExit = !!res.ctx?.__needsSummarization;
|
|
7995
8298
|
const finalAssistantMsg = isTransientSummarizationExit ? void 0 : getLastAssistantMessage(res.messages);
|
|
7996
8299
|
const finalIsSyntheticSummary = !isTransientSummarizationExit && finalAssistantMsg && isSyntheticSummaryMessage(finalAssistantMsg);
|
|
7997
|
-
let content = isTransientSummarizationExit || finalIsSyntheticSummary ? "" :
|
|
8300
|
+
let content = isTransientSummarizationExit || finalIsSyntheticSummary ? "" : extractMessageText(finalAssistantMsg);
|
|
7998
8301
|
const finalAnswerBlocked = Boolean(
|
|
7999
8302
|
isTransientSummarizationExit || res.ctx?.__awaitingApproval || res.ctx?.__awaitingUserQuestion || res.ctx?.__cancelled || res.ctx?.__paused || res.ctx?.__limitBreached
|
|
8000
8303
|
);
|
|
@@ -8253,9 +8556,11 @@ function createAgentNode(opts) {
|
|
|
8253
8556
|
|
|
8254
8557
|
// src/nodes/contextSummarize.ts
|
|
8255
8558
|
init_utilTokens();
|
|
8559
|
+
init_content();
|
|
8256
8560
|
|
|
8257
8561
|
// src/smart/contextPolicy.ts
|
|
8258
8562
|
init_utilTokens();
|
|
8563
|
+
init_content();
|
|
8259
8564
|
function collectRecentTurns(messages, lastTurnsToKeep) {
|
|
8260
8565
|
if (lastTurnsToKeep <= 0) return [];
|
|
8261
8566
|
const systemPrefix = messages.filter((message, index) => index === 0 && message.role === "system");
|
|
@@ -8317,7 +8622,7 @@ function isClampProtected(message, index, firstUserIndex) {
|
|
|
8317
8622
|
function clampToBudget(messages, maxContextTokens) {
|
|
8318
8623
|
let working = [...messages];
|
|
8319
8624
|
while (working.length > 2) {
|
|
8320
|
-
const tokenCount = countApproxTokens(working.map(
|
|
8625
|
+
const tokenCount = countApproxTokens(working.map(extractMessageText).join("\n"));
|
|
8321
8626
|
if (tokenCount <= maxContextTokens) return working;
|
|
8322
8627
|
const firstUserIndex = working.findIndex((message) => message.role === "user");
|
|
8323
8628
|
const firstNonSystem = working.findIndex((message, index) => !isClampProtected(message, index, firstUserIndex));
|
|
@@ -8657,7 +8962,7 @@ function createContextSummarizeNode(opts) {
|
|
|
8657
8962
|
let content = "";
|
|
8658
8963
|
if (typeof m.content === "string") content = m.content;
|
|
8659
8964
|
else if (Array.isArray(m.content)) {
|
|
8660
|
-
content = m.content.map((c) => c
|
|
8965
|
+
content = m.content.map((c) => contentPartToText(c, (part) => JSON.stringify(part))).join(" ");
|
|
8661
8966
|
}
|
|
8662
8967
|
if (m.role === "tool" && isSummarizedToolPlaceholder(content)) {
|
|
8663
8968
|
const historyEntry = findToolHistoryEntry(state, m.tool_call_id, m.name);
|
|
@@ -9502,6 +9807,9 @@ async function writeSummaryFactsToMemory(store, config, summary, sourceTurn) {
|
|
|
9502
9807
|
return store.get(config.memory.scope, { limit: config.context.lastTurnsToKeep + summary.stable_facts.length });
|
|
9503
9808
|
}
|
|
9504
9809
|
|
|
9810
|
+
// src/smart/index.ts
|
|
9811
|
+
init_content();
|
|
9812
|
+
|
|
9505
9813
|
// src/smart/skills/types.ts
|
|
9506
9814
|
var DEFAULT_SKILL_POLICY = {
|
|
9507
9815
|
maxOpenSkills: 4,
|
|
@@ -10516,7 +10824,7 @@ function createSmartAgent(opts) {
|
|
|
10516
10824
|
].join("\n");
|
|
10517
10825
|
function latestUserPrompt(messages) {
|
|
10518
10826
|
const latest = [...messages].reverse().find((message) => message.role === "user");
|
|
10519
|
-
return latest ?
|
|
10827
|
+
return latest ? extractMessageText(latest) : "";
|
|
10520
10828
|
}
|
|
10521
10829
|
async function syncMemory(state) {
|
|
10522
10830
|
const query = latestUserPrompt(state.messages || []);
|
|
@@ -11227,6 +11535,132 @@ async function runSmartAgentEvalHarness(params) {
|
|
|
11227
11535
|
}
|
|
11228
11536
|
return results;
|
|
11229
11537
|
}
|
|
11538
|
+
|
|
11539
|
+
// src/providers/base.ts
|
|
11540
|
+
var DEFAULT_RETRY = {
|
|
11541
|
+
maxRetries: 3,
|
|
11542
|
+
baseDelayMs: 500,
|
|
11543
|
+
maxDelayMs: 8e3
|
|
11544
|
+
};
|
|
11545
|
+
var BaseProvider = class {
|
|
11546
|
+
constructor() {
|
|
11547
|
+
this.retryPolicy = DEFAULT_RETRY;
|
|
11548
|
+
}
|
|
11549
|
+
/**
|
|
11550
|
+
* Helper concrete providers can wrap their fetch with. Retries 429/5xx
|
|
11551
|
+
* with exponential backoff and respects Retry-After if the response
|
|
11552
|
+
* carries one.
|
|
11553
|
+
*
|
|
11554
|
+
* `signal` is the call's cancellation: a run that is cancelled while the
|
|
11555
|
+
* provider is backing off must not sit out the delay, nor start another attempt.
|
|
11556
|
+
*/
|
|
11557
|
+
async doFetchWithRetry(execute, signal) {
|
|
11558
|
+
const policy = this.retryPolicy;
|
|
11559
|
+
const maxRetries = Math.max(0, policy.maxRetries ?? DEFAULT_RETRY.maxRetries);
|
|
11560
|
+
const baseDelay = Math.max(0, policy.baseDelayMs ?? DEFAULT_RETRY.baseDelayMs);
|
|
11561
|
+
const maxDelay = Math.max(baseDelay, policy.maxDelayMs ?? DEFAULT_RETRY.maxDelayMs);
|
|
11562
|
+
let lastResp;
|
|
11563
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
11564
|
+
if (signal?.aborted) throw abortReason(signal);
|
|
11565
|
+
const res = await execute();
|
|
11566
|
+
const isRetryable = res.status === 429 || res.status >= 500 && res.status < 600;
|
|
11567
|
+
if (!isRetryable) return res;
|
|
11568
|
+
const predicate = policy.shouldRetry;
|
|
11569
|
+
if (predicate && !predicate({ status: res.status }, attempt)) return res;
|
|
11570
|
+
if (attempt === maxRetries) {
|
|
11571
|
+
lastResp = res;
|
|
11572
|
+
break;
|
|
11573
|
+
}
|
|
11574
|
+
const retryAfter = res.headers.get("retry-after");
|
|
11575
|
+
let delay2 = Math.min(maxDelay, baseDelay * Math.pow(2, attempt));
|
|
11576
|
+
if (retryAfter) {
|
|
11577
|
+
const asNumber = Number(retryAfter);
|
|
11578
|
+
if (!Number.isNaN(asNumber)) delay2 = Math.min(maxDelay, Math.max(delay2, asNumber * 1e3));
|
|
11579
|
+
}
|
|
11580
|
+
try {
|
|
11581
|
+
await res.text();
|
|
11582
|
+
} catch {
|
|
11583
|
+
}
|
|
11584
|
+
await abortableSleep(delay2, signal);
|
|
11585
|
+
}
|
|
11586
|
+
return lastResp;
|
|
11587
|
+
}
|
|
11588
|
+
};
|
|
11589
|
+
|
|
11590
|
+
// src/providers/types.ts
|
|
11591
|
+
function emptyUsage() {
|
|
11592
|
+
return {
|
|
11593
|
+
inputTokens: 0,
|
|
11594
|
+
outputTokens: 0,
|
|
11595
|
+
totalTokens: 0,
|
|
11596
|
+
cachedInputTokens: 0,
|
|
11597
|
+
cachedWriteTokens: 0,
|
|
11598
|
+
cachedOutputTokens: 0,
|
|
11599
|
+
reasoningTokens: 0
|
|
11600
|
+
};
|
|
11601
|
+
}
|
|
11602
|
+
var ProviderError = class extends Error {
|
|
11603
|
+
constructor(message, provider, statusCode, responseBody) {
|
|
11604
|
+
super(message);
|
|
11605
|
+
this.provider = provider;
|
|
11606
|
+
this.statusCode = statusCode;
|
|
11607
|
+
this.responseBody = responseBody;
|
|
11608
|
+
this.name = "ProviderError";
|
|
11609
|
+
}
|
|
11610
|
+
};
|
|
11611
|
+
|
|
11612
|
+
// src/providers/jev.ts
|
|
11613
|
+
var JEV_DEFAULT_BASE_URL = "https://api.typesafe.ai";
|
|
11614
|
+
var JevProvider = class extends BaseProvider {
|
|
11615
|
+
constructor(config) {
|
|
11616
|
+
super();
|
|
11617
|
+
this.providerName = "jev";
|
|
11618
|
+
this.apiKey = config.apiKey;
|
|
11619
|
+
this.baseURL = (config.baseURL ?? JEV_DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
11620
|
+
this.defaultModel = config.defaultModel;
|
|
11621
|
+
this.defaultHeaders = config.defaultHeaders ?? {};
|
|
11622
|
+
if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
|
|
11623
|
+
}
|
|
11624
|
+
/** Ask System One questions about `state`. */
|
|
11625
|
+
async systemOne(request, options) {
|
|
11626
|
+
const model = request.model ?? this.defaultModel;
|
|
11627
|
+
const body = {
|
|
11628
|
+
...model ? { model } : {},
|
|
11629
|
+
state: request.state,
|
|
11630
|
+
questions: request.questions
|
|
11631
|
+
};
|
|
11632
|
+
const res = await this.doFetchWithRetry(
|
|
11633
|
+
() => fetch(`${this.baseURL}/v1/systemone`, {
|
|
11634
|
+
method: "POST",
|
|
11635
|
+
headers: {
|
|
11636
|
+
"Content-Type": "application/json",
|
|
11637
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
11638
|
+
...this.defaultHeaders
|
|
11639
|
+
},
|
|
11640
|
+
body: JSON.stringify(body),
|
|
11641
|
+
signal: options?.signal
|
|
11642
|
+
})
|
|
11643
|
+
);
|
|
11644
|
+
if (!res.ok) {
|
|
11645
|
+
const text = await res.text().catch(() => "");
|
|
11646
|
+
throw new ProviderError(`Jev API error ${res.status}: ${text}`, this.providerName, res.status, text);
|
|
11647
|
+
}
|
|
11648
|
+
return await res.json();
|
|
11649
|
+
}
|
|
11650
|
+
async complete(_request) {
|
|
11651
|
+
throw new ProviderError(
|
|
11652
|
+
'Jev is a decision model and has no chat completion; use systemOne() or agentVerdictRule({ engine: "jev" })',
|
|
11653
|
+
this.providerName
|
|
11654
|
+
);
|
|
11655
|
+
}
|
|
11656
|
+
// eslint-disable-next-line require-yield
|
|
11657
|
+
async *completeStream(_request) {
|
|
11658
|
+
throw new ProviderError("Jev does not stream; use systemOne()", this.providerName);
|
|
11659
|
+
}
|
|
11660
|
+
};
|
|
11661
|
+
|
|
11662
|
+
// src/guardrails/checks.ts
|
|
11663
|
+
init_content();
|
|
11230
11664
|
var Ajv = AjvModule__default.default?.default ?? AjvModule__default.default;
|
|
11231
11665
|
var defaultAjv = new Ajv({ allErrors: true });
|
|
11232
11666
|
defaultAjv.opts.strict = false;
|
|
@@ -11376,14 +11810,82 @@ function defaultPayload(context) {
|
|
|
11376
11810
|
2
|
|
11377
11811
|
);
|
|
11378
11812
|
}
|
|
11813
|
+
var DEFAULT_JEV_THRESHOLD = 0.5;
|
|
11814
|
+
var JEV_QUESTION_KEY = "shouldBlock";
|
|
11815
|
+
var DEFAULT_JEV_QUESTION = "Does this conversation payload pose a safety, security, or policy risk that should stop the agent from continuing? Answer yes when the latest message or action should be blocked, and no when it is safe to allow.";
|
|
11816
|
+
var DEFAULT_JEV_CRITERIA = {
|
|
11817
|
+
true: "The payload is unsafe, non-compliant, or otherwise warrants blocking.",
|
|
11818
|
+
false: "The payload is benign and the agent should be allowed to continue."
|
|
11819
|
+
};
|
|
11820
|
+
function resolveJevClient(config) {
|
|
11821
|
+
if (config.client) return config.client;
|
|
11822
|
+
const apiKey = config.apiKey ?? process.env.TYPESAFE_API_KEY;
|
|
11823
|
+
if (!apiKey) {
|
|
11824
|
+
throw new Error(
|
|
11825
|
+
"Jev engine requires an API key: pass `jev.apiKey`, set TYPESAFE_API_KEY, or pass a `jev.client`."
|
|
11826
|
+
);
|
|
11827
|
+
}
|
|
11828
|
+
return new JevProvider({
|
|
11829
|
+
provider: "jev",
|
|
11830
|
+
apiKey,
|
|
11831
|
+
baseURL: config.baseURL ?? process.env.TYPESAFE_BASE_URL
|
|
11832
|
+
});
|
|
11833
|
+
}
|
|
11379
11834
|
function agentVerdictRule(options) {
|
|
11380
11835
|
const payloadBuilder = options.payloadBuilder || defaultPayload;
|
|
11381
11836
|
const fallbackDisposition = options.dispositionFallback || "block";
|
|
11837
|
+
const engine = options.engine || "llm";
|
|
11838
|
+
const jevOptions = options.jev || {};
|
|
11839
|
+
const jevThreshold = typeof jevOptions.threshold === "number" ? jevOptions.threshold : DEFAULT_JEV_THRESHOLD;
|
|
11840
|
+
let jevClient;
|
|
11841
|
+
async function evaluateWithJev(context) {
|
|
11842
|
+
const client = jevClient ?? (jevClient = resolveJevClient(jevOptions));
|
|
11843
|
+
const instructions = jevOptions.question ? jevOptions.question(context) : DEFAULT_JEV_QUESTION;
|
|
11844
|
+
const result = await client.systemOne({
|
|
11845
|
+
state: payloadBuilder(context),
|
|
11846
|
+
questions: {
|
|
11847
|
+
[JEV_QUESTION_KEY]: {
|
|
11848
|
+
type: "noul",
|
|
11849
|
+
instructions,
|
|
11850
|
+
criteria: jevOptions.criteria ?? DEFAULT_JEV_CRITERIA
|
|
11851
|
+
}
|
|
11852
|
+
},
|
|
11853
|
+
...jevOptions.model ? { model: jevOptions.model } : {}
|
|
11854
|
+
});
|
|
11855
|
+
const answer = result?.answers?.[JEV_QUESTION_KEY];
|
|
11856
|
+
const probability = typeof answer?.noul === "number" ? answer.noul : void 0;
|
|
11857
|
+
if (probability === void 0) {
|
|
11858
|
+
return {
|
|
11859
|
+
passed: false,
|
|
11860
|
+
disposition: fallbackDisposition,
|
|
11861
|
+
reason: "Jev engine did not return a noul probability.",
|
|
11862
|
+
details: { jevModel: result?.model, jevUsage: result?.usage }
|
|
11863
|
+
};
|
|
11864
|
+
}
|
|
11865
|
+
const passed = probability < jevThreshold;
|
|
11866
|
+
return {
|
|
11867
|
+
passed,
|
|
11868
|
+
disposition: passed ? "allow" : fallbackDisposition,
|
|
11869
|
+
reason: passed ? void 0 : `Jev risk probability ${probability.toFixed(3)} met or exceeded threshold ${jevThreshold}.`,
|
|
11870
|
+
details: {
|
|
11871
|
+
jevProbability: probability,
|
|
11872
|
+
jevThreshold,
|
|
11873
|
+
jevModel: result?.model,
|
|
11874
|
+
jevUsage: result?.usage
|
|
11875
|
+
}
|
|
11876
|
+
};
|
|
11877
|
+
}
|
|
11382
11878
|
return {
|
|
11383
11879
|
id: options.id,
|
|
11384
11880
|
title: options.title || "Agent-based guardrail",
|
|
11385
11881
|
description: options.description,
|
|
11386
11882
|
async evaluate(context) {
|
|
11883
|
+
if (engine === "jev") {
|
|
11884
|
+
return evaluateWithJev(context);
|
|
11885
|
+
}
|
|
11886
|
+
if (!options.agent) {
|
|
11887
|
+
throw new Error("agentVerdictRule requires an `agent` when using the default 'llm' engine.");
|
|
11888
|
+
}
|
|
11387
11889
|
const payload = payloadBuilder(context);
|
|
11388
11890
|
const systemPrompt = options.systemPrompt || "You are a safety auditor. Review the provided conversation payload and decide whether it should continue. Return JSON with keys allow (boolean), optional disposition ('allow' | 'warn' | 'block'), optional reason (string), and optional details (object).";
|
|
11389
11891
|
const review = await options.agent.invoke({
|
|
@@ -11599,6 +12101,7 @@ function isHookImplemented(hook) {
|
|
|
11599
12101
|
}
|
|
11600
12102
|
|
|
11601
12103
|
// src/plugins/builtin/guardrail.ts
|
|
12104
|
+
init_content();
|
|
11602
12105
|
var ALLOW = { action: "allow" };
|
|
11603
12106
|
var RETRYABLE_STATUS = /* @__PURE__ */ new Set([408, 425, 429, 500, 502, 503, 504]);
|
|
11604
12107
|
var RetryableGuardrailError = class extends Error {
|
|
@@ -11885,7 +12388,7 @@ function createGuardrailPlugin(options) {
|
|
|
11885
12388
|
return { decision: "deny", reason: verdict.message ?? "Request blocked by guardrail policy." };
|
|
11886
12389
|
},
|
|
11887
12390
|
postModelCall: async ({ message }, ctx) => {
|
|
11888
|
-
const text =
|
|
12391
|
+
const text = extractMessageText(message);
|
|
11889
12392
|
if (!text) return void 0;
|
|
11890
12393
|
const verdict = await check({ phase: "output", content: text, hook: "postModelCall" }, ctx);
|
|
11891
12394
|
if (!raiseIfFailed(verdict, ctx) || verdict.action === "allow") return void 0;
|
|
@@ -12155,6 +12658,7 @@ function portkeyGuardrail(config = {}) {
|
|
|
12155
12658
|
}
|
|
12156
12659
|
|
|
12157
12660
|
// src/plugins/builtin/piiRedaction.ts
|
|
12661
|
+
init_content();
|
|
12158
12662
|
function isValidTckn(value) {
|
|
12159
12663
|
const digits = value.replace(/\D/g, "");
|
|
12160
12664
|
if (digits.length !== 11 || digits[0] === "0") return false;
|
|
@@ -12274,7 +12778,7 @@ function piiRedaction(config = {}) {
|
|
|
12274
12778
|
},
|
|
12275
12779
|
postModelCall: ({ message }, ctx) => {
|
|
12276
12780
|
if (!applied.has("modelOutput")) return void 0;
|
|
12277
|
-
const text =
|
|
12781
|
+
const text = extractMessageText(message);
|
|
12278
12782
|
if (!text) return void 0;
|
|
12279
12783
|
const result = redactText(text, detectors, mask);
|
|
12280
12784
|
if (result.findings.length === 0) return void 0;
|
|
@@ -14681,74 +15185,8 @@ function languageGuard(config) {
|
|
|
14681
15185
|
};
|
|
14682
15186
|
}
|
|
14683
15187
|
|
|
14684
|
-
// src/
|
|
14685
|
-
|
|
14686
|
-
return {
|
|
14687
|
-
inputTokens: 0,
|
|
14688
|
-
outputTokens: 0,
|
|
14689
|
-
totalTokens: 0,
|
|
14690
|
-
cachedInputTokens: 0,
|
|
14691
|
-
cachedWriteTokens: 0,
|
|
14692
|
-
cachedOutputTokens: 0,
|
|
14693
|
-
reasoningTokens: 0
|
|
14694
|
-
};
|
|
14695
|
-
}
|
|
14696
|
-
var ProviderError = class extends Error {
|
|
14697
|
-
constructor(message, provider, statusCode, responseBody) {
|
|
14698
|
-
super(message);
|
|
14699
|
-
this.provider = provider;
|
|
14700
|
-
this.statusCode = statusCode;
|
|
14701
|
-
this.responseBody = responseBody;
|
|
14702
|
-
this.name = "ProviderError";
|
|
14703
|
-
}
|
|
14704
|
-
};
|
|
14705
|
-
|
|
14706
|
-
// src/providers/base.ts
|
|
14707
|
-
var DEFAULT_RETRY = {
|
|
14708
|
-
maxRetries: 3,
|
|
14709
|
-
baseDelayMs: 500,
|
|
14710
|
-
maxDelayMs: 8e3
|
|
14711
|
-
};
|
|
14712
|
-
var BaseProvider = class {
|
|
14713
|
-
constructor() {
|
|
14714
|
-
this.retryPolicy = DEFAULT_RETRY;
|
|
14715
|
-
}
|
|
14716
|
-
/**
|
|
14717
|
-
* Helper concrete providers can wrap their fetch with. Retries 429/5xx
|
|
14718
|
-
* with exponential backoff and respects Retry-After if the response
|
|
14719
|
-
* carries one.
|
|
14720
|
-
*/
|
|
14721
|
-
async doFetchWithRetry(execute) {
|
|
14722
|
-
const policy = this.retryPolicy;
|
|
14723
|
-
const maxRetries = Math.max(0, policy.maxRetries ?? DEFAULT_RETRY.maxRetries);
|
|
14724
|
-
const baseDelay = Math.max(0, policy.baseDelayMs ?? DEFAULT_RETRY.baseDelayMs);
|
|
14725
|
-
const maxDelay = Math.max(baseDelay, policy.maxDelayMs ?? DEFAULT_RETRY.maxDelayMs);
|
|
14726
|
-
let lastResp;
|
|
14727
|
-
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
14728
|
-
const res = await execute();
|
|
14729
|
-
const isRetryable = res.status === 429 || res.status >= 500 && res.status < 600;
|
|
14730
|
-
if (!isRetryable) return res;
|
|
14731
|
-
const predicate = policy.shouldRetry;
|
|
14732
|
-
if (predicate && !predicate({ status: res.status }, attempt)) return res;
|
|
14733
|
-
if (attempt === maxRetries) {
|
|
14734
|
-
lastResp = res;
|
|
14735
|
-
break;
|
|
14736
|
-
}
|
|
14737
|
-
const retryAfter = res.headers.get("retry-after");
|
|
14738
|
-
let delay2 = Math.min(maxDelay, baseDelay * Math.pow(2, attempt));
|
|
14739
|
-
if (retryAfter) {
|
|
14740
|
-
const asNumber = Number(retryAfter);
|
|
14741
|
-
if (!Number.isNaN(asNumber)) delay2 = Math.min(maxDelay, Math.max(delay2, asNumber * 1e3));
|
|
14742
|
-
}
|
|
14743
|
-
try {
|
|
14744
|
-
await res.text();
|
|
14745
|
-
} catch {
|
|
14746
|
-
}
|
|
14747
|
-
await new Promise((r) => setTimeout(r, delay2));
|
|
14748
|
-
}
|
|
14749
|
-
return lastResp;
|
|
14750
|
-
}
|
|
14751
|
-
};
|
|
15188
|
+
// src/index.ts
|
|
15189
|
+
init_content();
|
|
14752
15190
|
|
|
14753
15191
|
// src/providers/utils/sse.ts
|
|
14754
15192
|
async function* parseSSEStream(body, signal) {
|
|
@@ -14757,7 +15195,7 @@ async function* parseSSEStream(body, signal) {
|
|
|
14757
15195
|
let buffer = "";
|
|
14758
15196
|
try {
|
|
14759
15197
|
while (true) {
|
|
14760
|
-
if (signal?.aborted) ;
|
|
15198
|
+
if (signal?.aborted) throw abortReason(signal);
|
|
14761
15199
|
const { done, value } = await reader.read();
|
|
14762
15200
|
if (done) break;
|
|
14763
15201
|
buffer += decoder.decode(value, { stream: true });
|
|
@@ -14774,6 +15212,7 @@ async function* parseSSEStream(body, signal) {
|
|
|
14774
15212
|
if (event) yield event;
|
|
14775
15213
|
}
|
|
14776
15214
|
} finally {
|
|
15215
|
+
reader.cancel().catch(() => void 0);
|
|
14777
15216
|
reader.releaseLock();
|
|
14778
15217
|
}
|
|
14779
15218
|
}
|
|
@@ -14991,8 +15430,127 @@ function sanitizeBedrockDocName(name, fallback = "document") {
|
|
|
14991
15430
|
return cleaned || fallback;
|
|
14992
15431
|
}
|
|
14993
15432
|
|
|
15433
|
+
// src/providers/utils/jsonSchemaRefs.ts
|
|
15434
|
+
var DEFINITION_KEYS = ["definitions", "$defs"];
|
|
15435
|
+
function inlineJsonSchemaRefs(schema) {
|
|
15436
|
+
if (!isObject2(schema) || !containsRef(schema)) return schema;
|
|
15437
|
+
const root = structuredClone(schema);
|
|
15438
|
+
const selfReaching = /* @__PURE__ */ new Map();
|
|
15439
|
+
const targetOf = (ref) => {
|
|
15440
|
+
const target = resolvePointer(root, ref);
|
|
15441
|
+
return isObject2(target) ? target : void 0;
|
|
15442
|
+
};
|
|
15443
|
+
const reachesItself = (target) => {
|
|
15444
|
+
const known = selfReaching.get(target);
|
|
15445
|
+
if (known !== void 0) return known;
|
|
15446
|
+
const seen = /* @__PURE__ */ new Set();
|
|
15447
|
+
const walk = (node) => {
|
|
15448
|
+
if (Array.isArray(node)) return node.some(walk);
|
|
15449
|
+
if (!isObject2(node)) return false;
|
|
15450
|
+
if (typeof node.$ref === "string") {
|
|
15451
|
+
const next = targetOf(node.$ref);
|
|
15452
|
+
if (next === target) return true;
|
|
15453
|
+
if (next && !seen.has(next)) {
|
|
15454
|
+
seen.add(next);
|
|
15455
|
+
if (walk(next)) return true;
|
|
15456
|
+
}
|
|
15457
|
+
}
|
|
15458
|
+
return Object.entries(node).some(([key, value]) => key !== "$ref" && walk(value));
|
|
15459
|
+
};
|
|
15460
|
+
const result2 = walk(target);
|
|
15461
|
+
selfReaching.set(target, result2);
|
|
15462
|
+
return result2;
|
|
15463
|
+
};
|
|
15464
|
+
const keptRefs = /* @__PURE__ */ new Set();
|
|
15465
|
+
const expand = (node) => {
|
|
15466
|
+
if (Array.isArray(node)) return node.map(expand);
|
|
15467
|
+
if (!isObject2(node)) return node;
|
|
15468
|
+
if (typeof node.$ref === "string") {
|
|
15469
|
+
const target = targetOf(node.$ref);
|
|
15470
|
+
if (target && !reachesItself(target)) {
|
|
15471
|
+
const { $ref: _inlined, ...siblings } = node;
|
|
15472
|
+
return { ...expand(target), ...expandEntries(siblings) };
|
|
15473
|
+
}
|
|
15474
|
+
keptRefs.add(node.$ref);
|
|
15475
|
+
return expandEntries(node);
|
|
15476
|
+
}
|
|
15477
|
+
return expandEntries(node);
|
|
15478
|
+
};
|
|
15479
|
+
const expandEntries = (node) => {
|
|
15480
|
+
const out = {};
|
|
15481
|
+
for (const [key, value] of Object.entries(node)) out[key] = key === "$ref" ? value : expand(value);
|
|
15482
|
+
return out;
|
|
15483
|
+
};
|
|
15484
|
+
const { definitions: _definitions, $defs: _defs, ...rootBody } = root;
|
|
15485
|
+
const result = typeof root.$ref === "string" ? expand(rootBody) : expandEntries(rootBody);
|
|
15486
|
+
for (const key of DEFINITION_KEYS) delete result[key];
|
|
15487
|
+
for (const key of DEFINITION_KEYS) {
|
|
15488
|
+
const block = root[key];
|
|
15489
|
+
if (!isObject2(block)) continue;
|
|
15490
|
+
const needed = neededEntries(key, block, keptRefs);
|
|
15491
|
+
if (needed.length === 0) continue;
|
|
15492
|
+
const kept = {};
|
|
15493
|
+
for (const name of Object.keys(block)) if (needed.includes(name)) kept[name] = block[name];
|
|
15494
|
+
result[key] = kept;
|
|
15495
|
+
}
|
|
15496
|
+
return result;
|
|
15497
|
+
}
|
|
15498
|
+
function neededEntries(key, block, keptRefs) {
|
|
15499
|
+
const needed = [];
|
|
15500
|
+
const queue = [...keptRefs];
|
|
15501
|
+
while (queue.length > 0) {
|
|
15502
|
+
const ref = queue.shift();
|
|
15503
|
+
const segments = pointerSegments(ref);
|
|
15504
|
+
if (!segments || segments[0] !== key || segments.length < 2) continue;
|
|
15505
|
+
const name = segments[1];
|
|
15506
|
+
if (needed.includes(name) || !(name in block)) continue;
|
|
15507
|
+
needed.push(name);
|
|
15508
|
+
collectRefs(block[name], queue);
|
|
15509
|
+
}
|
|
15510
|
+
return needed;
|
|
15511
|
+
}
|
|
15512
|
+
function collectRefs(node, into) {
|
|
15513
|
+
if (Array.isArray(node)) {
|
|
15514
|
+
node.forEach((child) => collectRefs(child, into));
|
|
15515
|
+
return;
|
|
15516
|
+
}
|
|
15517
|
+
if (!isObject2(node)) return;
|
|
15518
|
+
if (typeof node.$ref === "string") into.push(node.$ref);
|
|
15519
|
+
for (const [k, value] of Object.entries(node)) if (k !== "$ref") collectRefs(value, into);
|
|
15520
|
+
}
|
|
15521
|
+
function containsRef(node) {
|
|
15522
|
+
if (Array.isArray(node)) return node.some(containsRef);
|
|
15523
|
+
if (!isObject2(node)) return false;
|
|
15524
|
+
if (typeof node.$ref === "string") return true;
|
|
15525
|
+
return Object.values(node).some(containsRef);
|
|
15526
|
+
}
|
|
15527
|
+
function pointerSegments(ref) {
|
|
15528
|
+
if (ref === "#") return [];
|
|
15529
|
+
if (!ref.startsWith("#/")) return null;
|
|
15530
|
+
return ref.slice(2).split("/").map((segment) => segment.replace(/~1/g, "/").replace(/~0/g, "~"));
|
|
15531
|
+
}
|
|
15532
|
+
function resolvePointer(document, ref) {
|
|
15533
|
+
const segments = pointerSegments(ref);
|
|
15534
|
+
if (!segments) return void 0;
|
|
15535
|
+
let current = document;
|
|
15536
|
+
for (const segment of segments) {
|
|
15537
|
+
if (Array.isArray(current)) {
|
|
15538
|
+
if (!/^\d+$/.test(segment)) return void 0;
|
|
15539
|
+
current = current[Number(segment)];
|
|
15540
|
+
} else if (isObject2(current) && Object.prototype.hasOwnProperty.call(current, segment)) {
|
|
15541
|
+
current = current[segment];
|
|
15542
|
+
} else {
|
|
15543
|
+
return void 0;
|
|
15544
|
+
}
|
|
15545
|
+
}
|
|
15546
|
+
return current;
|
|
15547
|
+
}
|
|
15548
|
+
function isObject2(value) {
|
|
15549
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15550
|
+
}
|
|
15551
|
+
|
|
14994
15552
|
// src/providers/openai.ts
|
|
14995
|
-
var OpenAIProvider = class extends BaseProvider {
|
|
15553
|
+
var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
14996
15554
|
constructor(config) {
|
|
14997
15555
|
super();
|
|
14998
15556
|
this.providerName = "openai";
|
|
@@ -15004,8 +15562,21 @@ var OpenAIProvider = class extends BaseProvider {
|
|
|
15004
15562
|
...config.organization ? { "OpenAI-Organization": config.organization } : {}
|
|
15005
15563
|
};
|
|
15006
15564
|
this.responsesApi = config.responsesApi ?? "auto";
|
|
15565
|
+
const ownInstance = new.target === _OpenAIProvider;
|
|
15566
|
+
this.responsesApiModels = ownInstance ? [...config.responsesApiModels ?? []] : [];
|
|
15567
|
+
this.responsesStreaming = ownInstance && config.responsesStreaming === true;
|
|
15007
15568
|
if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
|
|
15008
15569
|
}
|
|
15570
|
+
/** True when the caller listed this request's model in `responsesApiModels`. */
|
|
15571
|
+
isResponsesApiModel(request) {
|
|
15572
|
+
if (this.responsesApiModels.length === 0) return false;
|
|
15573
|
+
const model = request.model || this.defaultModel;
|
|
15574
|
+
return this.responsesApiModels.some((entry) => {
|
|
15575
|
+
if (typeof entry === "string") return entry === model;
|
|
15576
|
+
entry.lastIndex = 0;
|
|
15577
|
+
return entry.test(model);
|
|
15578
|
+
});
|
|
15579
|
+
}
|
|
15009
15580
|
/** True when this request should go to the Responses API rather than Chat
|
|
15010
15581
|
* Completions — which exposes `reasoning.effort` and reasoning summaries that
|
|
15011
15582
|
* Chat Completions silently drops.
|
|
@@ -15014,10 +15585,14 @@ var OpenAIProvider = class extends BaseProvider {
|
|
|
15014
15585
|
* carries a reasoning config AND the model name looks like an o-series/gpt-5
|
|
15015
15586
|
* model. `never`/`always` let a caller state the answer instead, because the
|
|
15016
15587
|
* name check is a guess and the two APIs differ in far more than reasoning —
|
|
15017
|
-
* see `responsesApi` in OpenAIProviderConfig.
|
|
15588
|
+
* see `responsesApi` in OpenAIProviderConfig.
|
|
15589
|
+
*
|
|
15590
|
+
* A model listed in `responsesApiModels` is the caller stating the answer
|
|
15591
|
+
* for that model alone; `never` still overrides it. */
|
|
15018
15592
|
useResponsesApi(request) {
|
|
15019
15593
|
if (this.responsesApi === "never") return false;
|
|
15020
15594
|
if (this.responsesApi === "always") return true;
|
|
15595
|
+
if (this.isResponsesApiModel(request)) return true;
|
|
15021
15596
|
if (!request.reasoning) return false;
|
|
15022
15597
|
return isReasoningModel(request.model || this.defaultModel);
|
|
15023
15598
|
}
|
|
@@ -15026,12 +15601,16 @@ var OpenAIProvider = class extends BaseProvider {
|
|
|
15026
15601
|
return this.completeResponses(request);
|
|
15027
15602
|
}
|
|
15028
15603
|
const body = this.buildRequestBody(request, false);
|
|
15029
|
-
const res = await this.doFetch(body);
|
|
15604
|
+
const res = await this.doFetch(body, request.signal);
|
|
15030
15605
|
const json = await res.json();
|
|
15031
15606
|
return this.parseResponse(json);
|
|
15032
15607
|
}
|
|
15033
15608
|
async *completeStream(request) {
|
|
15034
15609
|
if (this.useResponsesApi(request)) {
|
|
15610
|
+
if (this.responsesStreaming && this.isResponsesApiModel(request)) {
|
|
15611
|
+
yield* this.streamResponses(request);
|
|
15612
|
+
return;
|
|
15613
|
+
}
|
|
15035
15614
|
const response = await this.completeResponses(request);
|
|
15036
15615
|
yield {
|
|
15037
15616
|
id: response.id,
|
|
@@ -15047,13 +15626,13 @@ var OpenAIProvider = class extends BaseProvider {
|
|
|
15047
15626
|
return;
|
|
15048
15627
|
}
|
|
15049
15628
|
const body = this.buildRequestBody(request, true);
|
|
15050
|
-
const res = await this.doFetch(body);
|
|
15629
|
+
const res = await this.doFetch(body, request.signal);
|
|
15051
15630
|
if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
|
|
15052
15631
|
let id = "";
|
|
15053
15632
|
let model = "";
|
|
15054
15633
|
const toolCallBuffers = /* @__PURE__ */ new Map();
|
|
15055
15634
|
let usage;
|
|
15056
|
-
for await (const event of parseSSEStream(res.body)) {
|
|
15635
|
+
for await (const event of parseSSEStream(res.body, request.signal)) {
|
|
15057
15636
|
if (event.data === "[DONE]") break;
|
|
15058
15637
|
let chunk;
|
|
15059
15638
|
try {
|
|
@@ -15147,10 +15726,101 @@ var OpenAIProvider = class extends BaseProvider {
|
|
|
15147
15726
|
// ─── Responses API (reasoning models) ──────────────────────────────────────
|
|
15148
15727
|
async completeResponses(request) {
|
|
15149
15728
|
const body = this.buildResponsesBody(request);
|
|
15150
|
-
|
|
15729
|
+
if (this.isResponsesApiModel(request)) adaptChatExtrasForResponses(body, request.extra);
|
|
15730
|
+
const res = await this.responsesFetch(body, request.signal);
|
|
15151
15731
|
const json = await res.json();
|
|
15152
15732
|
return this.parseResponsesResponse(json, request.model || this.defaultModel);
|
|
15153
15733
|
}
|
|
15734
|
+
/** Real Responses SSE streaming, for models opted in through
|
|
15735
|
+
* `responsesApiModels` with `responsesStreaming` on. Emits the same chunk
|
|
15736
|
+
* shapes as the Chat Completions stream: text deltas as they arrive, a tool
|
|
15737
|
+
* call's id + name when it opens and its argument fragments under that id,
|
|
15738
|
+
* then one final chunk with usage, finish reason and any reasoning summary
|
|
15739
|
+
* (taken from the completed response, exactly as the non-streaming parse
|
|
15740
|
+
* reads it). */
|
|
15741
|
+
async *streamResponses(request) {
|
|
15742
|
+
const modelId = request.model || this.defaultModel;
|
|
15743
|
+
const body = this.buildResponsesBody(request);
|
|
15744
|
+
adaptChatExtrasForResponses(body, request.extra);
|
|
15745
|
+
body.stream = true;
|
|
15746
|
+
const res = await this.responsesFetch(body, request.signal);
|
|
15747
|
+
if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
|
|
15748
|
+
let id = "";
|
|
15749
|
+
let model = modelId;
|
|
15750
|
+
const calls = /* @__PURE__ */ new Map();
|
|
15751
|
+
let final;
|
|
15752
|
+
for await (const event of parseSSEStream(res.body, request.signal)) {
|
|
15753
|
+
if (event.data === "[DONE]") break;
|
|
15754
|
+
let data;
|
|
15755
|
+
try {
|
|
15756
|
+
data = JSON.parse(event.data);
|
|
15757
|
+
} catch {
|
|
15758
|
+
continue;
|
|
15759
|
+
}
|
|
15760
|
+
switch (data.type ?? event.event) {
|
|
15761
|
+
case "response.created":
|
|
15762
|
+
case "response.in_progress":
|
|
15763
|
+
id = data.response?.id ?? id;
|
|
15764
|
+
model = data.response?.model ?? model;
|
|
15765
|
+
break;
|
|
15766
|
+
case "response.output_text.delta":
|
|
15767
|
+
if (data.delta) yield { id, model, delta: { content: data.delta } };
|
|
15768
|
+
break;
|
|
15769
|
+
case "response.output_item.added": {
|
|
15770
|
+
const item = data.item;
|
|
15771
|
+
if (item?.type !== "function_call") break;
|
|
15772
|
+
const call = { callId: item.call_id ?? item.id ?? "", name: item.name ?? "", arguments: item.arguments ?? "" };
|
|
15773
|
+
calls.set(item.id ?? call.callId, call);
|
|
15774
|
+
yield { id, model, delta: { toolCalls: [{ id: call.callId, name: call.name, arguments: call.arguments }] } };
|
|
15775
|
+
break;
|
|
15776
|
+
}
|
|
15777
|
+
case "response.function_call_arguments.delta": {
|
|
15778
|
+
const call = calls.get(data.item_id);
|
|
15779
|
+
if (!call || !data.delta) break;
|
|
15780
|
+
call.arguments += data.delta;
|
|
15781
|
+
yield { id, model, delta: { toolCalls: [{ id: call.callId, arguments: data.delta }] } };
|
|
15782
|
+
break;
|
|
15783
|
+
}
|
|
15784
|
+
case "response.output_item.done": {
|
|
15785
|
+
const item = data.item;
|
|
15786
|
+
if (item?.type !== "function_call") break;
|
|
15787
|
+
const full = typeof item.arguments === "string" ? item.arguments : "";
|
|
15788
|
+
const call = calls.get(item.id ?? item.call_id);
|
|
15789
|
+
if (!call) {
|
|
15790
|
+
const added = { callId: item.call_id ?? item.id ?? "", name: item.name ?? "", arguments: full };
|
|
15791
|
+
calls.set(item.id ?? added.callId, added);
|
|
15792
|
+
yield { id, model, delta: { toolCalls: [{ id: added.callId, name: added.name, arguments: full }] } };
|
|
15793
|
+
} else if (full.length > call.arguments.length && full.startsWith(call.arguments)) {
|
|
15794
|
+
const rest = full.slice(call.arguments.length);
|
|
15795
|
+
call.arguments = full;
|
|
15796
|
+
yield { id, model, delta: { toolCalls: [{ id: call.callId, arguments: rest }] } };
|
|
15797
|
+
}
|
|
15798
|
+
break;
|
|
15799
|
+
}
|
|
15800
|
+
case "response.completed":
|
|
15801
|
+
case "response.incomplete":
|
|
15802
|
+
final = this.parseResponsesResponse(data.response ?? {}, modelId);
|
|
15803
|
+
break;
|
|
15804
|
+
case "response.failed":
|
|
15805
|
+
case "error": {
|
|
15806
|
+
const err = data.response?.error ?? data.error ?? data;
|
|
15807
|
+
throw new ProviderError(
|
|
15808
|
+
`OpenAI Responses API stream error: ${err?.message ?? "unknown error"}`,
|
|
15809
|
+
this.providerName,
|
|
15810
|
+
void 0,
|
|
15811
|
+
data
|
|
15812
|
+
);
|
|
15813
|
+
}
|
|
15814
|
+
}
|
|
15815
|
+
}
|
|
15816
|
+
yield {
|
|
15817
|
+
id: final?.id || id,
|
|
15818
|
+
model: final?.model || model,
|
|
15819
|
+
delta: final?.reasoning ? { reasoning: final.reasoning } : {},
|
|
15820
|
+
usage: final?.usage,
|
|
15821
|
+
finishReason: final?.finishReason ?? (calls.size > 0 ? "tool_calls" : "stop")
|
|
15822
|
+
};
|
|
15823
|
+
}
|
|
15154
15824
|
buildResponsesBody(request) {
|
|
15155
15825
|
const body = {
|
|
15156
15826
|
model: request.model || this.defaultModel,
|
|
@@ -15180,7 +15850,7 @@ var OpenAIProvider = class extends BaseProvider {
|
|
|
15180
15850
|
format: {
|
|
15181
15851
|
type: "json_schema",
|
|
15182
15852
|
name: request.responseFormat.name ?? "response",
|
|
15183
|
-
schema: request.responseFormat.schema,
|
|
15853
|
+
schema: inlineJsonSchemaRefs(request.responseFormat.schema),
|
|
15184
15854
|
strict: true
|
|
15185
15855
|
}
|
|
15186
15856
|
};
|
|
@@ -15247,7 +15917,7 @@ var OpenAIProvider = class extends BaseProvider {
|
|
|
15247
15917
|
});
|
|
15248
15918
|
return { role, content };
|
|
15249
15919
|
}
|
|
15250
|
-
async responsesFetch(body) {
|
|
15920
|
+
async responsesFetch(body, signal) {
|
|
15251
15921
|
body.input = expandResponsesInput(body.input);
|
|
15252
15922
|
const url = `${this.baseURL}/responses`;
|
|
15253
15923
|
const headers = {
|
|
@@ -15256,7 +15926,7 @@ var OpenAIProvider = class extends BaseProvider {
|
|
|
15256
15926
|
...this.defaultHeaders
|
|
15257
15927
|
};
|
|
15258
15928
|
const payload = JSON.stringify(body);
|
|
15259
|
-
const res = await this.doFetchWithRetry(() => fetch(url, { method: "POST", headers, body: payload }));
|
|
15929
|
+
const res = await this.doFetchWithRetry(() => fetch(url, { method: "POST", headers, body: payload, signal }), signal);
|
|
15260
15930
|
if (!res.ok) {
|
|
15261
15931
|
const text = await res.text().catch(() => "");
|
|
15262
15932
|
throw new ProviderError(
|
|
@@ -15377,7 +16047,7 @@ var OpenAIProvider = class extends BaseProvider {
|
|
|
15377
16047
|
}
|
|
15378
16048
|
return { type: "function", function: fn };
|
|
15379
16049
|
}
|
|
15380
|
-
async doFetch(body) {
|
|
16050
|
+
async doFetch(body, signal) {
|
|
15381
16051
|
const url = `${this.baseURL}/chat/completions`;
|
|
15382
16052
|
const headers = {
|
|
15383
16053
|
"Content-Type": "application/json",
|
|
@@ -15385,7 +16055,7 @@ var OpenAIProvider = class extends BaseProvider {
|
|
|
15385
16055
|
...this.defaultHeaders
|
|
15386
16056
|
};
|
|
15387
16057
|
const payload = JSON.stringify(body);
|
|
15388
|
-
const res = await this.doFetchWithRetry(() => fetch(url, { method: "POST", headers, body: payload }));
|
|
16058
|
+
const res = await this.doFetchWithRetry(() => fetch(url, { method: "POST", headers, body: payload, signal }), signal);
|
|
15389
16059
|
if (!res.ok) {
|
|
15390
16060
|
const text = await res.text().catch(() => "");
|
|
15391
16061
|
throw new ProviderError(
|
|
@@ -15435,6 +16105,48 @@ function isReasoningModel(model) {
|
|
|
15435
16105
|
const m = model.toLowerCase();
|
|
15436
16106
|
return /(^|[/_-])o[0-9]/.test(m) || m.startsWith("o1") || m.startsWith("o3") || m.startsWith("o4") || m.includes("gpt-5") || m.includes("gpt5");
|
|
15437
16107
|
}
|
|
16108
|
+
function adaptChatExtrasForResponses(body, extra) {
|
|
16109
|
+
const native = extra ?? {};
|
|
16110
|
+
if ("reasoning_effort" in body) {
|
|
16111
|
+
const effort = body.reasoning_effort;
|
|
16112
|
+
delete body.reasoning_effort;
|
|
16113
|
+
if (effort != null) {
|
|
16114
|
+
const reasoning = body.reasoning && typeof body.reasoning === "object" ? body.reasoning : {};
|
|
16115
|
+
if (reasoning.effort == null) body.reasoning = { ...reasoning, effort };
|
|
16116
|
+
}
|
|
16117
|
+
}
|
|
16118
|
+
for (const key of ["max_tokens", "max_completion_tokens"]) {
|
|
16119
|
+
if (!(key in body)) continue;
|
|
16120
|
+
const value = body[key];
|
|
16121
|
+
delete body[key];
|
|
16122
|
+
if (value != null && !("max_output_tokens" in native)) body.max_output_tokens = value;
|
|
16123
|
+
}
|
|
16124
|
+
if ("response_format" in body) {
|
|
16125
|
+
const format = toResponsesTextFormat(body.response_format);
|
|
16126
|
+
delete body.response_format;
|
|
16127
|
+
if (format && !("text" in native)) body.text = { ...body.text, format };
|
|
16128
|
+
}
|
|
16129
|
+
if (body.stream_options && typeof body.stream_options === "object" && "include_usage" in body.stream_options) {
|
|
16130
|
+
const { include_usage: _dropped, ...rest } = body.stream_options;
|
|
16131
|
+
if (Object.keys(rest).length > 0) body.stream_options = rest;
|
|
16132
|
+
else delete body.stream_options;
|
|
16133
|
+
}
|
|
16134
|
+
}
|
|
16135
|
+
function toResponsesTextFormat(rf) {
|
|
16136
|
+
if (!rf || typeof rf !== "object") return void 0;
|
|
16137
|
+
if (rf.type === "json_schema") {
|
|
16138
|
+
const js = rf.json_schema ?? {};
|
|
16139
|
+
return {
|
|
16140
|
+
type: "json_schema",
|
|
16141
|
+
name: js.name ?? "response",
|
|
16142
|
+
schema: inlineJsonSchemaRefs(js.schema),
|
|
16143
|
+
...js.description != null ? { description: js.description } : {},
|
|
16144
|
+
...js.strict != null ? { strict: js.strict } : {}
|
|
16145
|
+
};
|
|
16146
|
+
}
|
|
16147
|
+
if (rf.type === "json_object" || rf.type === "text") return { type: rf.type };
|
|
16148
|
+
return void 0;
|
|
16149
|
+
}
|
|
15438
16150
|
function expandResponsesInput(input) {
|
|
15439
16151
|
const out = [];
|
|
15440
16152
|
for (const item of input) {
|
|
@@ -15479,13 +16191,13 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
15479
16191
|
}
|
|
15480
16192
|
async complete(request) {
|
|
15481
16193
|
const body = this.buildRequestBody(request, false);
|
|
15482
|
-
const res = await this.doFetch(body);
|
|
16194
|
+
const res = await this.doFetch(body, request.signal);
|
|
15483
16195
|
const json = await res.json();
|
|
15484
16196
|
return this.parseResponse(json);
|
|
15485
16197
|
}
|
|
15486
16198
|
async *completeStream(request) {
|
|
15487
16199
|
const body = this.buildRequestBody(request, true);
|
|
15488
|
-
const res = await this.doFetch(body);
|
|
16200
|
+
const res = await this.doFetch(body, request.signal);
|
|
15489
16201
|
if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
|
|
15490
16202
|
let id = "";
|
|
15491
16203
|
let model = "";
|
|
@@ -15495,7 +16207,7 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
15495
16207
|
let cacheCreationInputTokens = 0;
|
|
15496
16208
|
const currentToolCalls = /* @__PURE__ */ new Map();
|
|
15497
16209
|
const reasoningBlocks = /* @__PURE__ */ new Map();
|
|
15498
|
-
for await (const event of parseSSEStream(res.body)) {
|
|
16210
|
+
for await (const event of parseSSEStream(res.body, request.signal)) {
|
|
15499
16211
|
let data;
|
|
15500
16212
|
try {
|
|
15501
16213
|
data = JSON.parse(event.data);
|
|
@@ -15775,7 +16487,7 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
15775
16487
|
input_schema: t.parameters
|
|
15776
16488
|
};
|
|
15777
16489
|
}
|
|
15778
|
-
async doFetch(body) {
|
|
16490
|
+
async doFetch(body, signal) {
|
|
15779
16491
|
const url = `${this.baseURL}/v1/messages`;
|
|
15780
16492
|
const headers = {
|
|
15781
16493
|
"Content-Type": "application/json",
|
|
@@ -15784,7 +16496,7 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
15784
16496
|
...this.defaultHeaders
|
|
15785
16497
|
};
|
|
15786
16498
|
const payload = JSON.stringify(body);
|
|
15787
|
-
const res = await this.doFetchWithRetry(() => fetch(url, { method: "POST", headers, body: payload }));
|
|
16499
|
+
const res = await this.doFetchWithRetry(() => fetch(url, { method: "POST", headers, body: payload, signal }), signal);
|
|
15788
16500
|
if (!res.ok) {
|
|
15789
16501
|
const text = await res.text().catch(() => "");
|
|
15790
16502
|
throw new ProviderError(
|
|
@@ -15894,7 +16606,7 @@ var AzureProvider = class extends OpenAIProvider {
|
|
|
15894
16606
|
this.deploymentName = config.deploymentName;
|
|
15895
16607
|
this.azureApiKey = config.apiKey;
|
|
15896
16608
|
}
|
|
15897
|
-
async doFetch(body) {
|
|
16609
|
+
async doFetch(body, signal) {
|
|
15898
16610
|
const deployment = this.deploymentName ?? body.model;
|
|
15899
16611
|
if (!deployment) {
|
|
15900
16612
|
throw new ProviderError("Azure requires a deploymentName or model", this.providerName);
|
|
@@ -15908,7 +16620,8 @@ var AzureProvider = class extends OpenAIProvider {
|
|
|
15908
16620
|
"api-key": this.azureApiKey,
|
|
15909
16621
|
...this.defaultHeaders
|
|
15910
16622
|
},
|
|
15911
|
-
body: JSON.stringify(bodyWithoutModel)
|
|
16623
|
+
body: JSON.stringify(bodyWithoutModel),
|
|
16624
|
+
signal
|
|
15912
16625
|
});
|
|
15913
16626
|
if (!res.ok) {
|
|
15914
16627
|
const text = await res.text().catch(() => "");
|
|
@@ -15924,7 +16637,7 @@ var AzureProvider = class extends OpenAIProvider {
|
|
|
15924
16637
|
/** Azure exposes the Responses API at /openai/responses with api-key auth.
|
|
15925
16638
|
* Reasoning summaries require a preview api-version; callers can override via
|
|
15926
16639
|
* the `apiVersion` config. */
|
|
15927
|
-
async responsesFetch(body) {
|
|
16640
|
+
async responsesFetch(body, signal) {
|
|
15928
16641
|
body.input = expandAzureResponsesInput(body.input);
|
|
15929
16642
|
const deployment = this.deploymentName ?? body.model;
|
|
15930
16643
|
if (!deployment) {
|
|
@@ -15939,7 +16652,8 @@ var AzureProvider = class extends OpenAIProvider {
|
|
|
15939
16652
|
"api-key": this.azureApiKey,
|
|
15940
16653
|
...this.defaultHeaders
|
|
15941
16654
|
},
|
|
15942
|
-
body: payload
|
|
16655
|
+
body: payload,
|
|
16656
|
+
signal
|
|
15943
16657
|
});
|
|
15944
16658
|
if (!res.ok) {
|
|
15945
16659
|
const text = await res.text().catch(() => "");
|
|
@@ -16007,7 +16721,7 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16007
16721
|
async complete(request) {
|
|
16008
16722
|
const modelId = request.model || this.defaultModel;
|
|
16009
16723
|
const body = this.buildConverseBody(request);
|
|
16010
|
-
const json = await this.doFetch(modelId, body);
|
|
16724
|
+
const json = await this.doFetch(modelId, body, request.signal);
|
|
16011
16725
|
return this.parseResponse(json, modelId);
|
|
16012
16726
|
}
|
|
16013
16727
|
async *completeStream(request) {
|
|
@@ -16184,7 +16898,7 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16184
16898
|
}
|
|
16185
16899
|
};
|
|
16186
16900
|
}
|
|
16187
|
-
async doFetch(modelId, body) {
|
|
16901
|
+
async doFetch(modelId, body, signal) {
|
|
16188
16902
|
const host = `bedrock-runtime.${this.region}.amazonaws.com`;
|
|
16189
16903
|
const url = `https://${host}/model/${encodeURIComponent(modelId)}/converse`;
|
|
16190
16904
|
const bodyStr = JSON.stringify(body);
|
|
@@ -16202,8 +16916,8 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16202
16916
|
service: "bedrock",
|
|
16203
16917
|
credentials: this.credentials
|
|
16204
16918
|
});
|
|
16205
|
-
return fetch(url, { method: "POST", headers, body: bodyStr });
|
|
16206
|
-
});
|
|
16919
|
+
return fetch(url, { method: "POST", headers, body: bodyStr, signal });
|
|
16920
|
+
}, signal);
|
|
16207
16921
|
if (!res.ok) {
|
|
16208
16922
|
const text = await res.text().catch(() => "");
|
|
16209
16923
|
throw new ProviderError(
|
|
@@ -16336,7 +17050,7 @@ var VertexProvider = class extends BaseProvider {
|
|
|
16336
17050
|
const modelId = request.model || this.defaultModel;
|
|
16337
17051
|
const body = this.buildGeminiBody(request);
|
|
16338
17052
|
const url = this.buildUrl(modelId, false);
|
|
16339
|
-
const res = await this.doFetch(url, body);
|
|
17053
|
+
const res = await this.doFetch(url, body, request.signal);
|
|
16340
17054
|
const json = await res.json();
|
|
16341
17055
|
return this.parseResponse(json, modelId);
|
|
16342
17056
|
}
|
|
@@ -16344,11 +17058,11 @@ var VertexProvider = class extends BaseProvider {
|
|
|
16344
17058
|
const modelId = request.model || this.defaultModel;
|
|
16345
17059
|
const body = this.buildGeminiBody(request);
|
|
16346
17060
|
const url = this.buildUrl(modelId, true);
|
|
16347
|
-
const res = await this.doFetch(url, body);
|
|
17061
|
+
const res = await this.doFetch(url, body, request.signal);
|
|
16348
17062
|
if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
|
|
16349
17063
|
const contentType = res.headers.get("content-type") ?? "";
|
|
16350
17064
|
if (contentType.includes("text/event-stream")) {
|
|
16351
|
-
for await (const event of parseSSEStream(res.body)) {
|
|
17065
|
+
for await (const event of parseSSEStream(res.body, request.signal)) {
|
|
16352
17066
|
if (event.data === "[DONE]") break;
|
|
16353
17067
|
let chunk;
|
|
16354
17068
|
try {
|
|
@@ -16390,6 +17104,7 @@ var VertexProvider = class extends BaseProvider {
|
|
|
16390
17104
|
}
|
|
16391
17105
|
}
|
|
16392
17106
|
} finally {
|
|
17107
|
+
reader.cancel().catch(() => void 0);
|
|
16393
17108
|
reader.releaseLock();
|
|
16394
17109
|
}
|
|
16395
17110
|
}
|
|
@@ -16601,7 +17316,7 @@ var VertexProvider = class extends BaseProvider {
|
|
|
16601
17316
|
const tokenJson = await tokenRes.json();
|
|
16602
17317
|
return tokenJson.access_token;
|
|
16603
17318
|
}
|
|
16604
|
-
async doFetch(url, body) {
|
|
17319
|
+
async doFetch(url, body, signal) {
|
|
16605
17320
|
const token = await this.getAccessToken();
|
|
16606
17321
|
const res = await fetch(url, {
|
|
16607
17322
|
method: "POST",
|
|
@@ -16610,7 +17325,8 @@ var VertexProvider = class extends BaseProvider {
|
|
|
16610
17325
|
Authorization: `Bearer ${token}`,
|
|
16611
17326
|
...this.defaultHeaders
|
|
16612
17327
|
},
|
|
16613
|
-
body: JSON.stringify(body)
|
|
17328
|
+
body: JSON.stringify(body),
|
|
17329
|
+
signal
|
|
16614
17330
|
});
|
|
16615
17331
|
if (!res.ok) {
|
|
16616
17332
|
const text = await res.text().catch(() => "");
|
|
@@ -16749,6 +17465,8 @@ function createProvider(config) {
|
|
|
16749
17465
|
return new BedrockProvider(config);
|
|
16750
17466
|
case "vertex":
|
|
16751
17467
|
return new VertexProvider(config);
|
|
17468
|
+
case "jev":
|
|
17469
|
+
return new JevProvider(config);
|
|
16752
17470
|
default:
|
|
16753
17471
|
throw new Error(`Unknown provider: ${config.provider}`);
|
|
16754
17472
|
}
|
|
@@ -16776,6 +17494,7 @@ exports.HOOK_CONTRACT_VERSION = HOOK_CONTRACT_VERSION;
|
|
|
16776
17494
|
exports.HOOK_NAMES = HOOK_NAMES;
|
|
16777
17495
|
exports.HookTimeoutError = HookTimeoutError;
|
|
16778
17496
|
exports.InMemoryMemoryStore = InMemoryMemoryStore;
|
|
17497
|
+
exports.JevProvider = JevProvider;
|
|
16779
17498
|
exports.NativeJsonSchemaStrategy = NativeJsonSchemaStrategy;
|
|
16780
17499
|
exports.OpenAICompatibleProvider = OpenAICompatibleProvider;
|
|
16781
17500
|
exports.OpenAIProvider = OpenAIProvider;
|
|
@@ -16815,6 +17534,7 @@ exports.compressLogOutput = compressLogOutput;
|
|
|
16815
17534
|
exports.compressSearchOutput = compressSearchOutput;
|
|
16816
17535
|
exports.compressTextOutput = compressTextOutput;
|
|
16817
17536
|
exports.compressToolOutput = compressToolOutput;
|
|
17537
|
+
exports.contentPartToText = contentPartToText;
|
|
16818
17538
|
exports.contentToString = contentToString;
|
|
16819
17539
|
exports.conversationHistory = conversationHistory;
|
|
16820
17540
|
exports.countApproxTokens = countApproxTokens;
|
|
@@ -16857,6 +17577,7 @@ exports.dedupeToolsByName = dedupeToolsByName;
|
|
|
16857
17577
|
exports.defaultTokenCounter = defaultTokenCounter;
|
|
16858
17578
|
exports.defineHook = defineHook;
|
|
16859
17579
|
exports.definePlugin = definePlugin;
|
|
17580
|
+
exports.describeContentPart = describeContentPart;
|
|
16860
17581
|
exports.detectLanguage = detectLanguage;
|
|
16861
17582
|
exports.detectTextFormat = detectTextFormat;
|
|
16862
17583
|
exports.detectVolatileContent = detectVolatileContent;
|
|
@@ -16865,7 +17586,7 @@ exports.digestToolInputValue = digestToolInputValue;
|
|
|
16865
17586
|
exports.emptyUsage = emptyUsage;
|
|
16866
17587
|
exports.evaluateGuardrails = evaluateGuardrails;
|
|
16867
17588
|
exports.extractLatestUserQuery = extractLatestUserQuery;
|
|
16868
|
-
exports.extractMessageText =
|
|
17589
|
+
exports.extractMessageText = extractMessageText;
|
|
16869
17590
|
exports.fileCheckpointStore = fileCheckpointStore;
|
|
16870
17591
|
exports.fileSink = fileSink;
|
|
16871
17592
|
exports.findSubagent = findSubagent;
|
|
@@ -16879,6 +17600,7 @@ exports.getModelCapabilities = getModelCapabilities;
|
|
|
16879
17600
|
exports.getNestedValue = getNestedValue;
|
|
16880
17601
|
exports.getResolvedSmartConfig = getResolvedSmartConfig;
|
|
16881
17602
|
exports.getTokenCounter = getTokenCounter;
|
|
17603
|
+
exports.hasMediaPart = hasMediaPart;
|
|
16882
17604
|
exports.hasToolResponseRecoveryReference = hasToolResponseRecoveryReference;
|
|
16883
17605
|
exports.httpGuardrail = httpGuardrail;
|
|
16884
17606
|
exports.httpSink = httpSink;
|
|
@@ -16898,6 +17620,7 @@ exports.loadSkillsFromDisk = loadSkillsFromDisk;
|
|
|
16898
17620
|
exports.mapConsoleHookVerdict = mapConsoleHookVerdict;
|
|
16899
17621
|
exports.mapTextParts = mapTextParts;
|
|
16900
17622
|
exports.mcp = mcp;
|
|
17623
|
+
exports.mediaKindOf = mediaKindOf;
|
|
16901
17624
|
exports.mediaPolicy = mediaPolicy;
|
|
16902
17625
|
exports.normalizeSmartAgentOptions = normalizeSmartAgentOptions;
|
|
16903
17626
|
exports.normalizeVerdicts = normalizeVerdicts;
|