@cognipeer/agent-sdk 0.10.5 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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 extractMessageText(m) {
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(extractMessageText).join("\n");
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 response = await lcModel.invoke(lcMessages, options);
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 streamResult = lcModel.stream(lcMessages, options);
633
- const stream = typeof streamResult?.then === "function" ? await streamResult : streamResult;
634
- for await (const chunk of stream) {
635
- yield chunk;
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
- if (typeof sanitized.text === "string" && Object.keys(sanitized).length === 1) {
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
  }
@@ -2060,6 +2441,15 @@ function estimatePayloadBytes(value) {
2060
2441
  }
2061
2442
  }
2062
2443
  }
2444
+ function toMessageUsage(u) {
2445
+ return {
2446
+ prompt_tokens: u.inputTokens,
2447
+ completion_tokens: u.outputTokens,
2448
+ total_tokens: u.totalTokens,
2449
+ prompt_tokens_details: { cached_tokens: u.cachedInputTokens, cache_write_tokens: u.cachedWriteTokens },
2450
+ completion_tokens_details: { reasoning_tokens: u.reasoningTokens }
2451
+ };
2452
+ }
2063
2453
  function fromNativeProvider(provider, options) {
2064
2454
  let boundTools = options?.__tools;
2065
2455
  const modelName = options?.model ?? provider.defaultModel ?? provider.providerName;
@@ -2067,50 +2457,87 @@ function fromNativeProvider(provider, options) {
2067
2457
  modelName,
2068
2458
  capabilities: resolveCapabilities(provider.providerName),
2069
2459
  invoke: async (messages, _invokeOptions) => {
2070
- const request = buildRequest(messages, boundTools, options, _invokeOptions);
2071
- const response = await provider.complete(request);
2072
- return toBaseChatMessage(response);
2460
+ const link = linkAbortSignal(_invokeOptions);
2461
+ try {
2462
+ let request = buildRequest(messages, boundTools, options, _invokeOptions);
2463
+ if (link.signal) request.signal = link.signal;
2464
+ request = await applyTransform(request);
2465
+ const response = await provider.complete(request);
2466
+ return toBaseChatMessage(response);
2467
+ } finally {
2468
+ link.dispose();
2469
+ }
2073
2470
  },
2074
2471
  stream: async function* (messages, _invokeOptions) {
2075
- const request = buildRequest(messages, boundTools, options, _invokeOptions);
2076
- request.stream = true;
2077
- let fullContent = "";
2078
- let allToolCalls = [];
2079
- let lastUsage;
2080
- let reasoningBlocks;
2081
- const toolCallBuffers = /* @__PURE__ */ new Map();
2082
- for await (const chunk of provider.completeStream(request)) {
2083
- if (chunk.delta.content) {
2084
- fullContent += chunk.delta.content;
2085
- yield chunk.delta.content;
2086
- }
2087
- if (chunk.delta.reasoning?.blocks?.length) {
2088
- reasoningBlocks = chunk.delta.reasoning.blocks;
2089
- }
2090
- if (chunk.delta.toolCalls) {
2091
- for (const tc of chunk.delta.toolCalls) {
2092
- if (tc.id) {
2093
- const existing = toolCallBuffers.get(tc.id);
2094
- if (existing) {
2095
- if (tc.arguments) existing.arguments += tc.arguments;
2096
- } else {
2097
- toolCallBuffers.set(tc.id, {
2098
- id: tc.id,
2099
- name: tc.name ?? "",
2100
- arguments: tc.arguments ?? ""
2101
- });
2472
+ const link = linkAbortSignal(_invokeOptions);
2473
+ try {
2474
+ let request = buildRequest(messages, boundTools, options, _invokeOptions);
2475
+ request.stream = true;
2476
+ if (link.signal) request.signal = link.signal;
2477
+ request = await applyTransform(request);
2478
+ let fullContent = "";
2479
+ let allToolCalls = [];
2480
+ let lastUsage;
2481
+ let reasoningBlocks;
2482
+ let reasoningText = "";
2483
+ let finishReason;
2484
+ let responseModel;
2485
+ const toolCallBuffers = /* @__PURE__ */ new Map();
2486
+ for await (const chunk of provider.completeStream(request)) {
2487
+ if (chunk.delta.content) {
2488
+ fullContent += chunk.delta.content;
2489
+ yield chunk.delta.content;
2490
+ }
2491
+ if (chunk.model) responseModel = chunk.model;
2492
+ if (chunk.finishReason) finishReason = chunk.finishReason;
2493
+ if (chunk.delta.reasoning?.blocks?.length) {
2494
+ reasoningBlocks = chunk.delta.reasoning.blocks;
2495
+ }
2496
+ const reasoningDelta = chunk.delta.reasoning?.summary;
2497
+ if (reasoningDelta) {
2498
+ reasoningText += reasoningDelta;
2499
+ yield { type: "reasoning", reasoning_content: reasoningDelta };
2500
+ }
2501
+ if (chunk.delta.toolCalls) {
2502
+ for (const tc of chunk.delta.toolCalls) {
2503
+ if (tc.id) {
2504
+ const existing = toolCallBuffers.get(tc.id);
2505
+ if (existing) {
2506
+ if (tc.arguments) existing.arguments += tc.arguments;
2507
+ if (tc.thoughtSignature) existing.thoughtSignature = tc.thoughtSignature;
2508
+ } else {
2509
+ toolCallBuffers.set(tc.id, {
2510
+ id: tc.id,
2511
+ name: tc.name ?? "",
2512
+ arguments: tc.arguments ?? "",
2513
+ ...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {}
2514
+ });
2515
+ }
2102
2516
  }
2103
2517
  }
2104
2518
  }
2519
+ if (chunk.usage) lastUsage = chunk.usage;
2105
2520
  }
2106
- if (chunk.usage) lastUsage = chunk.usage;
2107
- }
2108
- allToolCalls = [...toolCallBuffers.values()];
2109
- const finalMessage = assembleMessage(fullContent, allToolCalls, lastUsage);
2110
- if (reasoningBlocks?.length) {
2111
- finalMessage.reasoning = { blocks: reasoningBlocks };
2521
+ if (link.signal?.aborted) return;
2522
+ allToolCalls = [...toolCallBuffers.values()];
2523
+ const finalMessage = assembleMessage(fullContent, allToolCalls, lastUsage);
2524
+ if (reasoningBlocks?.length || reasoningText) {
2525
+ finalMessage.reasoning = {
2526
+ ...reasoningBlocks?.length ? { blocks: reasoningBlocks } : {},
2527
+ ...reasoningText ? { summary: reasoningText } : {}
2528
+ };
2529
+ }
2530
+ if (finishReason || responseModel) {
2531
+ finalMessage.response_metadata = {
2532
+ ...finalMessage.response_metadata ?? {},
2533
+ ...finishReason ? { finish_reason: finishReason } : {},
2534
+ ...responseModel ? { model_name: responseModel } : {}
2535
+ };
2536
+ }
2537
+ yield finalMessage;
2538
+ } finally {
2539
+ link.dispose();
2112
2540
  }
2113
- yield finalMessage;
2114
2541
  },
2115
2542
  bindTools: (tools, _bindOptions) => {
2116
2543
  const strict = _bindOptions?.strict ?? false;
@@ -2119,6 +2546,11 @@ function fromNativeProvider(provider, options) {
2119
2546
  }
2120
2547
  };
2121
2548
  return adapted;
2549
+ async function applyTransform(req) {
2550
+ if (!options?.transformRequest) return req;
2551
+ const out = await options.transformRequest(req);
2552
+ return out ?? req;
2553
+ }
2122
2554
  function buildRequest(messages, tools, opts, invokeOptions) {
2123
2555
  const req = {
2124
2556
  model: opts?.model ?? modelName,
@@ -2126,6 +2558,10 @@ function fromNativeProvider(provider, options) {
2126
2558
  };
2127
2559
  if (opts?.temperature != null) req.temperature = opts.temperature;
2128
2560
  if (opts?.maxTokens != null) req.maxTokens = opts.maxTokens;
2561
+ if (opts?.topP != null) req.topP = opts.topP;
2562
+ if (opts?.stop?.length) req.stop = opts.stop;
2563
+ if (opts?.presencePenalty != null) req.presencePenalty = opts.presencePenalty;
2564
+ if (opts?.frequencyPenalty != null) req.frequencyPenalty = opts.frequencyPenalty;
2129
2565
  if (tools?.length) req.tools = tools;
2130
2566
  if (opts?.extra) req.extra = opts.extra;
2131
2567
  const reasoningOverride = invokeOptions?.reasoning;
@@ -2178,7 +2614,8 @@ function toUnifiedMessage(msg) {
2178
2614
  unified.toolCalls = msg.tool_calls.map((tc) => ({
2179
2615
  id: tc.id,
2180
2616
  name: tc.function?.name ?? tc.name ?? "",
2181
- arguments: tc.function?.arguments ?? tc.arguments ?? "{}"
2617
+ arguments: tc.function?.arguments ?? tc.arguments ?? "{}",
2618
+ ...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {}
2182
2619
  }));
2183
2620
  }
2184
2621
  const reasoning = msg.reasoning;
@@ -2452,29 +2889,16 @@ function toToolDefinition(tool, strict) {
2452
2889
  }
2453
2890
  return { name, description, parameters, ...useStrict ? { strict: true } : {} };
2454
2891
  }
2892
+ function legacyTokenUsage(u) {
2893
+ return { ...toMessageUsage(u), cached_tokens: u.cachedInputTokens, cache_write_tokens: u.cachedWriteTokens };
2894
+ }
2455
2895
  function toBaseChatMessage(response) {
2456
2896
  const msg = {
2457
2897
  role: "assistant",
2458
2898
  content: response.content ?? "",
2459
- usage: {
2460
- prompt_tokens: response.usage.inputTokens,
2461
- completion_tokens: response.usage.outputTokens,
2462
- total_tokens: response.usage.totalTokens,
2463
- prompt_tokens_details: {
2464
- cached_tokens: response.usage.cachedInputTokens
2465
- },
2466
- completion_tokens_details: {
2467
- reasoning_tokens: response.usage.reasoningTokens
2468
- }
2469
- },
2899
+ usage: toMessageUsage(response.usage),
2470
2900
  response_metadata: {
2471
- token_usage: {
2472
- prompt_tokens: response.usage.inputTokens,
2473
- completion_tokens: response.usage.outputTokens,
2474
- total_tokens: response.usage.totalTokens,
2475
- cached_tokens: response.usage.cachedInputTokens,
2476
- cache_write_tokens: response.usage.cachedWriteTokens
2477
- },
2901
+ token_usage: legacyTokenUsage(response.usage),
2478
2902
  finish_reason: response.finishReason,
2479
2903
  model_name: response.model
2480
2904
  }
@@ -2483,7 +2907,8 @@ function toBaseChatMessage(response) {
2483
2907
  msg.tool_calls = response.toolCalls.map((tc) => ({
2484
2908
  id: tc.id,
2485
2909
  type: "function",
2486
- function: { name: tc.name, arguments: tc.arguments }
2910
+ function: { name: tc.name, arguments: tc.arguments },
2911
+ ...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {}
2487
2912
  }));
2488
2913
  }
2489
2914
  if (response.reasoning && (response.reasoning.blocks?.length || response.reasoning.summary)) {
@@ -2497,32 +2922,15 @@ function assembleMessage(content, toolCalls, usage) {
2497
2922
  content
2498
2923
  };
2499
2924
  if (usage) {
2500
- msg.usage = {
2501
- prompt_tokens: usage.inputTokens,
2502
- completion_tokens: usage.outputTokens,
2503
- total_tokens: usage.totalTokens,
2504
- prompt_tokens_details: {
2505
- cached_tokens: usage.cachedInputTokens
2506
- },
2507
- completion_tokens_details: {
2508
- reasoning_tokens: usage.reasoningTokens
2509
- }
2510
- };
2511
- msg.response_metadata = {
2512
- token_usage: {
2513
- prompt_tokens: usage.inputTokens,
2514
- completion_tokens: usage.outputTokens,
2515
- total_tokens: usage.totalTokens,
2516
- cached_tokens: usage.cachedInputTokens,
2517
- cache_write_tokens: usage.cachedWriteTokens
2518
- }
2519
- };
2925
+ msg.usage = toMessageUsage(usage);
2926
+ msg.response_metadata = { token_usage: legacyTokenUsage(usage) };
2520
2927
  }
2521
2928
  if (toolCalls.length > 0) {
2522
2929
  msg.tool_calls = toolCalls.map((tc) => ({
2523
2930
  id: tc.id,
2524
2931
  type: "function",
2525
- function: { name: tc.name, arguments: tc.arguments }
2932
+ function: { name: tc.name, arguments: tc.arguments },
2933
+ ...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {}
2526
2934
  }));
2527
2935
  }
2528
2936
  return msg;
@@ -2555,8 +2963,8 @@ function resolveCapabilities(provider) {
2555
2963
  return {
2556
2964
  structuredOutput: "tool_based",
2557
2965
  strictToolCalling: false,
2558
- streaming: false,
2559
- // streaming uses binary protocol
2966
+ streaming: true,
2967
+ // ConverseStream (AWS event-stream frames)
2560
2968
  provider: "bedrock"
2561
2969
  };
2562
2970
  case "vertex":
@@ -2573,150 +2981,21 @@ function resolveCapabilities(provider) {
2573
2981
 
2574
2982
  // src/smart/toolResponses.ts
2575
2983
  init_utilTokens();
2984
+ init_content();
2576
2985
 
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
- }
2706
-
2707
- // src/smart/toolArgCoercion.ts
2708
- var PLACEHOLDER_TEXT = /* @__PURE__ */ new Set(["", "null", "undefined", "none", "nil", "n/a", "na"]);
2709
- var ENVELOPE_KEYS = ["input", "args", "arguments", "params", "parameters", "payload"];
2710
- function defOf(schema) {
2711
- const def = schema?._def;
2712
- return def && typeof def === "object" ? def : null;
2713
- }
2714
- function isPlaceholder(value) {
2715
- return typeof value === "string" && PLACEHOLDER_TEXT.has(value.trim().toLowerCase());
2716
- }
2717
- function parseJsonish(value) {
2718
- const text = value.trim();
2719
- if (!text.startsWith("{") && !text.startsWith("[")) return { ok: false };
2986
+ // src/smart/toolArgCoercion.ts
2987
+ var PLACEHOLDER_TEXT = /* @__PURE__ */ new Set(["", "null", "undefined", "none", "nil", "n/a", "na"]);
2988
+ var ENVELOPE_KEYS = ["input", "args", "arguments", "params", "parameters", "payload"];
2989
+ function defOf(schema) {
2990
+ const def = schema?._def;
2991
+ return def && typeof def === "object" ? def : null;
2992
+ }
2993
+ function isPlaceholder(value) {
2994
+ return typeof value === "string" && PLACEHOLDER_TEXT.has(value.trim().toLowerCase());
2995
+ }
2996
+ function parseJsonish(value) {
2997
+ const text = value.trim();
2998
+ if (!text.startsWith("{") && !text.startsWith("[")) return { ok: false };
2720
2999
  try {
2721
3000
  return { ok: true, value: JSON.parse(text) };
2722
3001
  } catch {
@@ -3591,6 +3870,7 @@ function detectVolatileContent(text, limit = 20) {
3591
3870
 
3592
3871
  // src/smart/contextPilot/jsonCrusher.ts
3593
3872
  init_utilTokens();
3873
+ init_content();
3594
3874
  var CONTEXT_PILOT_JSON_MARKER_KEY = "__contextPilotDropped";
3595
3875
  function findCompressibleArray(output, minItems) {
3596
3876
  if (Array.isArray(output)) {
@@ -3803,6 +4083,7 @@ function compressSearchOutput(text, config, ccrStore) {
3803
4083
 
3804
4084
  // src/smart/contextPilot/pipeline.ts
3805
4085
  init_utilTokens();
4086
+ init_content();
3806
4087
  function createContextPilotRuntime(config) {
3807
4088
  return {
3808
4089
  ccrStore: new CCRStore({ ttlMs: config.ccr.ttlMs, maxEntries: config.ccr.maxEntries }),
@@ -4176,6 +4457,8 @@ function createAgentCoreNode(opts) {
4176
4457
  const streamingEnabled = Boolean(state.ctx?.__streaming);
4177
4458
  const cancellationToken = state.ctx?.__cancellationToken;
4178
4459
  const abortSignal = state.ctx?.__abortSignal;
4460
+ const onProgress = state.ctx?.__onProgress;
4461
+ const cancelRequested = () => isCancellationRequested({ signal: abortSignal, cancellationToken });
4179
4462
  const resolvedForCachePilot = getResolvedSmartConfig(opts, runtime);
4180
4463
  if (resolvedForCachePilot.contextPilot.enabled && resolvedForCachePilot.contextPilot.cacheAlignment.enabled) {
4181
4464
  const ctxForCacheWarning = state.ctx = state.ctx || {};
@@ -4334,6 +4617,29 @@ ${append}`;
4334
4617
  let response;
4335
4618
  let modelAttempt = 0;
4336
4619
  const maxModelRetries = host?.maxModelRetries ?? 0;
4620
+ const finishCancelledTurn = (partialText) => {
4621
+ const reason = abortSignal?.aborted ? "aborted" : "cancelled";
4622
+ const ctx = state.ctx = state.ctx || {};
4623
+ ctx.__cancelled = { stage: "agent", reason, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
4624
+ recordTraceEvent(traceSession, {
4625
+ type: "ai_call",
4626
+ label: "Assistant Cancelled",
4627
+ actor: { scope: "agent", name: actorName, role: "assistant", version: actorVersion },
4628
+ // "skipped", not "error": the call did not fail, the caller ended it —
4629
+ // and an "error" would flip the whole session to error.
4630
+ status: "skipped",
4631
+ durationMs: Date.now() - start,
4632
+ requestBytes: promptBytes,
4633
+ model: getModelName(runtime.model || opts.model),
4634
+ provider: getProviderName(runtime.model || opts.model),
4635
+ messageList: state.messages,
4636
+ toolDefinitions: traceToolDefinitions
4637
+ });
4638
+ onEvent?.({ type: "cancelled", stage: "agent", reason });
4639
+ onProgress?.({ stage: "agent", message: "Cancelled", detail: { reason } });
4640
+ const partial = partialText.trim().length > 0 ? [{ role: "assistant", content: partialText }] : [];
4641
+ return { messages: [...state.messages, ...partial], usage: state.usage };
4642
+ };
4337
4643
  while (true) {
4338
4644
  start = Date.now();
4339
4645
  if (shortCircuited !== void 0) {
@@ -4349,19 +4655,25 @@ ${append}`;
4349
4655
  toolDefinitions: traceToolDefinitions
4350
4656
  });
4351
4657
  } else {
4658
+ let streamedText = "";
4352
4659
  try {
4353
4660
  const normalizedMessages = normalizeBedrockToolPairing([...wireMessages]);
4354
4661
  debugToolPairing(normalizedMessages);
4355
4662
  if (streamingEnabled && typeof modelWithTools.stream === "function") {
4356
- let streamedText = "";
4357
4663
  let streamedMessage;
4664
+ let cutByCancel = false;
4358
4665
  for await (const chunk of modelWithTools.stream(normalizedMessages, invokeParams)) {
4359
- if (cancellationToken && cancellationToken.isCancellationRequested || abortSignal?.aborted) {
4666
+ if (cancelRequested()) {
4667
+ cutByCancel = true;
4360
4668
  break;
4361
4669
  }
4362
4670
  if (chunk && typeof chunk === "object" && chunk.role) {
4363
4671
  streamedMessage = chunk;
4364
4672
  }
4673
+ if (chunk && typeof chunk === "object" && chunk.type === "reasoning" && typeof chunk.reasoning_content === "string") {
4674
+ onEvent?.({ type: "reasoning", text: chunk.reasoning_content });
4675
+ continue;
4676
+ }
4365
4677
  const text = extractText2(chunk);
4366
4678
  const isAssembledMessage = Boolean(chunk && typeof chunk === "object" && chunk.role) && text.length > 0 && text === streamedText;
4367
4679
  if (text && !isAssembledMessage) {
@@ -4370,6 +4682,7 @@ ${append}`;
4370
4682
  onEvent?.({ type: "stream", text });
4371
4683
  }
4372
4684
  }
4685
+ if (cutByCancel) return finishCancelledTurn(streamedText);
4373
4686
  if (streamedMessage) {
4374
4687
  response = { ...streamedMessage };
4375
4688
  if (response.content == null || response.content === "") {
@@ -4382,6 +4695,7 @@ ${append}`;
4382
4695
  response = await modelWithTools.invoke(normalizedMessages, invokeParams);
4383
4696
  }
4384
4697
  } catch (err) {
4698
+ if (cancelRequested()) return finishCancelledTurn(streamedText);
4385
4699
  const durationMs2 = Date.now() - start;
4386
4700
  recordTraceEvent(traceSession, {
4387
4701
  type: "ai_call",
@@ -4479,6 +4793,7 @@ ${append}`;
4479
4793
  }
4480
4794
 
4481
4795
  // src/utils/traceSections.ts
4796
+ init_content();
4482
4797
  function truncate(text, max = 500) {
4483
4798
  if (!text) return "";
4484
4799
  return text.length > max ? `${text.slice(0, max)}\u2026` : text;
@@ -6369,6 +6684,9 @@ function isCompactedToolContent(content) {
6369
6684
  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
6685
  }
6371
6686
 
6687
+ // src/agent.ts
6688
+ init_content();
6689
+
6372
6690
  // src/structuredOutput/manager.ts
6373
6691
  var StructuredOutputManager = class {
6374
6692
  constructor(schema, strategy, config) {
@@ -6601,6 +6919,7 @@ function buildSubagentCatalogBlock(subagents, policy, toolNames) {
6601
6919
  }
6602
6920
 
6603
6921
  // src/plugins/host.ts
6922
+ init_content();
6604
6923
  var DEFAULT_PRIORITY = 100;
6605
6924
  var DEFAULT_TIMEOUT_MS = 1e4;
6606
6925
  var HOOK_SPECS = {
@@ -7137,6 +7456,7 @@ function performanceNow() {
7137
7456
  }
7138
7457
 
7139
7458
  // src/plugins/session.ts
7459
+ init_content();
7140
7460
  async function openPluginSession(runHost, params) {
7141
7461
  let messages = params.messages;
7142
7462
  const startGate = await runHost.runGate("sessionStart", {
@@ -7606,6 +7926,7 @@ function createAgent(opts) {
7606
7926
  onProgress?.({ stage: "agent", message: "Invoking model" });
7607
7927
  if (cancelIfRequested("before_agent")) break;
7608
7928
  state = publish({ ...state, ...await agentCore(state) });
7929
+ if (state.ctx?.__cancelled) break;
7609
7930
  onProgress?.({ stage: "agent", message: "Model response received" });
7610
7931
  if (checkpointIfRequested("after_agent")) break;
7611
7932
  const postGuardrails = getGuardrailConfig(state);
@@ -7676,7 +7997,7 @@ function createAgent(opts) {
7676
7997
  if (toolCalls.length === 0) {
7677
7998
  if (soManager && !state.ctx?.__finalizedDueToStructuredOutput && !state.ctx?.__structuredOutputForceFinalize && !state.ctx?.__guardrailBlocked) {
7678
7999
  if (soManager.strategy.kind === "native") {
7679
- const assistantText = extractMessageText2(lastMsg);
8000
+ const assistantText = extractMessageText(lastMsg);
7680
8001
  if (assistantText) {
7681
8002
  const parsed = soManager.parseFromContent(assistantText);
7682
8003
  if (parsed.success) {
@@ -7732,7 +8053,7 @@ function createAgent(opts) {
7732
8053
  if (soManager && !state.ctx?.__finalizedDueToStructuredOutput && !structuredFinalizeBlocked) {
7733
8054
  const lastForParse = state.messages[state.messages.length - 1];
7734
8055
  if (lastForParse?.role === "assistant") {
7735
- const assistantText = extractMessageText2(lastForParse);
8056
+ const assistantText = extractMessageText(lastForParse);
7736
8057
  if (assistantText) {
7737
8058
  const parsed = soManager.parseFromContent(assistantText);
7738
8059
  if (parsed.success) {
@@ -7994,7 +8315,7 @@ function createAgent(opts) {
7994
8315
  const isTransientSummarizationExit = !!res.ctx?.__needsSummarization;
7995
8316
  const finalAssistantMsg = isTransientSummarizationExit ? void 0 : getLastAssistantMessage(res.messages);
7996
8317
  const finalIsSyntheticSummary = !isTransientSummarizationExit && finalAssistantMsg && isSyntheticSummaryMessage(finalAssistantMsg);
7997
- let content = isTransientSummarizationExit || finalIsSyntheticSummary ? "" : extractMessageText2(finalAssistantMsg);
8318
+ let content = isTransientSummarizationExit || finalIsSyntheticSummary ? "" : extractMessageText(finalAssistantMsg);
7998
8319
  const finalAnswerBlocked = Boolean(
7999
8320
  isTransientSummarizationExit || res.ctx?.__awaitingApproval || res.ctx?.__awaitingUserQuestion || res.ctx?.__cancelled || res.ctx?.__paused || res.ctx?.__limitBreached
8000
8321
  );
@@ -8253,9 +8574,11 @@ function createAgentNode(opts) {
8253
8574
 
8254
8575
  // src/nodes/contextSummarize.ts
8255
8576
  init_utilTokens();
8577
+ init_content();
8256
8578
 
8257
8579
  // src/smart/contextPolicy.ts
8258
8580
  init_utilTokens();
8581
+ init_content();
8259
8582
  function collectRecentTurns(messages, lastTurnsToKeep) {
8260
8583
  if (lastTurnsToKeep <= 0) return [];
8261
8584
  const systemPrefix = messages.filter((message, index) => index === 0 && message.role === "system");
@@ -8317,7 +8640,7 @@ function isClampProtected(message, index, firstUserIndex) {
8317
8640
  function clampToBudget(messages, maxContextTokens) {
8318
8641
  let working = [...messages];
8319
8642
  while (working.length > 2) {
8320
- const tokenCount = countApproxTokens(working.map(extractMessageText2).join("\n"));
8643
+ const tokenCount = countApproxTokens(working.map(extractMessageText).join("\n"));
8321
8644
  if (tokenCount <= maxContextTokens) return working;
8322
8645
  const firstUserIndex = working.findIndex((message) => message.role === "user");
8323
8646
  const firstNonSystem = working.findIndex((message, index) => !isClampProtected(message, index, firstUserIndex));
@@ -8657,7 +8980,7 @@ function createContextSummarizeNode(opts) {
8657
8980
  let content = "";
8658
8981
  if (typeof m.content === "string") content = m.content;
8659
8982
  else if (Array.isArray(m.content)) {
8660
- content = m.content.map((c) => c.text || JSON.stringify(c)).join(" ");
8983
+ content = m.content.map((c) => contentPartToText(c, (part) => JSON.stringify(part))).join(" ");
8661
8984
  }
8662
8985
  if (m.role === "tool" && isSummarizedToolPlaceholder(content)) {
8663
8986
  const historyEntry = findToolHistoryEntry(state, m.tool_call_id, m.name);
@@ -9502,6 +9825,9 @@ async function writeSummaryFactsToMemory(store, config, summary, sourceTurn) {
9502
9825
  return store.get(config.memory.scope, { limit: config.context.lastTurnsToKeep + summary.stable_facts.length });
9503
9826
  }
9504
9827
 
9828
+ // src/smart/index.ts
9829
+ init_content();
9830
+
9505
9831
  // src/smart/skills/types.ts
9506
9832
  var DEFAULT_SKILL_POLICY = {
9507
9833
  maxOpenSkills: 4,
@@ -10516,7 +10842,7 @@ function createSmartAgent(opts) {
10516
10842
  ].join("\n");
10517
10843
  function latestUserPrompt(messages) {
10518
10844
  const latest = [...messages].reverse().find((message) => message.role === "user");
10519
- return latest ? extractMessageText2(latest) : "";
10845
+ return latest ? extractMessageText(latest) : "";
10520
10846
  }
10521
10847
  async function syncMemory(state) {
10522
10848
  const query = latestUserPrompt(state.messages || []);
@@ -11227,6 +11553,182 @@ async function runSmartAgentEvalHarness(params) {
11227
11553
  }
11228
11554
  return results;
11229
11555
  }
11556
+
11557
+ // src/providers/types.ts
11558
+ function emptyUsage() {
11559
+ return {
11560
+ inputTokens: 0,
11561
+ outputTokens: 0,
11562
+ totalTokens: 0,
11563
+ cachedInputTokens: 0,
11564
+ cachedWriteTokens: 0,
11565
+ cachedOutputTokens: 0,
11566
+ reasoningTokens: 0
11567
+ };
11568
+ }
11569
+ var ProviderError = class extends Error {
11570
+ constructor(message, provider, statusCode, responseBody) {
11571
+ super(message);
11572
+ this.provider = provider;
11573
+ this.statusCode = statusCode;
11574
+ this.responseBody = responseBody;
11575
+ this.name = "ProviderError";
11576
+ }
11577
+ };
11578
+
11579
+ // src/providers/base.ts
11580
+ var DEFAULT_RETRY = {
11581
+ maxRetries: 3,
11582
+ baseDelayMs: 500,
11583
+ maxDelayMs: 8e3
11584
+ };
11585
+ var BaseProvider = class {
11586
+ constructor() {
11587
+ this.retryPolicy = DEFAULT_RETRY;
11588
+ }
11589
+ /** Applies the transport options shared by every provider config. */
11590
+ configureTransport(config) {
11591
+ this.fetchImpl = config.fetch;
11592
+ this.timeoutMs = typeof config.timeoutMs === "number" && config.timeoutMs > 0 ? config.timeoutMs : void 0;
11593
+ }
11594
+ /**
11595
+ * The single HTTP entry point for every provider call site. Uses the
11596
+ * configured `fetch` and applies `timeoutMs`: the timer covers the time until
11597
+ * the response HEADERS arrive and is cleared after that, so a long-running
11598
+ * stream is never cut by it (use the request `signal` to cancel a stream).
11599
+ * A timeout surfaces as a `ProviderError` with status 408. The caller's
11600
+ * `signal` still aborts the request as before.
11601
+ */
11602
+ async httpFetch(url, init = {}) {
11603
+ const doFetch = this.fetchImpl ?? fetch;
11604
+ const timeoutMs = this.timeoutMs;
11605
+ if (!timeoutMs) return doFetch(url, init);
11606
+ const controller = new AbortController();
11607
+ const outer = init.signal ?? void 0;
11608
+ let timedOut = false;
11609
+ const onOuterAbort = () => controller.abort(outer?.reason);
11610
+ if (outer) {
11611
+ if (outer.aborted) controller.abort(outer.reason);
11612
+ else outer.addEventListener("abort", onOuterAbort, { once: true });
11613
+ }
11614
+ const timer = setTimeout(() => {
11615
+ timedOut = true;
11616
+ controller.abort(new Error(`timed out after ${timeoutMs}ms`));
11617
+ }, timeoutMs);
11618
+ try {
11619
+ const res = await doFetch(url, { ...init, signal: controller.signal });
11620
+ return res;
11621
+ } catch (err) {
11622
+ if (timedOut) {
11623
+ throw new ProviderError(`${this.providerName} request timed out after ${timeoutMs}ms`, this.providerName, 408);
11624
+ }
11625
+ throw err;
11626
+ } finally {
11627
+ clearTimeout(timer);
11628
+ }
11629
+ }
11630
+ /**
11631
+ * Embeds `request.input`. Implemented by the providers that have an
11632
+ * embeddings endpoint (OpenAI, Azure, openai-compatible, Bedrock, Vertex);
11633
+ * the others reject with a 400 ProviderError.
11634
+ */
11635
+ async embed(_request) {
11636
+ throw new ProviderError(`${this.providerName} does not support embeddings`, this.providerName, 400);
11637
+ }
11638
+ /**
11639
+ * Helper concrete providers can wrap their fetch with. Retries 429/5xx
11640
+ * with exponential backoff and respects Retry-After if the response
11641
+ * carries one.
11642
+ *
11643
+ * `signal` is the call's cancellation: a run that is cancelled while the
11644
+ * provider is backing off must not sit out the delay, nor start another attempt.
11645
+ */
11646
+ async doFetchWithRetry(execute, signal) {
11647
+ const policy = this.retryPolicy;
11648
+ const maxRetries = Math.max(0, policy.maxRetries ?? DEFAULT_RETRY.maxRetries);
11649
+ const baseDelay = Math.max(0, policy.baseDelayMs ?? DEFAULT_RETRY.baseDelayMs);
11650
+ const maxDelay = Math.max(baseDelay, policy.maxDelayMs ?? DEFAULT_RETRY.maxDelayMs);
11651
+ let lastResp;
11652
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
11653
+ if (signal?.aborted) throw abortReason(signal);
11654
+ const res = await execute();
11655
+ const isRetryable = res.status === 429 || res.status >= 500 && res.status < 600;
11656
+ if (!isRetryable) return res;
11657
+ const predicate = policy.shouldRetry;
11658
+ if (predicate && !predicate({ status: res.status }, attempt)) return res;
11659
+ if (attempt === maxRetries) {
11660
+ lastResp = res;
11661
+ break;
11662
+ }
11663
+ const retryAfter = res.headers.get("retry-after");
11664
+ let delay2 = Math.min(maxDelay, baseDelay * Math.pow(2, attempt));
11665
+ if (retryAfter) {
11666
+ const asNumber = Number(retryAfter);
11667
+ if (!Number.isNaN(asNumber)) delay2 = Math.min(maxDelay, Math.max(delay2, asNumber * 1e3));
11668
+ }
11669
+ try {
11670
+ await res.text();
11671
+ } catch {
11672
+ }
11673
+ await abortableSleep(delay2, signal);
11674
+ }
11675
+ return lastResp;
11676
+ }
11677
+ };
11678
+
11679
+ // src/providers/jev.ts
11680
+ var JEV_DEFAULT_BASE_URL = "https://api.typesafe.ai";
11681
+ var JevProvider = class extends BaseProvider {
11682
+ constructor(config) {
11683
+ super();
11684
+ this.providerName = "jev";
11685
+ this.configureTransport(config);
11686
+ this.apiKey = config.apiKey;
11687
+ this.baseURL = (config.baseURL ?? JEV_DEFAULT_BASE_URL).replace(/\/$/, "");
11688
+ this.defaultModel = config.defaultModel;
11689
+ this.defaultHeaders = config.defaultHeaders ?? {};
11690
+ if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
11691
+ }
11692
+ /** Ask System One questions about `state`. */
11693
+ async systemOne(request, options) {
11694
+ const model = request.model ?? this.defaultModel;
11695
+ const body = {
11696
+ ...model ? { model } : {},
11697
+ state: request.state,
11698
+ questions: request.questions
11699
+ };
11700
+ const res = await this.doFetchWithRetry(
11701
+ () => this.httpFetch(`${this.baseURL}/v1/systemone`, {
11702
+ method: "POST",
11703
+ headers: {
11704
+ "Content-Type": "application/json",
11705
+ Authorization: `Bearer ${this.apiKey}`,
11706
+ ...this.defaultHeaders
11707
+ },
11708
+ body: JSON.stringify(body),
11709
+ signal: options?.signal
11710
+ })
11711
+ );
11712
+ if (!res.ok) {
11713
+ const text = await res.text().catch(() => "");
11714
+ throw new ProviderError(`Jev API error ${res.status}: ${text}`, this.providerName, res.status, text);
11715
+ }
11716
+ return await res.json();
11717
+ }
11718
+ async complete(_request) {
11719
+ throw new ProviderError(
11720
+ 'Jev is a decision model and has no chat completion; use systemOne() or agentVerdictRule({ engine: "jev" })',
11721
+ this.providerName
11722
+ );
11723
+ }
11724
+ // eslint-disable-next-line require-yield
11725
+ async *completeStream(_request) {
11726
+ throw new ProviderError("Jev does not stream; use systemOne()", this.providerName);
11727
+ }
11728
+ };
11729
+
11730
+ // src/guardrails/checks.ts
11731
+ init_content();
11230
11732
  var Ajv = AjvModule__default.default?.default ?? AjvModule__default.default;
11231
11733
  var defaultAjv = new Ajv({ allErrors: true });
11232
11734
  defaultAjv.opts.strict = false;
@@ -11376,14 +11878,82 @@ function defaultPayload(context) {
11376
11878
  2
11377
11879
  );
11378
11880
  }
11881
+ var DEFAULT_JEV_THRESHOLD = 0.5;
11882
+ var JEV_QUESTION_KEY = "shouldBlock";
11883
+ 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.";
11884
+ var DEFAULT_JEV_CRITERIA = {
11885
+ true: "The payload is unsafe, non-compliant, or otherwise warrants blocking.",
11886
+ false: "The payload is benign and the agent should be allowed to continue."
11887
+ };
11888
+ function resolveJevClient(config) {
11889
+ if (config.client) return config.client;
11890
+ const apiKey = config.apiKey ?? process.env.TYPESAFE_API_KEY;
11891
+ if (!apiKey) {
11892
+ throw new Error(
11893
+ "Jev engine requires an API key: pass `jev.apiKey`, set TYPESAFE_API_KEY, or pass a `jev.client`."
11894
+ );
11895
+ }
11896
+ return new JevProvider({
11897
+ provider: "jev",
11898
+ apiKey,
11899
+ baseURL: config.baseURL ?? process.env.TYPESAFE_BASE_URL
11900
+ });
11901
+ }
11379
11902
  function agentVerdictRule(options) {
11380
11903
  const payloadBuilder = options.payloadBuilder || defaultPayload;
11381
11904
  const fallbackDisposition = options.dispositionFallback || "block";
11905
+ const engine = options.engine || "llm";
11906
+ const jevOptions = options.jev || {};
11907
+ const jevThreshold = typeof jevOptions.threshold === "number" ? jevOptions.threshold : DEFAULT_JEV_THRESHOLD;
11908
+ let jevClient;
11909
+ async function evaluateWithJev(context) {
11910
+ const client = jevClient ?? (jevClient = resolveJevClient(jevOptions));
11911
+ const instructions = jevOptions.question ? jevOptions.question(context) : DEFAULT_JEV_QUESTION;
11912
+ const result = await client.systemOne({
11913
+ state: payloadBuilder(context),
11914
+ questions: {
11915
+ [JEV_QUESTION_KEY]: {
11916
+ type: "noul",
11917
+ instructions,
11918
+ criteria: jevOptions.criteria ?? DEFAULT_JEV_CRITERIA
11919
+ }
11920
+ },
11921
+ ...jevOptions.model ? { model: jevOptions.model } : {}
11922
+ });
11923
+ const answer = result?.answers?.[JEV_QUESTION_KEY];
11924
+ const probability = typeof answer?.noul === "number" ? answer.noul : void 0;
11925
+ if (probability === void 0) {
11926
+ return {
11927
+ passed: false,
11928
+ disposition: fallbackDisposition,
11929
+ reason: "Jev engine did not return a noul probability.",
11930
+ details: { jevModel: result?.model, jevUsage: result?.usage }
11931
+ };
11932
+ }
11933
+ const passed = probability < jevThreshold;
11934
+ return {
11935
+ passed,
11936
+ disposition: passed ? "allow" : fallbackDisposition,
11937
+ reason: passed ? void 0 : `Jev risk probability ${probability.toFixed(3)} met or exceeded threshold ${jevThreshold}.`,
11938
+ details: {
11939
+ jevProbability: probability,
11940
+ jevThreshold,
11941
+ jevModel: result?.model,
11942
+ jevUsage: result?.usage
11943
+ }
11944
+ };
11945
+ }
11382
11946
  return {
11383
11947
  id: options.id,
11384
11948
  title: options.title || "Agent-based guardrail",
11385
11949
  description: options.description,
11386
11950
  async evaluate(context) {
11951
+ if (engine === "jev") {
11952
+ return evaluateWithJev(context);
11953
+ }
11954
+ if (!options.agent) {
11955
+ throw new Error("agentVerdictRule requires an `agent` when using the default 'llm' engine.");
11956
+ }
11387
11957
  const payload = payloadBuilder(context);
11388
11958
  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
11959
  const review = await options.agent.invoke({
@@ -11599,6 +12169,7 @@ function isHookImplemented(hook) {
11599
12169
  }
11600
12170
 
11601
12171
  // src/plugins/builtin/guardrail.ts
12172
+ init_content();
11602
12173
  var ALLOW = { action: "allow" };
11603
12174
  var RETRYABLE_STATUS = /* @__PURE__ */ new Set([408, 425, 429, 500, 502, 503, 504]);
11604
12175
  var RetryableGuardrailError = class extends Error {
@@ -11885,7 +12456,7 @@ function createGuardrailPlugin(options) {
11885
12456
  return { decision: "deny", reason: verdict.message ?? "Request blocked by guardrail policy." };
11886
12457
  },
11887
12458
  postModelCall: async ({ message }, ctx) => {
11888
- const text = extractMessageText2(message);
12459
+ const text = extractMessageText(message);
11889
12460
  if (!text) return void 0;
11890
12461
  const verdict = await check({ phase: "output", content: text, hook: "postModelCall" }, ctx);
11891
12462
  if (!raiseIfFailed(verdict, ctx) || verdict.action === "allow") return void 0;
@@ -12155,6 +12726,7 @@ function portkeyGuardrail(config = {}) {
12155
12726
  }
12156
12727
 
12157
12728
  // src/plugins/builtin/piiRedaction.ts
12729
+ init_content();
12158
12730
  function isValidTckn(value) {
12159
12731
  const digits = value.replace(/\D/g, "");
12160
12732
  if (digits.length !== 11 || digits[0] === "0") return false;
@@ -12274,7 +12846,7 @@ function piiRedaction(config = {}) {
12274
12846
  },
12275
12847
  postModelCall: ({ message }, ctx) => {
12276
12848
  if (!applied.has("modelOutput")) return void 0;
12277
- const text = extractMessageText2(message);
12849
+ const text = extractMessageText(message);
12278
12850
  if (!text) return void 0;
12279
12851
  const result = redactText(text, detectors, mask);
12280
12852
  if (result.findings.length === 0) return void 0;
@@ -13362,12 +13934,12 @@ function responseCache(config = {}) {
13362
13934
  };
13363
13935
  }
13364
13936
  function signRequest(req) {
13365
- const now = /* @__PURE__ */ new Date();
13937
+ const now = req.now ?? /* @__PURE__ */ new Date();
13366
13938
  const dateStamp = toDateStamp(now);
13367
13939
  const amzDate = toAmzDate(now);
13368
13940
  const parsed = new URL(req.url);
13369
13941
  const host = parsed.host;
13370
- const canonicalUri = parsed.pathname || "/";
13942
+ const canonicalUri = (parsed.pathname || "/").split("/").map((seg) => encodeURIComponent(seg).replace(/[!'()*]/g, (c) => "%" + c.charCodeAt(0).toString(16).toUpperCase())).join("/");
13371
13943
  const canonicalQuerystring = sortQueryParams(parsed.searchParams);
13372
13944
  const headers = {
13373
13945
  ...req.headers,
@@ -14681,140 +15253,8 @@ function languageGuard(config) {
14681
15253
  };
14682
15254
  }
14683
15255
 
14684
- // src/providers/types.ts
14685
- function emptyUsage() {
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
- };
14752
-
14753
- // src/providers/utils/sse.ts
14754
- async function* parseSSEStream(body, signal) {
14755
- const reader = body.getReader();
14756
- const decoder = new TextDecoder();
14757
- let buffer = "";
14758
- try {
14759
- while (true) {
14760
- if (signal?.aborted) ;
14761
- const { done, value } = await reader.read();
14762
- if (done) break;
14763
- buffer += decoder.decode(value, { stream: true });
14764
- const parts = buffer.split(/\r?\n\r?\n/);
14765
- buffer = parts.pop() ?? "";
14766
- for (const part of parts) {
14767
- if (!part.trim()) continue;
14768
- const event = parseSSEBlock(part);
14769
- if (event) yield event;
14770
- }
14771
- }
14772
- if (buffer.trim()) {
14773
- const event = parseSSEBlock(buffer);
14774
- if (event) yield event;
14775
- }
14776
- } finally {
14777
- reader.releaseLock();
14778
- }
14779
- }
14780
- function parseSSEBlock(block) {
14781
- let event;
14782
- let id;
14783
- let retry;
14784
- const dataLines = [];
14785
- for (const line of block.split(/\r?\n/)) {
14786
- if (line.startsWith(":")) continue;
14787
- const colonIdx = line.indexOf(":");
14788
- let field;
14789
- let value;
14790
- if (colonIdx === -1) {
14791
- field = line;
14792
- value = "";
14793
- } else {
14794
- field = line.slice(0, colonIdx);
14795
- value = line.slice(colonIdx + 1);
14796
- if (value.startsWith(" ")) value = value.slice(1);
14797
- }
14798
- switch (field) {
14799
- case "event":
14800
- event = value;
14801
- break;
14802
- case "data":
14803
- dataLines.push(value);
14804
- break;
14805
- case "id":
14806
- id = value;
14807
- break;
14808
- case "retry": {
14809
- const n = parseInt(value, 10);
14810
- if (!isNaN(n)) retry = n;
14811
- break;
14812
- }
14813
- }
14814
- }
14815
- if (dataLines.length === 0) return null;
14816
- return { event, data: dataLines.join("\n"), id, retry };
14817
- }
15256
+ // src/index.ts
15257
+ init_content();
14818
15258
 
14819
15259
  // src/providers/utils/reasoning.ts
14820
15260
  var ANTHROPIC_EFFORT_BUDGET = {
@@ -14837,6 +15277,7 @@ var GEMINI_EFFORT_BUDGET = {
14837
15277
  high: 12e3
14838
15278
  };
14839
15279
  var THINKING_OUTPUT_RESERVE = 1024;
15280
+ var MIN_THINKING_BUDGET = 1024;
14840
15281
  var THINKING_MIN_MAX_TOKENS = 4096;
14841
15282
  function applyOpenAIReasoning(body, reasoning, mode = "legacy_effort") {
14842
15283
  if (!reasoning) return;
@@ -14852,8 +15293,48 @@ function applyOpenAIReasoning(body, reasoning, mode = "legacy_effort") {
14852
15293
  if (reasoning.providerExtras) Object.assign(body, reasoning.providerExtras);
14853
15294
  }
14854
15295
  }
14855
- function applyAnthropicReasoning(body, reasoning) {
15296
+ function supportsAdaptiveThinking(model) {
15297
+ if (typeof model !== "string") return false;
15298
+ const id = model.toLowerCase();
15299
+ const at = id.indexOf("claude-");
15300
+ if (at < 0) return false;
15301
+ for (const tok of id.slice(at + 7).split("-")) {
15302
+ if (tok === "fable") return true;
15303
+ const m = /^(\d+)(?:@|$)/.exec(tok);
15304
+ if (m) {
15305
+ if (m[1].length <= 2) return Number(m[1]) >= 5;
15306
+ return false;
15307
+ }
15308
+ }
15309
+ return false;
15310
+ }
15311
+ function resolveThinkingForm(model, mode) {
15312
+ if (mode === "adaptive" || mode === "budget") return mode;
15313
+ return supportsAdaptiveThinking(model) ? "adaptive" : "budget";
15314
+ }
15315
+ function applyAdaptiveThinking(_body, reasoning, setThinking, setOutputConfig) {
15316
+ const requested = normalizeEffort(reasoning.effort);
15317
+ if (requested === "none") return false;
15318
+ let effort;
15319
+ if (requested) effort = requested === "minimal" ? "low" : requested;
15320
+ else if (typeof reasoning.budgetTokens === "number" && reasoning.budgetTokens > 0) {
15321
+ effort = reasoning.budgetTokens <= ANTHROPIC_EFFORT_BUDGET.low ? "low" : reasoning.budgetTokens <= ANTHROPIC_EFFORT_BUDGET.medium ? "medium" : "high";
15322
+ }
15323
+ if (!effort) return false;
15324
+ const thinking = { type: "adaptive" };
15325
+ if (reasoning.includeThoughts !== false) thinking.display = "summarized";
15326
+ if (reasoning.providerExtras) Object.assign(thinking, reasoning.providerExtras);
15327
+ setThinking({ thinking });
15328
+ setOutputConfig({ effort });
15329
+ return true;
15330
+ }
15331
+ function applyAnthropicReasoning(body, reasoning, opts) {
14856
15332
  if (!reasoning) return;
15333
+ if (resolveThinkingForm(opts?.model ?? body.model, opts?.mode) === "adaptive") {
15334
+ const on = applyAdaptiveThinking(body, reasoning, (extra) => body.thinking = extra.thinking, (o) => body.output_config = { ...body.output_config ?? {}, ...o });
15335
+ if (on) stripSamplingParams(body, ["temperature", "top_p", "top_k"]);
15336
+ return;
15337
+ }
14857
15338
  let budget = resolveBudget(reasoning, ANTHROPIC_EFFORT_BUDGET);
14858
15339
  if (!budget) return;
14859
15340
  const currentMax = typeof body.max_tokens === "number" ? body.max_tokens : 0;
@@ -14861,14 +15342,20 @@ function applyAnthropicReasoning(body, reasoning) {
14861
15342
  if (currentMax < requiredMax) {
14862
15343
  body.max_tokens = requiredMax;
14863
15344
  }
14864
- budget = clampBudget(budget, body.max_tokens);
15345
+ budget = Math.max(MIN_THINKING_BUDGET, clampBudget(budget, body.max_tokens));
14865
15346
  const thinking = { type: "enabled", budget_tokens: budget };
14866
15347
  if (reasoning.providerExtras) Object.assign(thinking, reasoning.providerExtras);
14867
15348
  body.thinking = thinking;
14868
15349
  stripSamplingParams(body, ["temperature", "top_p", "top_k"]);
14869
15350
  }
14870
- function applyBedrockReasoning(body, reasoning) {
15351
+ function applyBedrockReasoning(body, reasoning, opts) {
14871
15352
  if (!reasoning) return;
15353
+ if (resolveThinkingForm(opts?.model ?? body.modelId, opts?.mode) === "adaptive") {
15354
+ const fields = () => body.additionalModelRequestFields ?? (body.additionalModelRequestFields = {});
15355
+ const on = applyAdaptiveThinking(body, reasoning, (extra2) => fields().thinking = extra2.thinking, (o) => fields().output_config = { ...fields().output_config ?? {}, ...o });
15356
+ if (on && body.inferenceConfig) stripSamplingParams(body.inferenceConfig, ["temperature", "topP"]);
15357
+ return;
15358
+ }
14872
15359
  let budget = resolveBudget(reasoning, ANTHROPIC_EFFORT_BUDGET);
14873
15360
  if (!budget) return;
14874
15361
  const inference = body.inferenceConfig ?? (body.inferenceConfig = {});
@@ -14877,7 +15364,7 @@ function applyBedrockReasoning(body, reasoning) {
14877
15364
  if (currentMax < requiredMax) {
14878
15365
  inference.maxTokens = requiredMax;
14879
15366
  }
14880
- budget = clampBudget(budget, inference.maxTokens);
15367
+ budget = Math.max(MIN_THINKING_BUDGET, clampBudget(budget, inference.maxTokens));
14881
15368
  const extra = body.additionalModelRequestFields ?? (body.additionalModelRequestFields = {});
14882
15369
  const thinking = { type: "enabled", budget_tokens: budget };
14883
15370
  if (reasoning.providerExtras) Object.assign(thinking, reasoning.providerExtras);
@@ -14887,8 +15374,9 @@ function applyBedrockReasoning(body, reasoning) {
14887
15374
  function applyGeminiReasoning(generationConfig, reasoning) {
14888
15375
  if (!reasoning) return;
14889
15376
  const budget = resolveBudget(reasoning, GEMINI_EFFORT_BUDGET);
14890
- if (budget == null) return;
14891
- const thinkingConfig = { thinkingBudget: budget };
15377
+ const level = typeof reasoning.thinkingLevel === "string" && reasoning.thinkingLevel ? reasoning.thinkingLevel : void 0;
15378
+ if (budget == null && !level) return;
15379
+ const thinkingConfig = level && budget !== 0 ? { thinkingLevel: level } : { thinkingBudget: budget ?? 0 };
14892
15380
  if (reasoning.includeThoughts) thinkingConfig.includeThoughts = true;
14893
15381
  if (reasoning.providerExtras) Object.assign(thinkingConfig, reasoning.providerExtras);
14894
15382
  generationConfig.thinkingConfig = thinkingConfig;
@@ -14919,6 +15407,73 @@ function resolveBudget(reasoning, effortBudget) {
14919
15407
  return void 0;
14920
15408
  }
14921
15409
 
15410
+ // src/providers/utils/sse.ts
15411
+ async function* parseSSEStream(body, signal) {
15412
+ const reader = body.getReader();
15413
+ const decoder = new TextDecoder();
15414
+ let buffer = "";
15415
+ try {
15416
+ while (true) {
15417
+ if (signal?.aborted) throw abortReason(signal);
15418
+ const { done, value } = await reader.read();
15419
+ if (done) break;
15420
+ buffer += decoder.decode(value, { stream: true });
15421
+ const parts = buffer.split(/\r?\n\r?\n/);
15422
+ buffer = parts.pop() ?? "";
15423
+ for (const part of parts) {
15424
+ if (!part.trim()) continue;
15425
+ const event = parseSSEBlock(part);
15426
+ if (event) yield event;
15427
+ }
15428
+ }
15429
+ if (buffer.trim()) {
15430
+ const event = parseSSEBlock(buffer);
15431
+ if (event) yield event;
15432
+ }
15433
+ } finally {
15434
+ reader.cancel().catch(() => void 0);
15435
+ reader.releaseLock();
15436
+ }
15437
+ }
15438
+ function parseSSEBlock(block) {
15439
+ let event;
15440
+ let id;
15441
+ let retry;
15442
+ const dataLines = [];
15443
+ for (const line of block.split(/\r?\n/)) {
15444
+ if (line.startsWith(":")) continue;
15445
+ const colonIdx = line.indexOf(":");
15446
+ let field;
15447
+ let value;
15448
+ if (colonIdx === -1) {
15449
+ field = line;
15450
+ value = "";
15451
+ } else {
15452
+ field = line.slice(0, colonIdx);
15453
+ value = line.slice(colonIdx + 1);
15454
+ if (value.startsWith(" ")) value = value.slice(1);
15455
+ }
15456
+ switch (field) {
15457
+ case "event":
15458
+ event = value;
15459
+ break;
15460
+ case "data":
15461
+ dataLines.push(value);
15462
+ break;
15463
+ case "id":
15464
+ id = value;
15465
+ break;
15466
+ case "retry": {
15467
+ const n = parseInt(value, 10);
15468
+ if (!isNaN(n)) retry = n;
15469
+ break;
15470
+ }
15471
+ }
15472
+ }
15473
+ if (dataLines.length === 0) return null;
15474
+ return { event, data: dataLines.join("\n"), id, retry };
15475
+ }
15476
+
14922
15477
  // src/providers/utils/media.ts
14923
15478
  var EXTENSION_MIME = {
14924
15479
  jpg: "image/jpeg",
@@ -14994,12 +15549,12 @@ function sanitizeBedrockDocName(name, fallback = "document") {
14994
15549
  // src/providers/utils/jsonSchemaRefs.ts
14995
15550
  var DEFINITION_KEYS = ["definitions", "$defs"];
14996
15551
  function inlineJsonSchemaRefs(schema) {
14997
- if (!isObject(schema) || !containsRef(schema)) return schema;
15552
+ if (!isObject2(schema) || !containsRef(schema)) return schema;
14998
15553
  const root = structuredClone(schema);
14999
15554
  const selfReaching = /* @__PURE__ */ new Map();
15000
15555
  const targetOf = (ref) => {
15001
15556
  const target = resolvePointer(root, ref);
15002
- return isObject(target) ? target : void 0;
15557
+ return isObject2(target) ? target : void 0;
15003
15558
  };
15004
15559
  const reachesItself = (target) => {
15005
15560
  const known = selfReaching.get(target);
@@ -15007,7 +15562,7 @@ function inlineJsonSchemaRefs(schema) {
15007
15562
  const seen = /* @__PURE__ */ new Set();
15008
15563
  const walk = (node) => {
15009
15564
  if (Array.isArray(node)) return node.some(walk);
15010
- if (!isObject(node)) return false;
15565
+ if (!isObject2(node)) return false;
15011
15566
  if (typeof node.$ref === "string") {
15012
15567
  const next = targetOf(node.$ref);
15013
15568
  if (next === target) return true;
@@ -15025,7 +15580,7 @@ function inlineJsonSchemaRefs(schema) {
15025
15580
  const keptRefs = /* @__PURE__ */ new Set();
15026
15581
  const expand = (node) => {
15027
15582
  if (Array.isArray(node)) return node.map(expand);
15028
- if (!isObject(node)) return node;
15583
+ if (!isObject2(node)) return node;
15029
15584
  if (typeof node.$ref === "string") {
15030
15585
  const target = targetOf(node.$ref);
15031
15586
  if (target && !reachesItself(target)) {
@@ -15047,7 +15602,7 @@ function inlineJsonSchemaRefs(schema) {
15047
15602
  for (const key of DEFINITION_KEYS) delete result[key];
15048
15603
  for (const key of DEFINITION_KEYS) {
15049
15604
  const block = root[key];
15050
- if (!isObject(block)) continue;
15605
+ if (!isObject2(block)) continue;
15051
15606
  const needed = neededEntries(key, block, keptRefs);
15052
15607
  if (needed.length === 0) continue;
15053
15608
  const kept = {};
@@ -15075,13 +15630,13 @@ function collectRefs(node, into) {
15075
15630
  node.forEach((child) => collectRefs(child, into));
15076
15631
  return;
15077
15632
  }
15078
- if (!isObject(node)) return;
15633
+ if (!isObject2(node)) return;
15079
15634
  if (typeof node.$ref === "string") into.push(node.$ref);
15080
15635
  for (const [k, value] of Object.entries(node)) if (k !== "$ref") collectRefs(value, into);
15081
15636
  }
15082
15637
  function containsRef(node) {
15083
15638
  if (Array.isArray(node)) return node.some(containsRef);
15084
- if (!isObject(node)) return false;
15639
+ if (!isObject2(node)) return false;
15085
15640
  if (typeof node.$ref === "string") return true;
15086
15641
  return Object.values(node).some(containsRef);
15087
15642
  }
@@ -15098,7 +15653,7 @@ function resolvePointer(document, ref) {
15098
15653
  if (Array.isArray(current)) {
15099
15654
  if (!/^\d+$/.test(segment)) return void 0;
15100
15655
  current = current[Number(segment)];
15101
- } else if (isObject(current) && Object.prototype.hasOwnProperty.call(current, segment)) {
15656
+ } else if (isObject2(current) && Object.prototype.hasOwnProperty.call(current, segment)) {
15102
15657
  current = current[segment];
15103
15658
  } else {
15104
15659
  return void 0;
@@ -15106,15 +15661,68 @@ function resolvePointer(document, ref) {
15106
15661
  }
15107
15662
  return current;
15108
15663
  }
15109
- function isObject(value) {
15664
+ function isObject2(value) {
15110
15665
  return typeof value === "object" && value !== null && !Array.isArray(value);
15111
15666
  }
15112
15667
 
15668
+ // src/providers/utils/embeddings.ts
15669
+ function chunkArray(items, size) {
15670
+ const n = Math.max(1, Math.floor(size));
15671
+ const out = [];
15672
+ for (let i = 0; i < items.length; i += n) out.push(items.slice(i, i + n));
15673
+ return out;
15674
+ }
15675
+ async function mapWithConcurrency(items, limit, fn, signal) {
15676
+ const results = new Array(items.length);
15677
+ let next = 0;
15678
+ let failure;
15679
+ let failed = false;
15680
+ const worker = async () => {
15681
+ while (!failed) {
15682
+ if (signal?.aborted) throw signal.reason ?? new Error("aborted");
15683
+ const i = next++;
15684
+ if (i >= items.length) return;
15685
+ try {
15686
+ results[i] = await fn(items[i], i);
15687
+ } catch (err) {
15688
+ failed = true;
15689
+ failure = err;
15690
+ return;
15691
+ }
15692
+ }
15693
+ };
15694
+ await Promise.all(Array.from({ length: Math.min(Math.max(1, limit), items.length) }, worker));
15695
+ if (failed) throw failure;
15696
+ return results;
15697
+ }
15698
+ function decodeBase64Vector(b64) {
15699
+ const buf = Buffer.from(b64, "base64");
15700
+ const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
15701
+ const out = new Array(Math.floor(buf.byteLength / 4));
15702
+ for (let i = 0; i < out.length; i++) out[i] = view.getFloat32(i * 4, true);
15703
+ return out;
15704
+ }
15705
+ function assertVectorCount(provider, vectors, expected) {
15706
+ if (vectors.length !== expected) {
15707
+ throw new ProviderError(
15708
+ `${provider} embeddings returned ${vectors.length} vectors for ${expected} inputs`,
15709
+ provider,
15710
+ 502
15711
+ );
15712
+ }
15713
+ }
15714
+ function requireEmbeddingModel(provider, model) {
15715
+ if (!model) throw new ProviderError(`${provider} embeddings require a model`, provider, 400);
15716
+ return model;
15717
+ }
15718
+
15113
15719
  // src/providers/openai.ts
15114
- var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15720
+ var OpenAIProvider = class extends BaseProvider {
15115
15721
  constructor(config) {
15116
15722
  super();
15117
15723
  this.providerName = "openai";
15724
+ this.configureTransport(config);
15725
+ this.maxTokensParam = config.maxTokensParam ?? "auto";
15118
15726
  this.apiKey = config.apiKey;
15119
15727
  this.baseURL = (config.baseURL ?? "https://api.openai.com/v1").replace(/\/$/, "");
15120
15728
  this.defaultModel = config.defaultModel ?? "gpt-4o";
@@ -15122,10 +15730,14 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15122
15730
  ...config.defaultHeaders,
15123
15731
  ...config.organization ? { "OpenAI-Organization": config.organization } : {}
15124
15732
  };
15125
- this.responsesApi = config.responsesApi ?? "auto";
15126
- const ownInstance = new.target === _OpenAIProvider;
15127
- this.responsesApiModels = ownInstance ? [...config.responsesApiModels ?? []] : [];
15128
- this.responsesStreaming = ownInstance && config.responsesStreaming === true;
15733
+ const legacy = config.responsesApi;
15734
+ const explicit = config.api === "chat" || config.api === "responses" ? config.api : void 0;
15735
+ this.responsesApi = explicit === "responses" ? "always" : explicit === "chat" ? "never" : legacy ?? (config._autoMeansChat ? "never" : "auto");
15736
+ this.apiExplicitChat = explicit === "chat" || explicit === void 0 && legacy === "never";
15737
+ this.apiExplicitResponses = this.responsesApi === "always";
15738
+ this.apiResponsesNative = explicit === "responses";
15739
+ this.responsesApiModels = [...config.responsesApiModels ?? []];
15740
+ this.responsesStreaming = config.responsesStreaming ?? this.apiResponsesNative;
15129
15741
  if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
15130
15742
  }
15131
15743
  /** True when the caller listed this request's model in `responsesApiModels`. */
@@ -15151,9 +15763,10 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15151
15763
  * A model listed in `responsesApiModels` is the caller stating the answer
15152
15764
  * for that model alone; `never` still overrides it. */
15153
15765
  useResponsesApi(request) {
15154
- if (this.responsesApi === "never") return false;
15155
- if (this.responsesApi === "always") return true;
15766
+ if (this.apiExplicitChat) return false;
15767
+ if (this.apiExplicitResponses) return true;
15156
15768
  if (this.isResponsesApiModel(request)) return true;
15769
+ if (this.responsesApi !== "auto") return false;
15157
15770
  if (!request.reasoning) return false;
15158
15771
  return isReasoningModel(request.model || this.defaultModel);
15159
15772
  }
@@ -15162,13 +15775,13 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15162
15775
  return this.completeResponses(request);
15163
15776
  }
15164
15777
  const body = this.buildRequestBody(request, false);
15165
- const res = await this.doFetch(body);
15778
+ const res = await this.doFetch(body, request.signal);
15166
15779
  const json = await res.json();
15167
15780
  return this.parseResponse(json);
15168
15781
  }
15169
15782
  async *completeStream(request) {
15170
15783
  if (this.useResponsesApi(request)) {
15171
- if (this.responsesStreaming && this.isResponsesApiModel(request)) {
15784
+ if (this.responsesStreaming && (this.apiResponsesNative || this.isResponsesApiModel(request))) {
15172
15785
  yield* this.streamResponses(request);
15173
15786
  return;
15174
15787
  }
@@ -15187,13 +15800,13 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15187
15800
  return;
15188
15801
  }
15189
15802
  const body = this.buildRequestBody(request, true);
15190
- const res = await this.doFetch(body);
15803
+ const res = await this.doFetch(body, request.signal);
15191
15804
  if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
15192
15805
  let id = "";
15193
15806
  let model = "";
15194
15807
  const toolCallBuffers = /* @__PURE__ */ new Map();
15195
15808
  let usage;
15196
- for await (const event of parseSSEStream(res.body)) {
15809
+ for await (const event of parseSSEStream(res.body, request.signal)) {
15197
15810
  if (event.data === "[DONE]") break;
15198
15811
  let chunk;
15199
15812
  try {
@@ -15218,9 +15831,14 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15218
15831
  delta: {},
15219
15832
  finishReason: mapFinishReason(choice.finish_reason)
15220
15833
  };
15834
+ if (typeof choice.finish_reason === "string") out.rawFinishReason = choice.finish_reason;
15835
+ const fields = pickProviderFields(chunk, delta, choice);
15836
+ if (fields) out.providerFields = fields;
15221
15837
  if (delta.content) {
15222
15838
  out.delta.content = delta.content;
15223
15839
  }
15840
+ const reasoningDelta = extractReasoningText(delta);
15841
+ if (reasoningDelta) out.delta.reasoning = { summary: reasoningDelta };
15224
15842
  if (delta.tool_calls) {
15225
15843
  const partials = [];
15226
15844
  for (const tc of delta.tool_calls) {
@@ -15232,7 +15850,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15232
15850
  if (tc.id) buf.id = tc.id;
15233
15851
  if (tc.function?.name) buf.name = tc.function.name;
15234
15852
  if (tc.function?.arguments) buf.arguments += tc.function.arguments;
15235
- partials.push({ id: buf.id, name: buf.name || void 0, arguments: tc.function?.arguments });
15853
+ partials.push({ id: buf.id, name: buf.name || void 0, arguments: tc.function?.arguments, index: idx });
15236
15854
  }
15237
15855
  out.delta.toolCalls = partials;
15238
15856
  }
@@ -15240,6 +15858,51 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15240
15858
  yield out;
15241
15859
  }
15242
15860
  }
15861
+ // ─── Embeddings ──────────────────────────────────────────────────────────
15862
+ /** POST /embeddings, batched (default 2048 inputs per request, the OpenAI cap). */
15863
+ async embed(request) {
15864
+ const model = requireEmbeddingModel(this.providerName, request.model);
15865
+ const batches = chunkArray(request.input, request.batchSize ?? 2048);
15866
+ const vectors = [];
15867
+ const raw = [];
15868
+ let inputTokens = 0;
15869
+ let totalTokens = 0;
15870
+ let responseModel = model;
15871
+ for (const batch of batches) {
15872
+ const body = { model, input: batch };
15873
+ if (request.dimensions != null) body.dimensions = request.dimensions;
15874
+ if (request.encodingFormat) body.encoding_format = request.encodingFormat;
15875
+ if (request.extra) Object.assign(body, request.extra);
15876
+ const res = await this.embeddingsFetch(body, request.signal);
15877
+ const json = await res.json();
15878
+ raw.push(json);
15879
+ const data = Array.isArray(json.data) ? [...json.data] : [];
15880
+ data.sort((a, b) => (a.index ?? 0) - (b.index ?? 0));
15881
+ for (const d of data) {
15882
+ vectors.push(typeof d.embedding === "string" ? decodeBase64Vector(d.embedding) : d.embedding);
15883
+ }
15884
+ inputTokens += json.usage?.prompt_tokens ?? 0;
15885
+ totalTokens += json.usage?.total_tokens ?? json.usage?.prompt_tokens ?? 0;
15886
+ responseModel = json.model ?? responseModel;
15887
+ }
15888
+ assertVectorCount(this.providerName, vectors, request.input.length);
15889
+ return { model: responseModel, vectors, usage: { inputTokens, totalTokens }, raw };
15890
+ }
15891
+ async embeddingsFetch(body, signal) {
15892
+ const url = `${this.baseURL}/embeddings`;
15893
+ const headers = {
15894
+ "Content-Type": "application/json",
15895
+ Authorization: `Bearer ${this.apiKey}`,
15896
+ ...this.defaultHeaders
15897
+ };
15898
+ const payload = JSON.stringify(body);
15899
+ const res = await this.doFetchWithRetry(() => this.httpFetch(url, { method: "POST", headers, body: payload, signal }), signal);
15900
+ if (!res.ok) {
15901
+ const text = await res.text().catch(() => "");
15902
+ throw new ProviderError(`OpenAI embeddings API error ${res.status}: ${text}`, this.providerName, res.status, text);
15903
+ }
15904
+ return res;
15905
+ }
15243
15906
  // ─── Internals ───────────────────────────────────────────────────────────
15244
15907
  buildRequestBody(request, stream) {
15245
15908
  const body = {
@@ -15247,15 +15910,27 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15247
15910
  messages: request.messages.map((m) => this.toOpenAIMessage(m)),
15248
15911
  stream
15249
15912
  };
15250
- if (stream) {
15913
+ if (stream && request.streamUsage !== false) {
15251
15914
  body.stream_options = { include_usage: true };
15252
15915
  }
15253
- if (request.temperature != null) body.temperature = request.temperature;
15254
- if (request.maxTokens != null) body.max_tokens = request.maxTokens;
15255
- if (request.topP != null) body.top_p = request.topP;
15916
+ const modelId = String(body.model);
15917
+ const reasoningModel = isReasoningModel(modelId) && !/chat/i.test(modelId);
15918
+ if (request.temperature != null && !reasoningModel) body.temperature = request.temperature;
15919
+ if (request.maxTokens != null) {
15920
+ const useCompletionTokens = this.maxTokensParam === "max_completion_tokens" || this.maxTokensParam === "auto" && isReasoningModel(modelId);
15921
+ body[useCompletionTokens ? "max_completion_tokens" : "max_tokens"] = request.maxTokens;
15922
+ }
15923
+ if (request.topP != null && !reasoningModel) body.top_p = request.topP;
15256
15924
  if (request.stop) body.stop = request.stop;
15925
+ if (request.presencePenalty != null) body.presence_penalty = request.presencePenalty;
15926
+ if (request.frequencyPenalty != null) body.frequency_penalty = request.frequencyPenalty;
15927
+ if (request.seed != null) body.seed = request.seed;
15928
+ if (request.n != null) body.n = request.n;
15929
+ if (request.logprobs != null) body.logprobs = request.logprobs;
15930
+ if (request.topLogprobs != null) body.top_logprobs = request.topLogprobs;
15257
15931
  if (request.tools?.length) {
15258
15932
  body.tools = request.tools.map((t) => this.toOpenAITool(t));
15933
+ if (request.parallelToolCalls != null) body.parallel_tool_calls = request.parallelToolCalls;
15259
15934
  }
15260
15935
  if (request.toolChoice != null && request.tools?.length) {
15261
15936
  if (typeof request.toolChoice === "string") {
@@ -15287,8 +15962,8 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15287
15962
  // ─── Responses API (reasoning models) ──────────────────────────────────────
15288
15963
  async completeResponses(request) {
15289
15964
  const body = this.buildResponsesBody(request);
15290
- if (this.isResponsesApiModel(request)) adaptChatExtrasForResponses(body, request.extra);
15291
- const res = await this.responsesFetch(body);
15965
+ if (this.apiResponsesNative || this.isResponsesApiModel(request)) adaptChatExtrasForResponses(body, request.extra);
15966
+ const res = await this.responsesFetch(body, request.signal);
15292
15967
  const json = await res.json();
15293
15968
  return this.parseResponsesResponse(json, request.model || this.defaultModel);
15294
15969
  }
@@ -15304,13 +15979,14 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15304
15979
  const body = this.buildResponsesBody(request);
15305
15980
  adaptChatExtrasForResponses(body, request.extra);
15306
15981
  body.stream = true;
15307
- const res = await this.responsesFetch(body);
15982
+ const res = await this.responsesFetch(body, request.signal);
15308
15983
  if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
15309
15984
  let id = "";
15310
15985
  let model = modelId;
15311
15986
  const calls = /* @__PURE__ */ new Map();
15312
15987
  let final;
15313
- for await (const event of parseSSEStream(res.body)) {
15988
+ let streamedSummary = false;
15989
+ for await (const event of parseSSEStream(res.body, request.signal)) {
15314
15990
  if (event.data === "[DONE]") break;
15315
15991
  let data;
15316
15992
  try {
@@ -15327,19 +16003,28 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15327
16003
  case "response.output_text.delta":
15328
16004
  if (data.delta) yield { id, model, delta: { content: data.delta } };
15329
16005
  break;
16006
+ case "response.reasoning_summary_part.added":
16007
+ if (streamedSummary) yield { id, model, delta: { reasoning: { summary: "\n\n" } } };
16008
+ break;
16009
+ case "response.reasoning_summary_text.delta":
16010
+ if (typeof data.delta === "string" && data.delta) {
16011
+ streamedSummary = true;
16012
+ yield { id, model, delta: { reasoning: { summary: data.delta } } };
16013
+ }
16014
+ break;
15330
16015
  case "response.output_item.added": {
15331
16016
  const item = data.item;
15332
16017
  if (item?.type !== "function_call") break;
15333
- const call = { callId: item.call_id ?? item.id ?? "", name: item.name ?? "", arguments: item.arguments ?? "" };
16018
+ const call = { callId: item.call_id ?? item.id ?? "", name: item.name ?? "", arguments: item.arguments ?? "", index: calls.size };
15334
16019
  calls.set(item.id ?? call.callId, call);
15335
- yield { id, model, delta: { toolCalls: [{ id: call.callId, name: call.name, arguments: call.arguments }] } };
16020
+ yield { id, model, delta: { toolCalls: [{ id: call.callId, name: call.name, arguments: call.arguments, index: call.index }] } };
15336
16021
  break;
15337
16022
  }
15338
16023
  case "response.function_call_arguments.delta": {
15339
16024
  const call = calls.get(data.item_id);
15340
16025
  if (!call || !data.delta) break;
15341
16026
  call.arguments += data.delta;
15342
- yield { id, model, delta: { toolCalls: [{ id: call.callId, arguments: data.delta }] } };
16027
+ yield { id, model, delta: { toolCalls: [{ id: call.callId, arguments: data.delta, index: call.index }] } };
15343
16028
  break;
15344
16029
  }
15345
16030
  case "response.output_item.done": {
@@ -15348,13 +16033,13 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15348
16033
  const full = typeof item.arguments === "string" ? item.arguments : "";
15349
16034
  const call = calls.get(item.id ?? item.call_id);
15350
16035
  if (!call) {
15351
- const added = { callId: item.call_id ?? item.id ?? "", name: item.name ?? "", arguments: full };
16036
+ const added = { callId: item.call_id ?? item.id ?? "", name: item.name ?? "", arguments: full, index: calls.size };
15352
16037
  calls.set(item.id ?? added.callId, added);
15353
- yield { id, model, delta: { toolCalls: [{ id: added.callId, name: added.name, arguments: full }] } };
16038
+ yield { id, model, delta: { toolCalls: [{ id: added.callId, name: added.name, arguments: full, index: added.index }] } };
15354
16039
  } else if (full.length > call.arguments.length && full.startsWith(call.arguments)) {
15355
16040
  const rest = full.slice(call.arguments.length);
15356
16041
  call.arguments = full;
15357
- yield { id, model, delta: { toolCalls: [{ id: call.callId, arguments: rest }] } };
16042
+ yield { id, model, delta: { toolCalls: [{ id: call.callId, arguments: rest, index: call.index }] } };
15358
16043
  }
15359
16044
  break;
15360
16045
  }
@@ -15377,7 +16062,8 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15377
16062
  yield {
15378
16063
  id: final?.id || id,
15379
16064
  model: final?.model || model,
15380
- delta: final?.reasoning ? { reasoning: final.reasoning } : {},
16065
+ // Summary text already went out as deltas; do not repeat it.
16066
+ delta: final?.reasoning && !streamedSummary ? { reasoning: final.reasoning } : {},
15381
16067
  usage: final?.usage,
15382
16068
  finishReason: final?.finishReason ?? (calls.size > 0 ? "tool_calls" : "stop")
15383
16069
  };
@@ -15478,7 +16164,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15478
16164
  });
15479
16165
  return { role, content };
15480
16166
  }
15481
- async responsesFetch(body) {
16167
+ async responsesFetch(body, signal) {
15482
16168
  body.input = expandResponsesInput(body.input);
15483
16169
  const url = `${this.baseURL}/responses`;
15484
16170
  const headers = {
@@ -15487,7 +16173,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15487
16173
  ...this.defaultHeaders
15488
16174
  };
15489
16175
  const payload = JSON.stringify(body);
15490
- const res = await this.doFetchWithRetry(() => fetch(url, { method: "POST", headers, body: payload }));
16176
+ const res = await this.doFetchWithRetry(() => this.httpFetch(url, { method: "POST", headers, body: payload, signal }), signal);
15491
16177
  if (!res.ok) {
15492
16178
  const text = await res.text().catch(() => "");
15493
16179
  throw new ProviderError(
@@ -15608,7 +16294,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15608
16294
  }
15609
16295
  return { type: "function", function: fn };
15610
16296
  }
15611
- async doFetch(body) {
16297
+ async doFetch(body, signal) {
15612
16298
  const url = `${this.baseURL}/chat/completions`;
15613
16299
  const headers = {
15614
16300
  "Content-Type": "application/json",
@@ -15616,7 +16302,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15616
16302
  ...this.defaultHeaders
15617
16303
  };
15618
16304
  const payload = JSON.stringify(body);
15619
- const res = await this.doFetchWithRetry(() => fetch(url, { method: "POST", headers, body: payload }));
16305
+ const res = await this.doFetchWithRetry(() => this.httpFetch(url, { method: "POST", headers, body: payload, signal }), signal);
15620
16306
  if (!res.ok) {
15621
16307
  const text = await res.text().catch(() => "");
15622
16308
  throw new ProviderError(
@@ -15636,6 +16322,8 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15636
16322
  name: tc.function?.name ?? "",
15637
16323
  arguments: tc.function?.arguments ?? "{}"
15638
16324
  }));
16325
+ const reasoningText = extractReasoningText(message);
16326
+ const providerFields = pickProviderFields(json, message, choice);
15639
16327
  return {
15640
16328
  id: json.id ?? "",
15641
16329
  model: json.model ?? "",
@@ -15643,6 +16331,9 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15643
16331
  toolCalls,
15644
16332
  usage: this.extractUsage(json.usage),
15645
16333
  finishReason: mapFinishReason(choice?.finish_reason),
16334
+ ...typeof choice?.finish_reason === "string" ? { rawFinishReason: choice.finish_reason } : {},
16335
+ ...providerFields ? { providerFields } : {},
16336
+ ...reasoningText ? { reasoning: { summary: reasoningText } } : {},
15646
16337
  raw: json
15647
16338
  };
15648
16339
  }
@@ -15661,6 +16352,23 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15661
16352
  };
15662
16353
  }
15663
16354
  };
16355
+ function extractReasoningText(src) {
16356
+ if (!src || typeof src !== "object") return void 0;
16357
+ for (const key of ["reasoning_content", "reasoning"]) {
16358
+ const v = src[key];
16359
+ if (typeof v === "string" && v.length > 0) return v;
16360
+ }
16361
+ return void 0;
16362
+ }
16363
+ function pickProviderFields(top, message, choice) {
16364
+ const out = {};
16365
+ if (top?.system_fingerprint != null) out.system_fingerprint = top.system_fingerprint;
16366
+ if (top?.service_tier != null) out.service_tier = top.service_tier;
16367
+ if (message?.annotations != null) out.annotations = message.annotations;
16368
+ if (message?.refusal != null) out.refusal = message.refusal;
16369
+ if (choice?.logprobs != null) out.logprobs = choice.logprobs;
16370
+ return Object.keys(out).length > 0 ? out : void 0;
16371
+ }
15664
16372
  function isReasoningModel(model) {
15665
16373
  if (!model) return false;
15666
16374
  const m = model.toLowerCase();
@@ -15737,38 +16445,88 @@ function mapFinishReason(reason) {
15737
16445
  }
15738
16446
  }
15739
16447
 
16448
+ // src/providers/utils/toolChoice.ts
16449
+ function supportsForcedToolChoice(model) {
16450
+ if (typeof model !== "string") return true;
16451
+ const id = model.toLowerCase();
16452
+ const at = id.indexOf("claude-");
16453
+ if (at < 0) return true;
16454
+ const toks = id.slice(at + 7).split("-");
16455
+ let family = false;
16456
+ for (const tok of toks) {
16457
+ if (tok === "sonnet" || tok === "opus") {
16458
+ family = true;
16459
+ continue;
16460
+ }
16461
+ const m = /^(\d+)(?:@|:|$)/.exec(tok);
16462
+ if (m) {
16463
+ if (m[1].length > 2) continue;
16464
+ if (Number(m[1]) < 5) return true;
16465
+ if (family) return false;
16466
+ return !toks.some((t) => t === "sonnet" || t === "opus");
16467
+ }
16468
+ }
16469
+ return true;
16470
+ }
16471
+ function forcedToolChoiceRejected(text) {
16472
+ const t = text.toLowerCase();
16473
+ return t.indexOf("tool_choice") >= 0 && t.indexOf("not supported for this model") >= 0;
16474
+ }
16475
+
15740
16476
  // src/providers/anthropic.ts
16477
+ var DEFAULT_MAX_TOKENS = 4096;
16478
+ function normalizeExplicitThinking(body) {
16479
+ const t = body.thinking;
16480
+ if (t == null) {
16481
+ delete body.thinking;
16482
+ return;
16483
+ }
16484
+ if (t.type !== "enabled") return;
16485
+ const budget = typeof t.budget_tokens === "number" ? t.budget_tokens : 0;
16486
+ if (budget > 0 && (typeof body.max_tokens !== "number" || body.max_tokens <= budget)) {
16487
+ body.max_tokens = budget + 1024;
16488
+ }
16489
+ for (const k of ["temperature", "top_p", "top_k"]) delete body[k];
16490
+ }
16491
+ function thinkingFormRejected(text) {
16492
+ const t = text.toLowerCase();
16493
+ if (t.indexOf("thinking.type.enabled") >= 0 && t.indexOf("not supported") >= 0) return "enabled";
16494
+ if (t.indexOf("thinking.type.adaptive") >= 0 && t.indexOf("not supported") >= 0 && t.indexOf("thinking.type.enabled") < 0) return "adaptive";
16495
+ return void 0;
16496
+ }
15741
16497
  var AnthropicProvider = class extends BaseProvider {
15742
16498
  constructor(config) {
15743
16499
  super();
15744
16500
  this.providerName = "anthropic";
16501
+ this.configureTransport(config);
15745
16502
  this.apiKey = config.apiKey;
15746
16503
  this.baseURL = (config.baseURL ?? "https://api.anthropic.com").replace(/\/$/, "");
15747
16504
  this.defaultModel = config.defaultModel ?? "claude-sonnet-4-20250514";
15748
16505
  this.defaultHeaders = config.defaultHeaders ?? {};
15749
16506
  this.anthropicVersion = config.anthropicVersion ?? "2023-06-01";
16507
+ this.thinkingMode = config.thinkingMode ?? "auto";
15750
16508
  this.promptCachingEnabled = config.prompt_caching?.enabled === true;
15751
16509
  if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
15752
16510
  }
15753
16511
  async complete(request) {
15754
- const body = this.buildRequestBody(request, false);
15755
- const res = await this.doFetch(body);
16512
+ const res = await this.send(request, false);
15756
16513
  const json = await res.json();
15757
16514
  return this.parseResponse(json);
15758
16515
  }
15759
16516
  async *completeStream(request) {
15760
- const body = this.buildRequestBody(request, true);
15761
- const res = await this.doFetch(body);
16517
+ const res = await this.send(request, true);
15762
16518
  if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
15763
16519
  let id = "";
15764
16520
  let model = "";
15765
16521
  let inputTokens = 0;
15766
16522
  let outputTokens = 0;
16523
+ let thinkingTokens = 0;
15767
16524
  let cacheReadInputTokens = 0;
15768
16525
  let cacheCreationInputTokens = 0;
15769
16526
  const currentToolCalls = /* @__PURE__ */ new Map();
16527
+ let toolOrdinal = 0;
15770
16528
  const reasoningBlocks = /* @__PURE__ */ new Map();
15771
- for await (const event of parseSSEStream(res.body)) {
16529
+ for await (const event of parseSSEStream(res.body, request.signal)) {
15772
16530
  let data;
15773
16531
  try {
15774
16532
  data = JSON.parse(event.data);
@@ -15795,8 +16553,11 @@ var AnthropicProvider = class extends BaseProvider {
15795
16553
  currentToolCalls.set(idx, {
15796
16554
  id: block.id ?? "",
15797
16555
  name: block.name ?? "",
15798
- arguments: ""
16556
+ arguments: "",
16557
+ ordinal: toolOrdinal++
15799
16558
  });
16559
+ const opened = currentToolCalls.get(idx);
16560
+ yield { id, model, delta: { toolCalls: [{ id: opened.id, name: opened.name, arguments: "", index: opened.ordinal }] } };
15800
16561
  } else if (block?.type === "thinking") {
15801
16562
  reasoningBlocks.set(idx, { type: "thinking", text: block.thinking ?? "", signature: block.signature });
15802
16563
  } else if (block?.type === "redacted_thinking") {
@@ -15834,7 +16595,7 @@ var AnthropicProvider = class extends BaseProvider {
15834
16595
  id,
15835
16596
  model,
15836
16597
  delta: {
15837
- toolCalls: [{ id: tc.id, name: tc.name, arguments: delta.partial_json }]
16598
+ toolCalls: [{ id: tc.id, name: tc.name, arguments: delta.partial_json, index: tc.ordinal }]
15838
16599
  }
15839
16600
  };
15840
16601
  }
@@ -15847,8 +16608,10 @@ var AnthropicProvider = class extends BaseProvider {
15847
16608
  const delta = data.delta;
15848
16609
  if (data.usage) {
15849
16610
  outputTokens = data.usage.output_tokens ?? outputTokens;
16611
+ thinkingTokens = data.usage.output_tokens_details?.thinking_tokens ?? thinkingTokens;
15850
16612
  }
15851
16613
  const finishReason = mapAnthropicStopReason(delta?.stop_reason);
16614
+ const rawFinishReason = typeof delta?.stop_reason === "string" ? delta.stop_reason : void 0;
15852
16615
  const usage = {
15853
16616
  inputTokens,
15854
16617
  outputTokens,
@@ -15856,7 +16619,7 @@ var AnthropicProvider = class extends BaseProvider {
15856
16619
  cachedInputTokens: cacheReadInputTokens,
15857
16620
  cachedWriteTokens: cacheCreationInputTokens,
15858
16621
  cachedOutputTokens: 0,
15859
- reasoningTokens: 0
16622
+ reasoningTokens: thinkingTokens
15860
16623
  };
15861
16624
  const blocks = [...reasoningBlocks.values()].filter(
15862
16625
  (b) => b.type === "thinking" && b.signature || b.type === "redacted_thinking" && b.data
@@ -15866,6 +16629,7 @@ var AnthropicProvider = class extends BaseProvider {
15866
16629
  model,
15867
16630
  delta: blocks.length > 0 ? { reasoning: { blocks } } : {},
15868
16631
  finishReason,
16632
+ ...rawFinishReason ? { rawFinishReason } : {},
15869
16633
  usage
15870
16634
  };
15871
16635
  break;
@@ -15880,12 +16644,12 @@ var AnthropicProvider = class extends BaseProvider {
15880
16644
  }
15881
16645
  }
15882
16646
  // ─── Internals ───────────────────────────────────────────────────────────
15883
- buildRequestBody(request, stream) {
16647
+ buildRequestBody(request, stream, modeOverride, downgradeToolChoice = false) {
15884
16648
  const { system, messages } = this.splitSystemMessages(request.messages);
15885
16649
  const body = {
15886
16650
  model: request.model || this.defaultModel,
15887
16651
  messages: this.toAnthropicMessages(messages),
15888
- max_tokens: request.maxTokens ?? 4096,
16652
+ max_tokens: request.maxTokens ?? DEFAULT_MAX_TOKENS,
15889
16653
  stream
15890
16654
  };
15891
16655
  if (system) {
@@ -15906,18 +16670,27 @@ var AnthropicProvider = class extends BaseProvider {
15906
16670
  body.tools = tools;
15907
16671
  }
15908
16672
  if (request.toolChoice != null) {
16673
+ const forceOk = !downgradeToolChoice && supportsForcedToolChoice(body.model);
15909
16674
  if (request.toolChoice === "auto") {
15910
16675
  body.tool_choice = { type: "auto" };
15911
16676
  } else if (request.toolChoice === "required") {
15912
- body.tool_choice = { type: "any" };
16677
+ body.tool_choice = forceOk ? { type: "any" } : { type: "auto" };
15913
16678
  } else if (request.toolChoice === "none") ; else {
15914
- body.tool_choice = { type: "tool", name: request.toolChoice.name };
16679
+ body.tool_choice = forceOk ? { type: "tool", name: request.toolChoice.name } : { type: "auto" };
15915
16680
  }
15916
16681
  }
15917
16682
  if (request.extra) {
15918
16683
  Object.assign(body, request.extra);
15919
16684
  }
15920
- applyAnthropicReasoning(body, request.reasoning);
16685
+ const explicitThinking = request.extra && typeof request.extra === "object" && "thinking" in request.extra;
16686
+ if (explicitThinking) {
16687
+ normalizeExplicitThinking(body);
16688
+ } else {
16689
+ applyAnthropicReasoning(body, request.reasoning, { model: body.model, mode: modeOverride ?? this.thinkingMode });
16690
+ }
16691
+ if (typeof body.max_tokens !== "number" || !(body.max_tokens > 0)) {
16692
+ body.max_tokens = DEFAULT_MAX_TOKENS;
16693
+ }
15921
16694
  return body;
15922
16695
  }
15923
16696
  splitSystemMessages(messages) {
@@ -16048,7 +16821,35 @@ var AnthropicProvider = class extends BaseProvider {
16048
16821
  input_schema: t.parameters
16049
16822
  };
16050
16823
  }
16051
- async doFetch(body) {
16824
+ /** Builds and sends the request; retries once with the other thinking form
16825
+ * when the upstream rejects the one we picked. */
16826
+ async send(request, stream) {
16827
+ let mode;
16828
+ let downgrade = false;
16829
+ let flippedThinking = false;
16830
+ for (; ; ) {
16831
+ const body = this.buildRequestBody(request, stream, mode, downgrade);
16832
+ try {
16833
+ return await this.doFetch(body, request.signal);
16834
+ } catch (err) {
16835
+ if (!(err instanceof ProviderError) || err.statusCode !== 400) throw err;
16836
+ const text = String(err.responseBody ?? err.message);
16837
+ if (!downgrade && body.tool_choice && body.tool_choice.type !== "auto" && forcedToolChoiceRejected(text)) {
16838
+ downgrade = true;
16839
+ continue;
16840
+ }
16841
+ const explicit = request.extra && typeof request.extra === "object" && "thinking" in request.extra;
16842
+ if (flippedThinking || explicit || !request.reasoning) throw err;
16843
+ const wrong = thinkingFormRejected(text);
16844
+ if (!wrong) throw err;
16845
+ const used = resolveThinkingForm(request.model ?? this.defaultModel, this.thinkingMode);
16846
+ if (wrong === "enabled" && used !== "budget" || wrong === "adaptive" && used !== "adaptive") throw err;
16847
+ mode = wrong === "enabled" ? "adaptive" : "budget";
16848
+ flippedThinking = true;
16849
+ }
16850
+ }
16851
+ }
16852
+ async doFetch(body, signal) {
16052
16853
  const url = `${this.baseURL}/v1/messages`;
16053
16854
  const headers = {
16054
16855
  "Content-Type": "application/json",
@@ -16057,7 +16858,7 @@ var AnthropicProvider = class extends BaseProvider {
16057
16858
  ...this.defaultHeaders
16058
16859
  };
16059
16860
  const payload = JSON.stringify(body);
16060
- const res = await this.doFetchWithRetry(() => fetch(url, { method: "POST", headers, body: payload }));
16861
+ const res = await this.doFetchWithRetry(() => this.httpFetch(url, { method: "POST", headers, body: payload, signal }), signal);
16061
16862
  if (!res.ok) {
16062
16863
  const text = await res.text().catch(() => "");
16063
16864
  throw new ProviderError(
@@ -16102,10 +16903,9 @@ var AnthropicProvider = class extends BaseProvider {
16102
16903
  cachedInputTokens: usage.cache_read_input_tokens ?? 0,
16103
16904
  cachedWriteTokens: usage.cache_creation_input_tokens ?? 0,
16104
16905
  cachedOutputTokens: 0,
16105
- // Anthropic bills thinking tokens inside `output_tokens` and does not
16106
- // expose a separate count, so reasoningTokens stays 0 here (cost is still
16107
- // captured via outputTokens). See docs for the limitation.
16108
- reasoningTokens: 0
16906
+ // Thinking tokens are billed inside `output_tokens`; newer models also
16907
+ // report the split as `output_tokens_details.thinking_tokens`.
16908
+ reasoningTokens: usage.output_tokens_details?.thinking_tokens ?? 0
16109
16909
  };
16110
16910
  return {
16111
16911
  id: json.id ?? "",
@@ -16114,6 +16914,7 @@ var AnthropicProvider = class extends BaseProvider {
16114
16914
  toolCalls,
16115
16915
  usage: tokenUsage,
16116
16916
  finishReason: mapAnthropicStopReason(json.stop_reason),
16917
+ ...typeof json.stop_reason === "string" ? { rawFinishReason: json.stop_reason } : {},
16117
16918
  reasoning: reasoningBlocks.length > 0 ? { blocks: reasoningBlocks, summary: summaryParts.join("\n").trim() || void 0 } : void 0,
16118
16919
  raw: json
16119
16920
  };
@@ -16159,7 +16960,15 @@ var AzureProvider = class extends OpenAIProvider {
16159
16960
  provider: "openai",
16160
16961
  apiKey: config.apiKey,
16161
16962
  defaultModel: config.defaultModel ?? config.deploymentName ?? "gpt-4o",
16162
- defaultHeaders: config.defaultHeaders
16963
+ defaultHeaders: config.defaultHeaders,
16964
+ retry: config.retry,
16965
+ fetch: config.fetch,
16966
+ timeoutMs: config.timeoutMs,
16967
+ maxTokensParam: config.maxTokensParam,
16968
+ api: config.api,
16969
+ responsesApi: config.responsesApi,
16970
+ responsesApiModels: config.responsesApiModels,
16971
+ responsesStreaming: config.responsesStreaming
16163
16972
  });
16164
16973
  this.providerName = "azure";
16165
16974
  this.endpoint = config.endpoint.replace(/\/$/, "");
@@ -16167,22 +16976,24 @@ var AzureProvider = class extends OpenAIProvider {
16167
16976
  this.deploymentName = config.deploymentName;
16168
16977
  this.azureApiKey = config.apiKey;
16169
16978
  }
16170
- async doFetch(body) {
16979
+ async doFetch(body, signal) {
16171
16980
  const deployment = this.deploymentName ?? body.model;
16172
16981
  if (!deployment) {
16173
16982
  throw new ProviderError("Azure requires a deploymentName or model", this.providerName);
16174
16983
  }
16175
16984
  const url = `${this.endpoint}/openai/deployments/${deployment}/chat/completions?api-version=${this.apiVersion}`;
16176
16985
  const { model: _model, ...bodyWithoutModel } = body;
16177
- const res = await fetch(url, {
16986
+ const payload = JSON.stringify(bodyWithoutModel);
16987
+ const res = await this.doFetchWithRetry(() => this.httpFetch(url, {
16178
16988
  method: "POST",
16179
16989
  headers: {
16180
16990
  "Content-Type": "application/json",
16181
16991
  "api-key": this.azureApiKey,
16182
16992
  ...this.defaultHeaders
16183
16993
  },
16184
- body: JSON.stringify(bodyWithoutModel)
16185
- });
16994
+ body: payload,
16995
+ signal
16996
+ }), signal);
16186
16997
  if (!res.ok) {
16187
16998
  const text = await res.text().catch(() => "");
16188
16999
  throw new ProviderError(
@@ -16194,10 +17005,36 @@ var AzureProvider = class extends OpenAIProvider {
16194
17005
  }
16195
17006
  return res;
16196
17007
  }
17008
+ /** Azure embeddings: the deployment named by the request's model (falling back
17009
+ * to the configured deployment) in the path, api-key auth. */
17010
+ async embeddingsFetch(body, signal) {
17011
+ const deployment = body.model || this.deploymentName;
17012
+ if (!deployment) {
17013
+ throw new ProviderError("Azure embeddings require a deployment name or model", this.providerName, 400);
17014
+ }
17015
+ const url = `${this.endpoint}/openai/deployments/${deployment}/embeddings?api-version=${this.apiVersion}`;
17016
+ const { model: _model, ...bodyWithoutModel } = body;
17017
+ const payload = JSON.stringify(bodyWithoutModel);
17018
+ const res = await this.doFetchWithRetry(() => this.httpFetch(url, {
17019
+ method: "POST",
17020
+ headers: {
17021
+ "Content-Type": "application/json",
17022
+ "api-key": this.azureApiKey,
17023
+ ...this.defaultHeaders
17024
+ },
17025
+ body: payload,
17026
+ signal
17027
+ }), signal);
17028
+ if (!res.ok) {
17029
+ const text = await res.text().catch(() => "");
17030
+ throw new ProviderError(`Azure OpenAI embeddings API error ${res.status}: ${text}`, this.providerName, res.status, text);
17031
+ }
17032
+ return res;
17033
+ }
16197
17034
  /** Azure exposes the Responses API at /openai/responses with api-key auth.
16198
17035
  * Reasoning summaries require a preview api-version; callers can override via
16199
17036
  * the `apiVersion` config. */
16200
- async responsesFetch(body) {
17037
+ async responsesFetch(body, signal) {
16201
17038
  body.input = expandAzureResponsesInput(body.input);
16202
17039
  const deployment = this.deploymentName ?? body.model;
16203
17040
  if (!deployment) {
@@ -16205,15 +17042,16 @@ var AzureProvider = class extends OpenAIProvider {
16205
17042
  }
16206
17043
  const url = `${this.endpoint}/openai/responses?api-version=${this.apiVersion}`;
16207
17044
  const payload = JSON.stringify({ ...body, model: deployment });
16208
- const res = await fetch(url, {
17045
+ const res = await this.doFetchWithRetry(() => this.httpFetch(url, {
16209
17046
  method: "POST",
16210
17047
  headers: {
16211
17048
  "Content-Type": "application/json",
16212
17049
  "api-key": this.azureApiKey,
16213
17050
  ...this.defaultHeaders
16214
17051
  },
16215
- body: payload
16216
- });
17052
+ body: payload,
17053
+ signal
17054
+ }), signal);
16217
17055
  if (!res.ok) {
16218
17056
  const text = await res.text().catch(() => "");
16219
17057
  throw new ProviderError(
@@ -16249,20 +17087,155 @@ var OpenAICompatibleProvider = class extends OpenAIProvider {
16249
17087
  apiKey: config.apiKey,
16250
17088
  baseURL: config.baseURL,
16251
17089
  defaultModel: config.defaultModel,
16252
- defaultHeaders: config.defaultHeaders
17090
+ defaultHeaders: config.defaultHeaders,
17091
+ organization: config.organization,
17092
+ retry: config.retry,
17093
+ fetch: config.fetch,
17094
+ timeoutMs: config.timeoutMs,
17095
+ maxTokensParam: config.maxTokensParam,
17096
+ api: config.api,
17097
+ // Unlike OpenAI / Azure, "auto" on a compatible server means Chat
17098
+ // Completions (the 0.11 default): the model name is the operator's.
17099
+ // `responsesApiModels` still applies; `responsesApi: "auto"` opts in.
17100
+ _autoMeansChat: true,
17101
+ responsesApi: config.responsesApi,
17102
+ responsesApiModels: config.responsesApiModels,
17103
+ responsesStreaming: config.responsesStreaming
16253
17104
  });
16254
17105
  this.providerName = "openai-compatible";
16255
17106
  }
16256
17107
  };
16257
17108
 
17109
+ // src/providers/utils/eventStream.ts
17110
+ var EventStreamError = class extends Error {
17111
+ constructor(message) {
17112
+ super(message);
17113
+ this.name = "EventStreamError";
17114
+ }
17115
+ };
17116
+ var CRC_TABLE = (() => {
17117
+ const table = new Uint32Array(256);
17118
+ for (let n = 0; n < 256; n++) {
17119
+ let c = n;
17120
+ for (let k = 0; k < 8; k++) c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
17121
+ table[n] = c >>> 0;
17122
+ }
17123
+ return table;
17124
+ })();
17125
+ function crc32(bytes, start = 0, end = bytes.length) {
17126
+ let c = 4294967295;
17127
+ for (let i = start; i < end; i++) c = CRC_TABLE[(c ^ bytes[i]) & 255] ^ c >>> 8;
17128
+ return (c ^ 4294967295) >>> 0;
17129
+ }
17130
+ function decodeFrame(frame) {
17131
+ const view = new DataView(frame.buffer, frame.byteOffset, frame.byteLength);
17132
+ const total = view.getUint32(0);
17133
+ const headersLen = view.getUint32(4);
17134
+ if (total !== frame.byteLength) throw new EventStreamError("event-stream frame length mismatch");
17135
+ if (crc32(frame, 0, 8) !== view.getUint32(8)) throw new EventStreamError("event-stream prelude CRC mismatch");
17136
+ if (crc32(frame, 0, total - 4) !== view.getUint32(total - 4)) throw new EventStreamError("event-stream message CRC mismatch");
17137
+ if (12 + headersLen > total - 4) throw new EventStreamError("event-stream headers overflow frame");
17138
+ const headers = {};
17139
+ const td = new TextDecoder();
17140
+ let o = 12;
17141
+ const headersEnd = 12 + headersLen;
17142
+ while (o < headersEnd) {
17143
+ const nameLen = frame[o++];
17144
+ const name = td.decode(frame.subarray(o, o + nameLen));
17145
+ o += nameLen;
17146
+ const type = frame[o++];
17147
+ switch (type) {
17148
+ case 0:
17149
+ headers[name] = true;
17150
+ break;
17151
+ case 1:
17152
+ headers[name] = false;
17153
+ break;
17154
+ case 2:
17155
+ headers[name] = view.getInt8(o);
17156
+ o += 1;
17157
+ break;
17158
+ case 3:
17159
+ headers[name] = view.getInt16(o);
17160
+ o += 2;
17161
+ break;
17162
+ case 4:
17163
+ headers[name] = view.getInt32(o);
17164
+ o += 4;
17165
+ break;
17166
+ case 5:
17167
+ headers[name] = view.getBigInt64(o);
17168
+ o += 8;
17169
+ break;
17170
+ case 6: {
17171
+ const len = view.getUint16(o);
17172
+ o += 2;
17173
+ headers[name] = frame.slice(o, o + len);
17174
+ o += len;
17175
+ break;
17176
+ }
17177
+ case 7: {
17178
+ const len = view.getUint16(o);
17179
+ o += 2;
17180
+ headers[name] = td.decode(frame.subarray(o, o + len));
17181
+ o += len;
17182
+ break;
17183
+ }
17184
+ case 8:
17185
+ headers[name] = view.getBigInt64(o);
17186
+ o += 8;
17187
+ break;
17188
+ case 9:
17189
+ headers[name] = frame.slice(o, o + 16);
17190
+ o += 16;
17191
+ break;
17192
+ default:
17193
+ throw new EventStreamError(`unknown event-stream header type ${type}`);
17194
+ }
17195
+ }
17196
+ return { headers, payload: frame.slice(headersEnd, total - 4) };
17197
+ }
17198
+ async function* parseEventStream(body, signal) {
17199
+ const reader = body.getReader();
17200
+ let buf = new Uint8Array(0);
17201
+ try {
17202
+ while (true) {
17203
+ if (signal?.aborted) throw abortReason(signal);
17204
+ const { done, value } = await reader.read();
17205
+ if (done) break;
17206
+ if (!value?.length) continue;
17207
+ const merged = new Uint8Array(buf.length + value.length);
17208
+ merged.set(buf, 0);
17209
+ merged.set(value, buf.length);
17210
+ buf = merged;
17211
+ while (buf.length >= 12) {
17212
+ const total = new DataView(buf.buffer, buf.byteOffset, buf.byteLength).getUint32(0);
17213
+ if (total < 16) throw new EventStreamError("invalid event-stream frame length");
17214
+ if (buf.length < total) break;
17215
+ yield decodeFrame(buf.subarray(0, total));
17216
+ buf = buf.subarray(total);
17217
+ }
17218
+ }
17219
+ if (buf.length > 0) throw new EventStreamError("event-stream ended inside a frame");
17220
+ } finally {
17221
+ reader.cancel().catch(() => void 0);
17222
+ try {
17223
+ reader.releaseLock();
17224
+ } catch {
17225
+ }
17226
+ }
17227
+ }
17228
+
16258
17229
  // src/providers/bedrock.ts
16259
17230
  var BedrockProvider = class extends BaseProvider {
16260
17231
  constructor(config) {
16261
17232
  super();
16262
17233
  this.providerName = "bedrock";
17234
+ this.configureTransport(config);
16263
17235
  this.region = config.region;
16264
17236
  this.defaultModel = config.defaultModel ?? "anthropic.claude-sonnet-4-20250514-v1:0";
16265
17237
  this.defaultHeaders = config.defaultHeaders ?? {};
17238
+ this.thinkingMode = config.thinkingMode ?? "auto";
16266
17239
  this.promptCachingEnabled = config.prompt_caching?.enabled === true;
16267
17240
  if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
16268
17241
  this.credentials = {
@@ -16279,25 +17252,202 @@ var BedrockProvider = class extends BaseProvider {
16279
17252
  }
16280
17253
  async complete(request) {
16281
17254
  const modelId = request.model || this.defaultModel;
16282
- const body = this.buildConverseBody(request);
16283
- const json = await this.doFetch(modelId, body);
16284
- return this.parseResponse(json, modelId);
17255
+ const res = await this.converseFetch(modelId, request, false);
17256
+ return this.parseResponse(await res.json(), modelId);
16285
17257
  }
17258
+ /**
17259
+ * Real streaming over ConverseStream. The response is an AWS event-stream
17260
+ * (binary frames); each frame carries one JSON event: messageStart,
17261
+ * contentBlockStart/Delta/Stop (text, toolUse, reasoningContent),
17262
+ * messageStop and, last, metadata (usage). Text, tool-call argument and
17263
+ * reasoning deltas are yielded as they arrive; one closing chunk carries the
17264
+ * finish reason, usage and the signed reasoning blocks.
17265
+ */
16286
17266
  async *completeStream(request) {
16287
- const response = await this.complete(request);
17267
+ const modelId = request.model || this.defaultModel;
17268
+ const res = await this.converseFetch(modelId, request, true);
17269
+ if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
17270
+ const id = res.headers.get("x-amzn-requestid") ?? "";
17271
+ const toolsByIndex = /* @__PURE__ */ new Map();
17272
+ const reasoningByIndex = /* @__PURE__ */ new Map();
17273
+ let finishReason;
17274
+ let rawFinishReason;
17275
+ let toolOrdinal = 0;
17276
+ let usage;
17277
+ for await (const msg of parseEventStream(res.body, request.signal)) {
17278
+ const messageType = String(msg.headers[":message-type"] ?? "event");
17279
+ const eventType = String(msg.headers[":event-type"] ?? msg.headers[":exception-type"] ?? "");
17280
+ let data = {};
17281
+ const text = new TextDecoder().decode(msg.payload);
17282
+ if (text) {
17283
+ try {
17284
+ data = JSON.parse(text);
17285
+ } catch {
17286
+ data = { message: text };
17287
+ }
17288
+ }
17289
+ if (messageType === "exception" || messageType === "error") {
17290
+ const code = String(msg.headers[":exception-type"] ?? msg.headers[":error-code"] ?? eventType);
17291
+ throw new ProviderError(
17292
+ `Bedrock stream error ${code}: ${data.message ?? text}`,
17293
+ this.providerName,
17294
+ bedrockExceptionStatus(code),
17295
+ data
17296
+ );
17297
+ }
17298
+ switch (eventType) {
17299
+ case "contentBlockStart": {
17300
+ const idx = data.contentBlockIndex ?? 0;
17301
+ const tu = data.start?.toolUse;
17302
+ if (tu) {
17303
+ const ordinal = toolOrdinal++;
17304
+ toolsByIndex.set(idx, { id: tu.toolUseId ?? "", name: tu.name ?? "", ordinal });
17305
+ yield { id, model: modelId, delta: { toolCalls: [{ id: tu.toolUseId, name: tu.name, arguments: "", index: ordinal }] } };
17306
+ }
17307
+ break;
17308
+ }
17309
+ case "contentBlockDelta": {
17310
+ const idx = data.contentBlockIndex ?? 0;
17311
+ const d = data.delta ?? {};
17312
+ if (typeof d.text === "string" && d.text) {
17313
+ yield { id, model: modelId, delta: { content: d.text } };
17314
+ } else if (d.toolUse) {
17315
+ const tc = toolsByIndex.get(idx);
17316
+ if (tc && typeof d.toolUse.input === "string" && d.toolUse.input) {
17317
+ yield { id, model: modelId, delta: { toolCalls: [{ id: tc.id, name: tc.name, arguments: d.toolUse.input, index: tc.ordinal }] } };
17318
+ }
17319
+ } else if (d.reasoningContent) {
17320
+ const rc = d.reasoningContent;
17321
+ const blk = reasoningByIndex.get(idx) ?? { type: "thinking", text: "" };
17322
+ if (typeof rc.text === "string" && rc.text) {
17323
+ blk.text = (blk.text ?? "") + rc.text;
17324
+ reasoningByIndex.set(idx, blk);
17325
+ yield { id, model: modelId, delta: { reasoning: { summary: rc.text } } };
17326
+ }
17327
+ if (typeof rc.signature === "string" && rc.signature) {
17328
+ blk.signature = (blk.signature ?? "") + rc.signature;
17329
+ reasoningByIndex.set(idx, blk);
17330
+ }
17331
+ if (rc.redactedContent) {
17332
+ reasoningByIndex.set(idx, { type: "redacted_thinking", data: rc.redactedContent });
17333
+ }
17334
+ }
17335
+ break;
17336
+ }
17337
+ case "messageStop":
17338
+ finishReason = mapBedrockStopReason(data.stopReason);
17339
+ if (typeof data.stopReason === "string") rawFinishReason = data.stopReason;
17340
+ break;
17341
+ case "metadata": {
17342
+ const u = data.usage ?? {};
17343
+ usage = {
17344
+ inputTokens: u.inputTokens ?? 0,
17345
+ outputTokens: u.outputTokens ?? 0,
17346
+ totalTokens: u.totalTokens ?? (u.inputTokens ?? 0) + (u.outputTokens ?? 0),
17347
+ cachedInputTokens: u.cacheReadInputTokens ?? u.cacheReadInputTokenCount ?? 0,
17348
+ cachedWriteTokens: u.cacheWriteInputTokens ?? u.cacheWriteInputTokenCount ?? 0,
17349
+ cachedOutputTokens: 0,
17350
+ reasoningTokens: 0
17351
+ };
17352
+ break;
17353
+ }
17354
+ }
17355
+ }
17356
+ const blocks = [...reasoningByIndex.values()].filter(
17357
+ (b) => b.type === "thinking" && b.signature || b.type === "redacted_thinking" && b.data
17358
+ );
16288
17359
  yield {
16289
- id: response.id,
16290
- model: response.model,
16291
- delta: {
16292
- content: response.content ?? void 0,
16293
- toolCalls: response.toolCalls.length > 0 ? response.toolCalls : void 0
16294
- },
16295
- usage: response.usage,
16296
- finishReason: response.finishReason
17360
+ id,
17361
+ model: modelId,
17362
+ delta: blocks.length > 0 ? { reasoning: { blocks } } : {},
17363
+ finishReason: finishReason ?? "stop",
17364
+ ...rawFinishReason ? { rawFinishReason } : {},
17365
+ usage
16297
17366
  };
16298
17367
  }
17368
+ // ─── Embeddings ──────────────────────────────────────────────────────────
17369
+ /**
17370
+ * InvokeModel embeddings. Supported families (by model id, inference-profile
17371
+ * prefixes such as `us.` allowed):
17372
+ * - Amazon Titan Text Embeddings (v1, v2): one text per call, `dimensions`
17373
+ * (v2: 256/512/1024) and `normalize` via `extra`.
17374
+ * - Cohere Embed (v3, v4): a batch of texts per call (default 96), `inputType`
17375
+ * maps to `input_type`, `dimensions` to `output_dimension` (v4).
17376
+ */
17377
+ async embed(request) {
17378
+ const model = requireEmbeddingModel(this.providerName, request.model);
17379
+ const id = model.toLowerCase();
17380
+ const raw = [];
17381
+ let inputTokens = 0;
17382
+ let vectors = [];
17383
+ if (id.includes("titan-embed")) {
17384
+ const results = await mapWithConcurrency(request.input, 4, async (text) => {
17385
+ const body = { inputText: text };
17386
+ if (request.dimensions != null && !id.includes("titan-embed-text-v1")) body.dimensions = request.dimensions;
17387
+ if (request.extra) Object.assign(body, request.extra);
17388
+ const res = await this.invokeModel(model, body, request.signal);
17389
+ const json = await res.json();
17390
+ return { json, tokens: json.inputTextTokenCount ?? Number(res.headers.get("x-amzn-bedrock-input-token-count") ?? 0) };
17391
+ }, request.signal);
17392
+ for (const r of results) {
17393
+ raw.push(r.json);
17394
+ inputTokens += r.tokens || 0;
17395
+ vectors.push(r.json.embedding ?? r.json.embeddingsByType?.float);
17396
+ }
17397
+ } else if (id.includes("cohere.embed")) {
17398
+ for (const batch of chunkArray(request.input, request.batchSize ?? 96)) {
17399
+ const body = {
17400
+ texts: batch,
17401
+ input_type: request.inputType ?? "search_document",
17402
+ embedding_types: ["float"]
17403
+ };
17404
+ if (request.dimensions != null) body.output_dimension = request.dimensions;
17405
+ if (request.extra) Object.assign(body, request.extra);
17406
+ const res = await this.invokeModel(model, body, request.signal);
17407
+ const json = await res.json();
17408
+ raw.push(json);
17409
+ const emb = Array.isArray(json.embeddings) ? json.embeddings : json.embeddings?.float;
17410
+ vectors.push(...emb ?? []);
17411
+ inputTokens += Number(res.headers.get("x-amzn-bedrock-input-token-count") ?? 0) || 0;
17412
+ }
17413
+ } else {
17414
+ throw new ProviderError(
17415
+ `Bedrock embeddings are supported for Amazon Titan and Cohere Embed models, not "${model}"`,
17416
+ this.providerName,
17417
+ 400
17418
+ );
17419
+ }
17420
+ assertVectorCount(this.providerName, vectors, request.input.length);
17421
+ return { model, vectors, usage: { inputTokens, totalTokens: inputTokens }, raw };
17422
+ }
17423
+ async invokeModel(modelId, body, signal) {
17424
+ const host = `bedrock-runtime.${this.region}.amazonaws.com`;
17425
+ const url = `https://${host}/model/${encodeURIComponent(modelId)}/invoke`;
17426
+ const bodyStr = JSON.stringify(body);
17427
+ const res = await this.doFetchWithRetry(() => {
17428
+ const headers = signRequest({
17429
+ method: "POST",
17430
+ url,
17431
+ headers: {
17432
+ "Content-Type": "application/json",
17433
+ Accept: "application/json",
17434
+ ...this.defaultHeaders
17435
+ },
17436
+ body: bodyStr,
17437
+ region: this.region,
17438
+ service: "bedrock",
17439
+ credentials: this.credentials
17440
+ });
17441
+ return this.httpFetch(url, { method: "POST", headers, body: bodyStr, signal });
17442
+ }, signal);
17443
+ if (!res.ok) {
17444
+ const text = await res.text().catch(() => "");
17445
+ throw new ProviderError(`Bedrock API error ${res.status}: ${text}`, this.providerName, res.status, text);
17446
+ }
17447
+ return res;
17448
+ }
16299
17449
  // ─── Internals ───────────────────────────────────────────────────────────
16300
- buildConverseBody(request) {
17450
+ buildConverseBody(request, downgradeToolChoice = false) {
16301
17451
  const { system, messages } = this.splitSystemMessages(request.messages);
16302
17452
  const body = {
16303
17453
  messages: this.toBedrockMessages(messages)
@@ -16321,8 +17471,9 @@ var BedrockProvider = class extends BaseProvider {
16321
17471
  body.toolConfig = {
16322
17472
  tools
16323
17473
  };
17474
+ const forceOk = !downgradeToolChoice && supportsForcedToolChoice(request.model || this.defaultModel);
16324
17475
  if (request.toolChoice != null) {
16325
- if (request.toolChoice === "auto") {
17476
+ if (request.toolChoice === "auto" || !forceOk && request.toolChoice !== "none") {
16326
17477
  body.toolConfig.toolChoice = { auto: {} };
16327
17478
  } else if (request.toolChoice === "required") {
16328
17479
  body.toolConfig.toolChoice = { any: {} };
@@ -16332,9 +17483,17 @@ var BedrockProvider = class extends BaseProvider {
16332
17483
  }
16333
17484
  }
16334
17485
  if (request.extra) {
16335
- Object.assign(body, request.extra);
17486
+ const fields = { ...request.extra.additionalModelRequestFields ?? {} };
17487
+ const topLevel = { ...request.extra.__top ?? {} };
17488
+ for (const [key, value] of Object.entries(request.extra)) {
17489
+ if (key === "additionalModelRequestFields" || key === "__top") continue;
17490
+ if (CONVERSE_TOP_LEVEL_FIELDS.has(key)) body[key] = value;
17491
+ else fields[key] = value;
17492
+ }
17493
+ Object.assign(body, topLevel);
17494
+ if (Object.keys(fields).length > 0) body.additionalModelRequestFields = fields;
16336
17495
  }
16337
- applyBedrockReasoning(body, request.reasoning);
17496
+ applyBedrockReasoning(body, request.reasoning, { model: request.model || this.defaultModel, mode: this.thinkingMode });
16338
17497
  return body;
16339
17498
  }
16340
17499
  splitSystemMessages(messages) {
@@ -16457,9 +17616,22 @@ var BedrockProvider = class extends BaseProvider {
16457
17616
  }
16458
17617
  };
16459
17618
  }
16460
- async doFetch(modelId, body) {
17619
+ /** Sends the Converse call; retries once with toolChoice auto when the
17620
+ * model rejects forced tool use. */
17621
+ async converseFetch(modelId, request, stream) {
17622
+ const body = this.buildConverseBody(request);
17623
+ try {
17624
+ return await this.doFetch(modelId, body, request.signal, stream);
17625
+ } catch (err) {
17626
+ const tc = body.toolConfig?.toolChoice;
17627
+ if (!(err instanceof ProviderError) || err.statusCode !== 400 || !tc || tc.auto) throw err;
17628
+ if (!forcedToolChoiceRejected(String(err.responseBody ?? err.message))) throw err;
17629
+ return this.doFetch(modelId, this.buildConverseBody(request, true), request.signal, stream);
17630
+ }
17631
+ }
17632
+ async doFetch(modelId, body, signal, stream) {
16461
17633
  const host = `bedrock-runtime.${this.region}.amazonaws.com`;
16462
- const url = `https://${host}/model/${encodeURIComponent(modelId)}/converse`;
17634
+ const url = `https://${host}/model/${encodeURIComponent(modelId)}/${stream ? "converse-stream" : "converse"}`;
16463
17635
  const bodyStr = JSON.stringify(body);
16464
17636
  const res = await this.doFetchWithRetry(() => {
16465
17637
  const headers = signRequest({
@@ -16467,7 +17639,7 @@ var BedrockProvider = class extends BaseProvider {
16467
17639
  url,
16468
17640
  headers: {
16469
17641
  "Content-Type": "application/json",
16470
- Accept: "application/json",
17642
+ Accept: stream ? "application/vnd.amazon.eventstream" : "application/json",
16471
17643
  ...this.defaultHeaders
16472
17644
  },
16473
17645
  body: bodyStr,
@@ -16475,8 +17647,8 @@ var BedrockProvider = class extends BaseProvider {
16475
17647
  service: "bedrock",
16476
17648
  credentials: this.credentials
16477
17649
  });
16478
- return fetch(url, { method: "POST", headers, body: bodyStr });
16479
- });
17650
+ return this.httpFetch(url, { method: "POST", headers, body: bodyStr, signal });
17651
+ }, signal);
16480
17652
  if (!res.ok) {
16481
17653
  const text = await res.text().catch(() => "");
16482
17654
  throw new ProviderError(
@@ -16486,7 +17658,7 @@ var BedrockProvider = class extends BaseProvider {
16486
17658
  text
16487
17659
  );
16488
17660
  }
16489
- return res.json();
17661
+ return res;
16490
17662
  }
16491
17663
  parseResponse(json, modelId) {
16492
17664
  const output = json.output?.message;
@@ -16522,8 +17694,8 @@ var BedrockProvider = class extends BaseProvider {
16522
17694
  inputTokens: usage.inputTokens ?? 0,
16523
17695
  outputTokens: usage.outputTokens ?? 0,
16524
17696
  totalTokens: usage.totalTokens ?? (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0),
16525
- cachedInputTokens: usage.cacheReadInputTokenCount ?? 0,
16526
- cachedWriteTokens: usage.cacheWriteInputTokenCount ?? 0,
17697
+ cachedInputTokens: usage.cacheReadInputTokens ?? usage.cacheReadInputTokenCount ?? 0,
17698
+ cachedWriteTokens: usage.cacheWriteInputTokens ?? usage.cacheWriteInputTokenCount ?? 0,
16527
17699
  cachedOutputTokens: 0,
16528
17700
  // Bedrock bills thinking tokens inside outputTokens; no separate count.
16529
17701
  reasoningTokens: 0
@@ -16535,11 +17707,26 @@ var BedrockProvider = class extends BaseProvider {
16535
17707
  toolCalls,
16536
17708
  usage: tokenUsage,
16537
17709
  finishReason: mapBedrockStopReason(json.stopReason),
17710
+ ...typeof json.stopReason === "string" ? { rawFinishReason: json.stopReason } : {},
16538
17711
  reasoning: reasoningBlocks.length > 0 ? { blocks: reasoningBlocks, summary: summaryParts.join("\n").trim() || void 0 } : void 0,
16539
17712
  raw: json
16540
17713
  };
16541
17714
  }
16542
17715
  };
17716
+ var CONVERSE_TOP_LEVEL_FIELDS = /* @__PURE__ */ new Set([
17717
+ "messages",
17718
+ "system",
17719
+ "inferenceConfig",
17720
+ "toolConfig",
17721
+ "guardrailConfig",
17722
+ "additionalModelRequestFields",
17723
+ "additionalModelResponseFieldPaths",
17724
+ "promptVariables",
17725
+ "requestMetadata",
17726
+ "performanceConfig",
17727
+ "serviceTier",
17728
+ "outputConfig"
17729
+ ]);
16543
17730
  function appendBedrockReasoning(content, blocks) {
16544
17731
  if (!blocks?.length) return;
16545
17732
  for (const b of blocks) {
@@ -16554,6 +17741,23 @@ function appendBedrockReasoning(content, blocks) {
16554
17741
  }
16555
17742
  }
16556
17743
  }
17744
+ function bedrockExceptionStatus(code) {
17745
+ switch (code) {
17746
+ case "throttlingException":
17747
+ return 429;
17748
+ case "validationException":
17749
+ return 400;
17750
+ case "modelTimeoutException":
17751
+ return 408;
17752
+ case "serviceUnavailableException":
17753
+ return 503;
17754
+ case "internalServerException":
17755
+ case "modelStreamErrorException":
17756
+ return 500;
17757
+ default:
17758
+ return void 0;
17759
+ }
17760
+ }
16557
17761
  function mapBedrockStopReason(reason) {
16558
17762
  switch (reason) {
16559
17763
  case "end_turn":
@@ -16562,8 +17766,10 @@ function mapBedrockStopReason(reason) {
16562
17766
  case "tool_use":
16563
17767
  return "tool_calls";
16564
17768
  case "max_tokens":
17769
+ case "model_context_window_exceeded":
16565
17770
  return "length";
16566
17771
  case "content_filtered":
17772
+ case "guardrail_intervened":
16567
17773
  case "guardrail":
16568
17774
  return "content_filter";
16569
17775
  default:
@@ -16593,10 +17799,12 @@ var VertexProvider = class extends BaseProvider {
16593
17799
  super();
16594
17800
  this.providerName = "vertex";
16595
17801
  this.tokenExpiry = 0;
17802
+ this.configureTransport(config);
16596
17803
  this.projectId = config.projectId;
16597
17804
  this.location = config.location ?? "us-central1";
16598
17805
  this.defaultModel = config.defaultModel ?? "gemini-2.0-flash";
16599
17806
  this.defaultHeaders = config.defaultHeaders ?? {};
17807
+ if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
16600
17808
  if (config.accessToken) {
16601
17809
  this.accessToken = config.accessToken;
16602
17810
  this.tokenExpiry = Date.now() + 36e5;
@@ -16609,7 +17817,7 @@ var VertexProvider = class extends BaseProvider {
16609
17817
  const modelId = request.model || this.defaultModel;
16610
17818
  const body = this.buildGeminiBody(request);
16611
17819
  const url = this.buildUrl(modelId, false);
16612
- const res = await this.doFetch(url, body);
17820
+ const res = await this.doFetch(url, body, request.signal);
16613
17821
  const json = await res.json();
16614
17822
  return this.parseResponse(json, modelId);
16615
17823
  }
@@ -16617,11 +17825,12 @@ var VertexProvider = class extends BaseProvider {
16617
17825
  const modelId = request.model || this.defaultModel;
16618
17826
  const body = this.buildGeminiBody(request);
16619
17827
  const url = this.buildUrl(modelId, true);
16620
- const res = await this.doFetch(url, body);
17828
+ const res = await this.doFetch(url, body, request.signal);
16621
17829
  if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
17830
+ const counter = { next: 0 };
16622
17831
  const contentType = res.headers.get("content-type") ?? "";
16623
17832
  if (contentType.includes("text/event-stream")) {
16624
- for await (const event of parseSSEStream(res.body)) {
17833
+ for await (const event of parseSSEStream(res.body, request.signal)) {
16625
17834
  if (event.data === "[DONE]") break;
16626
17835
  let chunk;
16627
17836
  try {
@@ -16629,7 +17838,7 @@ var VertexProvider = class extends BaseProvider {
16629
17838
  } catch {
16630
17839
  continue;
16631
17840
  }
16632
- yield this.parseStreamChunk(chunk, modelId);
17841
+ yield this.parseStreamChunk(chunk, modelId, counter);
16633
17842
  }
16634
17843
  } else {
16635
17844
  const reader = res.body.getReader();
@@ -16647,7 +17856,7 @@ var VertexProvider = class extends BaseProvider {
16647
17856
  if (!trimmed || trimmed === "[" || trimmed === "]") continue;
16648
17857
  try {
16649
17858
  const chunk = JSON.parse(trimmed);
16650
- yield this.parseStreamChunk(chunk, modelId);
17859
+ yield this.parseStreamChunk(chunk, modelId, counter);
16651
17860
  } catch {
16652
17861
  buffer = line + "\n" + buffer;
16653
17862
  break;
@@ -16658,16 +17867,59 @@ var VertexProvider = class extends BaseProvider {
16658
17867
  if (remaining && remaining !== "[" && remaining !== "]") {
16659
17868
  try {
16660
17869
  const chunk = JSON.parse(remaining);
16661
- yield this.parseStreamChunk(chunk, modelId);
17870
+ yield this.parseStreamChunk(chunk, modelId, counter);
16662
17871
  } catch {
16663
17872
  }
16664
17873
  }
16665
17874
  } finally {
17875
+ reader.cancel().catch(() => void 0);
16666
17876
  reader.releaseLock();
16667
17877
  }
16668
17878
  }
16669
17879
  }
16670
17880
  // ─── Internals ───────────────────────────────────────────────────────────
17881
+ /**
17882
+ * Vertex `:predict` embeddings (text-embedding-00x, text-multilingual-embedding,
17883
+ * gemini-embedding-001). `inputType` maps to the task type; `dimensions` to
17884
+ * `outputDimensionality`. gemini-embedding takes one instance per request, the
17885
+ * text-embedding models up to `batchSize` (default 100).
17886
+ */
17887
+ async embed(request) {
17888
+ const model = requireEmbeddingModel(this.providerName, request.model);
17889
+ const perRequest = request.batchSize ?? (/gemini-embedding/i.test(model) ? 1 : 100);
17890
+ const url = `https://${this.location}-aiplatform.googleapis.com/v1/projects/${this.projectId}/locations/${this.location}/publishers/google/models/${model}:predict`;
17891
+ const taskType = request.inputType ? Object.prototype.hasOwnProperty.call(GEMINI_TASK_TYPES, request.inputType) ? GEMINI_TASK_TYPES[request.inputType] : request.inputType.toUpperCase() : void 0;
17892
+ const vectors = [];
17893
+ const raw = [];
17894
+ let inputTokens = 0;
17895
+ for (const batch of chunkArray(request.input, perRequest)) {
17896
+ const body = {
17897
+ instances: batch.map((content) => ({ content, ...taskType ? { task_type: taskType } : {} }))
17898
+ };
17899
+ const { parameters: extraParameters, ...extraRest } = request.extra ?? {};
17900
+ const parameters = {
17901
+ ...request.dimensions != null ? { outputDimensionality: request.dimensions } : {},
17902
+ // Caller-supplied parameters are merged in, not replacing the above (an
17903
+ // explicit extra.parameters.outputDimensionality still wins).
17904
+ ...extraParameters && typeof extraParameters === "object" ? extraParameters : {}
17905
+ };
17906
+ if (Object.keys(parameters).length > 0) body.parameters = parameters;
17907
+ Object.assign(body, extraRest);
17908
+ const res = await this.doFetch(url, body, request.signal);
17909
+ const json = await res.json();
17910
+ raw.push(json);
17911
+ for (const p of json.predictions ?? []) {
17912
+ const values = p.embeddings?.values;
17913
+ if (!Array.isArray(values)) {
17914
+ throw new ProviderError("Vertex embeddings response has a prediction without an embeddings.values array", this.providerName, void 0, json);
17915
+ }
17916
+ vectors.push(values);
17917
+ inputTokens += p.embeddings?.statistics?.token_count ?? 0;
17918
+ }
17919
+ }
17920
+ assertVectorCount(this.providerName, vectors, request.input.length);
17921
+ return { model, vectors, usage: { inputTokens, totalTokens: inputTokens }, raw };
17922
+ }
16671
17923
  buildUrl(modelId, stream) {
16672
17924
  const base = `https://${this.location}-aiplatform.googleapis.com/v1`;
16673
17925
  const path2 = `projects/${this.projectId}/locations/${this.location}/publishers/google/models/${modelId}`;
@@ -16765,7 +18017,9 @@ var VertexProvider = class extends BaseProvider {
16765
18017
  functionCall: {
16766
18018
  name: tc.name,
16767
18019
  args: safeJsonParse3(tc.arguments)
16768
- }
18020
+ },
18021
+ // Gemini 3 requires the signature of each functionCall echoed back.
18022
+ ...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {}
16769
18023
  });
16770
18024
  }
16771
18025
  return { role: "model", parts: parts2 };
@@ -16862,7 +18116,7 @@ var VertexProvider = class extends BaseProvider {
16862
18116
  sign.update(signingInput);
16863
18117
  const signature = sign.sign(sa.private_key, "base64url");
16864
18118
  const jwt = `${signingInput}.${signature}`;
16865
- const tokenRes = await fetch("https://oauth2.googleapis.com/token", {
18119
+ const tokenRes = await this.httpFetch("https://oauth2.googleapis.com/token", {
16866
18120
  method: "POST",
16867
18121
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
16868
18122
  body: `grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=${jwt}`
@@ -16874,17 +18128,22 @@ var VertexProvider = class extends BaseProvider {
16874
18128
  const tokenJson = await tokenRes.json();
16875
18129
  return tokenJson.access_token;
16876
18130
  }
16877
- async doFetch(url, body) {
18131
+ async doFetch(url, body, signal) {
16878
18132
  const token = await this.getAccessToken();
16879
- const res = await fetch(url, {
16880
- method: "POST",
16881
- headers: {
16882
- "Content-Type": "application/json",
16883
- Authorization: `Bearer ${token}`,
16884
- ...this.defaultHeaders
16885
- },
16886
- body: JSON.stringify(body)
16887
- });
18133
+ const bodyStr = JSON.stringify(body);
18134
+ const res = await this.doFetchWithRetry(
18135
+ () => this.httpFetch(url, {
18136
+ method: "POST",
18137
+ headers: {
18138
+ "Content-Type": "application/json",
18139
+ Authorization: `Bearer ${token}`,
18140
+ ...this.defaultHeaders
18141
+ },
18142
+ body: bodyStr,
18143
+ signal
18144
+ }),
18145
+ signal
18146
+ );
16888
18147
  if (!res.ok) {
16889
18148
  const text = await res.text().catch(() => "");
16890
18149
  throw new ProviderError(
@@ -16914,7 +18173,8 @@ var VertexProvider = class extends BaseProvider {
16914
18173
  toolCalls.push({
16915
18174
  id: `call_${toolCallIdx++}`,
16916
18175
  name: part.functionCall.name,
16917
- arguments: JSON.stringify(part.functionCall.args ?? {})
18176
+ arguments: JSON.stringify(part.functionCall.args ?? {}),
18177
+ ...part.thoughtSignature ? { thoughtSignature: part.thoughtSignature } : {}
16918
18178
  });
16919
18179
  }
16920
18180
  }
@@ -16935,11 +18195,12 @@ var VertexProvider = class extends BaseProvider {
16935
18195
  toolCalls,
16936
18196
  usage: tokenUsage,
16937
18197
  finishReason: mapGeminiFinishReason(candidate?.finishReason),
18198
+ ...typeof candidate?.finishReason === "string" ? { rawFinishReason: candidate.finishReason } : {},
16938
18199
  reasoning: thoughtParts.length > 0 ? { summary: thoughtParts.join("\n").trim() || void 0 } : void 0,
16939
18200
  raw: json
16940
18201
  };
16941
18202
  }
16942
- parseStreamChunk(chunk, modelId) {
18203
+ parseStreamChunk(chunk, modelId, counter) {
16943
18204
  const candidate = chunk.candidates?.[0];
16944
18205
  const parts = candidate?.content?.parts ?? [];
16945
18206
  const delta = {};
@@ -16953,9 +18214,12 @@ var VertexProvider = class extends BaseProvider {
16953
18214
  } else if (part.functionCall) {
16954
18215
  if (!delta.toolCalls) delta.toolCalls = [];
16955
18216
  delta.toolCalls.push({
16956
- id: `call_${delta.toolCalls.length}`,
18217
+ // Unique across the whole stream: the adapter merges chunks by id.
18218
+ id: `call_${counter.next}`,
18219
+ index: counter.next++,
16957
18220
  name: part.functionCall.name,
16958
- arguments: JSON.stringify(part.functionCall.args ?? {})
18221
+ arguments: JSON.stringify(part.functionCall.args ?? {}),
18222
+ ...part.thoughtSignature ? { thoughtSignature: part.thoughtSignature } : {}
16959
18223
  });
16960
18224
  }
16961
18225
  }
@@ -16977,10 +18241,21 @@ var VertexProvider = class extends BaseProvider {
16977
18241
  model: modelId,
16978
18242
  delta,
16979
18243
  usage,
16980
- finishReason: mapGeminiFinishReason(candidate?.finishReason)
18244
+ finishReason: mapGeminiFinishReason(candidate?.finishReason),
18245
+ ...typeof candidate?.finishReason === "string" ? { rawFinishReason: candidate.finishReason } : {}
16981
18246
  };
16982
18247
  }
16983
18248
  };
18249
+ var GEMINI_TASK_TYPES = {
18250
+ search_document: "RETRIEVAL_DOCUMENT",
18251
+ search_query: "RETRIEVAL_QUERY",
18252
+ classification: "CLASSIFICATION",
18253
+ clustering: "CLUSTERING",
18254
+ semantic_similarity: "SEMANTIC_SIMILARITY",
18255
+ question_answering: "QUESTION_ANSWERING",
18256
+ fact_verification: "FACT_VERIFICATION",
18257
+ code_retrieval_query: "CODE_RETRIEVAL_QUERY"
18258
+ };
16984
18259
  function mapGeminiFinishReason(reason) {
16985
18260
  switch (reason) {
16986
18261
  case "STOP":
@@ -17022,6 +18297,8 @@ function createProvider(config) {
17022
18297
  return new BedrockProvider(config);
17023
18298
  case "vertex":
17024
18299
  return new VertexProvider(config);
18300
+ case "jev":
18301
+ return new JevProvider(config);
17025
18302
  default:
17026
18303
  throw new Error(`Unknown provider: ${config.provider}`);
17027
18304
  }
@@ -17049,6 +18326,7 @@ exports.HOOK_CONTRACT_VERSION = HOOK_CONTRACT_VERSION;
17049
18326
  exports.HOOK_NAMES = HOOK_NAMES;
17050
18327
  exports.HookTimeoutError = HookTimeoutError;
17051
18328
  exports.InMemoryMemoryStore = InMemoryMemoryStore;
18329
+ exports.JevProvider = JevProvider;
17052
18330
  exports.NativeJsonSchemaStrategy = NativeJsonSchemaStrategy;
17053
18331
  exports.OpenAICompatibleProvider = OpenAICompatibleProvider;
17054
18332
  exports.OpenAIProvider = OpenAIProvider;
@@ -17088,6 +18366,7 @@ exports.compressLogOutput = compressLogOutput;
17088
18366
  exports.compressSearchOutput = compressSearchOutput;
17089
18367
  exports.compressTextOutput = compressTextOutput;
17090
18368
  exports.compressToolOutput = compressToolOutput;
18369
+ exports.contentPartToText = contentPartToText;
17091
18370
  exports.contentToString = contentToString;
17092
18371
  exports.conversationHistory = conversationHistory;
17093
18372
  exports.countApproxTokens = countApproxTokens;
@@ -17130,6 +18409,7 @@ exports.dedupeToolsByName = dedupeToolsByName;
17130
18409
  exports.defaultTokenCounter = defaultTokenCounter;
17131
18410
  exports.defineHook = defineHook;
17132
18411
  exports.definePlugin = definePlugin;
18412
+ exports.describeContentPart = describeContentPart;
17133
18413
  exports.detectLanguage = detectLanguage;
17134
18414
  exports.detectTextFormat = detectTextFormat;
17135
18415
  exports.detectVolatileContent = detectVolatileContent;
@@ -17138,7 +18418,7 @@ exports.digestToolInputValue = digestToolInputValue;
17138
18418
  exports.emptyUsage = emptyUsage;
17139
18419
  exports.evaluateGuardrails = evaluateGuardrails;
17140
18420
  exports.extractLatestUserQuery = extractLatestUserQuery;
17141
- exports.extractMessageText = extractMessageText2;
18421
+ exports.extractMessageText = extractMessageText;
17142
18422
  exports.fileCheckpointStore = fileCheckpointStore;
17143
18423
  exports.fileSink = fileSink;
17144
18424
  exports.findSubagent = findSubagent;
@@ -17152,6 +18432,7 @@ exports.getModelCapabilities = getModelCapabilities;
17152
18432
  exports.getNestedValue = getNestedValue;
17153
18433
  exports.getResolvedSmartConfig = getResolvedSmartConfig;
17154
18434
  exports.getTokenCounter = getTokenCounter;
18435
+ exports.hasMediaPart = hasMediaPart;
17155
18436
  exports.hasToolResponseRecoveryReference = hasToolResponseRecoveryReference;
17156
18437
  exports.httpGuardrail = httpGuardrail;
17157
18438
  exports.httpSink = httpSink;
@@ -17171,6 +18452,7 @@ exports.loadSkillsFromDisk = loadSkillsFromDisk;
17171
18452
  exports.mapConsoleHookVerdict = mapConsoleHookVerdict;
17172
18453
  exports.mapTextParts = mapTextParts;
17173
18454
  exports.mcp = mcp;
18455
+ exports.mediaKindOf = mediaKindOf;
17174
18456
  exports.mediaPolicy = mediaPolicy;
17175
18457
  exports.normalizeSmartAgentOptions = normalizeSmartAgentOptions;
17176
18458
  exports.normalizeVerdicts = normalizeVerdicts;
@@ -17217,7 +18499,9 @@ exports.sessionMetrics = sessionMetrics;
17217
18499
  exports.setTokenCounter = setTokenCounter;
17218
18500
  exports.startStreamingSession = startStreamingSession;
17219
18501
  exports.summarizeObject = summarizeObject;
18502
+ exports.supportsAdaptiveThinking = supportsAdaptiveThinking;
17220
18503
  exports.textFromContent = textFromContent;
18504
+ exports.toMessageUsage = toMessageUsage;
17221
18505
  exports.toStrictCompatible = toStrictCompatible;
17222
18506
  exports.toStrictToolSchema = toStrictToolSchema;
17223
18507
  exports.tokenize = tokenize;