@cognipeer/agent-sdk 0.10.5 → 0.10.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -18,6 +18,238 @@ var __export = (target, all) => {
18
18
  __defProp(target, name, { get: all[name], enumerable: true });
19
19
  };
20
20
 
21
+ // src/utils/content.ts
22
+ function isRecord(value) {
23
+ return value !== null && typeof value === "object" && !Array.isArray(value);
24
+ }
25
+ function nonEmpty(value) {
26
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
27
+ }
28
+ function kindFromMediaType(mediaType) {
29
+ const top = mediaType?.split("/")[0];
30
+ return top === "image" || top === "audio" || top === "video" ? top : "file";
31
+ }
32
+ function inlineDataOf(part) {
33
+ const inline = part.inlineData ?? part.inline_data ?? part.fileData ?? part.file_data;
34
+ return isRecord(inline) ? inline : void 0;
35
+ }
36
+ function mediaKindOf(part) {
37
+ if (!isRecord(part)) return void 0;
38
+ const type = nonEmpty(part.type);
39
+ if (type) return MEDIA_PART_KINDS[type];
40
+ const inline = inlineDataOf(part);
41
+ if (inline) return kindFromMediaType(nonEmpty(inline.mimeType) ?? nonEmpty(inline.mime_type));
42
+ return void 0;
43
+ }
44
+ function hasMediaPart(content) {
45
+ return Array.isArray(content) && content.some((part) => mediaKindOf(part) !== void 0);
46
+ }
47
+ function urlOfPart(part) {
48
+ const image = part.image_url;
49
+ const video = part.video_url;
50
+ 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);
51
+ }
52
+ function mediaTypeOfPart(part) {
53
+ const image = isRecord(part.image_url) ? part.image_url : void 0;
54
+ const source = isRecord(part.source) ? part.source : void 0;
55
+ const inline = inlineDataOf(part);
56
+ const audioFormat = nonEmpty(part.input_audio?.format);
57
+ const fromDataUrl = /^data:([^;,]+)/i.exec(urlOfPart(part) ?? "")?.[1];
58
+ 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);
59
+ }
60
+ function nameOfPart(part) {
61
+ const file = isRecord(part.file) ? part.file : void 0;
62
+ const image = isRecord(part.image_url) ? part.image_url : void 0;
63
+ const source = isRecord(part.source) ? part.source : void 0;
64
+ 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);
65
+ }
66
+ function labelFromUrl(url) {
67
+ if (!url || url.startsWith("data:")) return void 0;
68
+ try {
69
+ const parsed = new URL(url);
70
+ if (parsed.protocol === "session-file:") return nonEmpty(parsed.hostname) ?? nonEmpty(parsed.pathname.replace(/^\/+/, ""));
71
+ if (parsed.protocol === "http:" || parsed.protocol === "https:") {
72
+ return nonEmpty(decodeURIComponent(parsed.pathname.split("/").filter(Boolean).pop() ?? ""));
73
+ }
74
+ } catch {
75
+ }
76
+ return void 0;
77
+ }
78
+ function describeContentPart(part) {
79
+ const kind = mediaKindOf(part);
80
+ if (!kind || !isRecord(part)) return void 0;
81
+ const label = nameOfPart(part) ?? mediaTypeOfPart(part) ?? labelFromUrl(urlOfPart(part));
82
+ if (!label) return `[${kind}]`;
83
+ const clean = label.replace(/[\r\n\]]+/g, " ").slice(0, PLACEHOLDER_LABEL_MAX);
84
+ return `[${kind}: ${clean}]`;
85
+ }
86
+ function contentPartToText(part, fallback) {
87
+ if (typeof part === "string") return part;
88
+ if (!isRecord(part)) return part == null ? "" : String(part);
89
+ const media = describeContentPart(part);
90
+ if (media) return media;
91
+ if (typeof part.text === "string") return part.text;
92
+ if (typeof part.content === "string") return part.content;
93
+ if (fallback) return fallback(part);
94
+ try {
95
+ return JSON.stringify(part);
96
+ } catch {
97
+ return String(part);
98
+ }
99
+ }
100
+ function contentToString(content) {
101
+ try {
102
+ if (content == null) return "";
103
+ if (typeof content === "string") return content;
104
+ if (Array.isArray(content)) {
105
+ return content.map((p) => {
106
+ if (!p || typeof p !== "object") return String(p);
107
+ if (p.type === "text") return String(p.text ?? "");
108
+ if (p.type === "image_url") {
109
+ const img = p.image_url;
110
+ const url = typeof img === "string" ? img : img?.url;
111
+ if (typeof url === "string" && /^https?:\/\//i.test(url)) {
112
+ const detail = typeof img === "string" ? void 0 : img?.detail;
113
+ return `[image:${url}${detail ? ` detail=${detail}` : ""}]`;
114
+ }
115
+ return describeContentPart(p) ?? "[image]";
116
+ }
117
+ const media = describeContentPart(p);
118
+ if (media) return media;
119
+ return JSON.stringify(p);
120
+ }).join("\n");
121
+ }
122
+ return describeContentPart(content) ?? JSON.stringify(content);
123
+ } catch {
124
+ return String(content);
125
+ }
126
+ }
127
+ function mergeContentsToString(contents) {
128
+ return contents.map((c) => contentToString(c)).join("\n");
129
+ }
130
+ function safeStringify(value, pretty = false) {
131
+ if (value == null) return "";
132
+ if (typeof value === "string") return value;
133
+ try {
134
+ return JSON.stringify(value, null, pretty ? 2 : void 0) ?? String(value);
135
+ } catch {
136
+ return String(value);
137
+ }
138
+ }
139
+ function extractMessageText(message) {
140
+ if (!message) return "";
141
+ const content = message.content;
142
+ if (typeof content === "string") return content;
143
+ if (Array.isArray(content)) {
144
+ return content.map((part) => typeof part === "string" ? part : part?.text ?? part?.content ?? "").join("");
145
+ }
146
+ return "";
147
+ }
148
+ function textFromContent(content) {
149
+ if (typeof content === "string") return content;
150
+ if (!Array.isArray(content)) return "";
151
+ return content.filter((part) => isTextPart(part)).map((part) => part.text ?? "").join("\n");
152
+ }
153
+ function isTextPart(part) {
154
+ return !!part && typeof part === "object" && part.type === "text";
155
+ }
156
+ function mapTextParts(content, fn) {
157
+ if (typeof content === "string") return fn(content);
158
+ if (!Array.isArray(content)) return content;
159
+ return content.map((part) => isTextPart(part) ? { ...part, text: fn(part.text) } : part);
160
+ }
161
+ function replaceTextContent(content, text) {
162
+ if (typeof content === "string" || content == null) return text;
163
+ if (!Array.isArray(content)) return text;
164
+ const textIndexes = content.reduce((acc, part, index) => {
165
+ if (isTextPart(part)) acc.push(index);
166
+ return acc;
167
+ }, []);
168
+ if (textIndexes.length === 0) {
169
+ return text.length > 0 ? [{ type: "text", text }, ...content] : content;
170
+ }
171
+ const [first, ...rest] = textIndexes;
172
+ const dropped = new Set(rest);
173
+ return content.map((part, index) => index === first ? { ...part, text } : part).filter((_part, index) => !dropped.has(index));
174
+ }
175
+ function normalizeSource(source) {
176
+ if (!source || typeof source !== "object") return {};
177
+ const src = source;
178
+ if (src.type === "base64" && typeof src.data === "string") {
179
+ return {
180
+ sourceType: "base64",
181
+ mediaType: typeof src.mediaType === "string" ? src.mediaType : void 0,
182
+ // base64 encodes 3 bytes per 4 characters; padding makes this an upper bound.
183
+ approxBytes: Math.floor(src.data.length * 3 / 4)
184
+ };
185
+ }
186
+ if (src.type === "url" && typeof src.url === "string") {
187
+ return {
188
+ sourceType: "url",
189
+ url: src.url,
190
+ mediaType: typeof src.mediaType === "string" ? src.mediaType : void 0
191
+ };
192
+ }
193
+ return {};
194
+ }
195
+ function collectAttachments(content) {
196
+ if (!Array.isArray(content)) return [];
197
+ const attachments = [];
198
+ content.forEach((part, index) => {
199
+ if (!part || typeof part !== "object") return;
200
+ const type = part.type;
201
+ if (!type || type === "text") return;
202
+ if (type === "image" || type === "audio" || type === "video" || type === "file") {
203
+ attachments.push({
204
+ index,
205
+ kind: type,
206
+ fileName: typeof part.fileName === "string" ? part.fileName : void 0,
207
+ ...normalizeSource(part.source)
208
+ });
209
+ return;
210
+ }
211
+ if (type === "image_url") {
212
+ const image = part.image_url;
213
+ const url = typeof image === "string" ? image : image?.url;
214
+ if (typeof url === "string" && url.startsWith("data:")) {
215
+ const comma = url.indexOf(",");
216
+ const header = url.slice(5, comma);
217
+ attachments.push({
218
+ index,
219
+ kind: "image",
220
+ sourceType: "base64",
221
+ mediaType: header.split(";")[0] || void 0,
222
+ approxBytes: Math.floor((url.length - comma - 1) * 3 / 4)
223
+ });
224
+ } else {
225
+ attachments.push({ index, kind: "image", sourceType: "url", url });
226
+ }
227
+ return;
228
+ }
229
+ attachments.push({ index, kind: "unknown" });
230
+ });
231
+ return attachments;
232
+ }
233
+ var MEDIA_PART_KINDS, PLACEHOLDER_LABEL_MAX;
234
+ var init_content = __esm({
235
+ "src/utils/content.ts"() {
236
+ MEDIA_PART_KINDS = {
237
+ image: "image",
238
+ image_url: "image",
239
+ input_image: "image",
240
+ image_file: "image",
241
+ audio: "audio",
242
+ input_audio: "audio",
243
+ video: "video",
244
+ video_url: "video",
245
+ file: "file",
246
+ input_file: "file",
247
+ document: "file"
248
+ };
249
+ PLACEHOLDER_LABEL_MAX = 80;
250
+ }
251
+ });
252
+
21
253
  // src/utils/utilTokens.ts
22
254
  var utilTokens_exports = {};
23
255
  __export(utilTokens_exports, {
@@ -42,7 +274,7 @@ function getTokenCounter() {
42
274
  function countApproxTokens(text) {
43
275
  return activeTokenCounter(text || "");
44
276
  }
45
- function extractMessageText(m) {
277
+ function extractMessageText2(m) {
46
278
  if (!m) return "";
47
279
  const parts = [];
48
280
  parts.push(m.role || "");
@@ -52,6 +284,7 @@ function extractMessageText(m) {
52
284
  } else if (Array.isArray(m.content)) {
53
285
  for (const c of m.content) {
54
286
  if (typeof c === "string") parts.push(c);
287
+ else if (describeContentPart(c)) parts.push(describeContentPart(c));
55
288
  else if (c?.text) parts.push(c.text);
56
289
  else if (c?.content) parts.push(c.content);
57
290
  else if (c?.type === "tool_use" && c?.input) {
@@ -62,7 +295,7 @@ function extractMessageText(m) {
62
295
  }
63
296
  }
64
297
  } else if (m.content != null && typeof m.content === "object") {
65
- parts.push(JSON.stringify(m.content));
298
+ parts.push(describeContentPart(m.content) ?? JSON.stringify(m.content));
66
299
  }
67
300
  if (Array.isArray(m.tool_calls)) {
68
301
  for (const tc of m.tool_calls) {
@@ -92,12 +325,13 @@ function extractMessageText(m) {
92
325
  }
93
326
  function countMessagesTokens(messages) {
94
327
  if (!Array.isArray(messages) || messages.length === 0) return 0;
95
- const allText = messages.map(extractMessageText).join("\n");
328
+ const allText = messages.map(extractMessageText2).join("\n");
96
329
  return countApproxTokens(allText) + messages.length * 4;
97
330
  }
98
331
  var activeTokenCounter;
99
332
  var init_utilTokens = __esm({
100
333
  "src/utils/utilTokens.ts"() {
334
+ init_content();
101
335
  activeTokenCounter = defaultTokenCounter;
102
336
  }
103
337
  });
@@ -558,6 +792,125 @@ function isOpenAIHostedEndpoint(lcModel) {
558
792
  }
559
793
  }
560
794
 
795
+ // src/utils/abort.ts
796
+ var POLL_INTERVAL_MS = 100;
797
+ var NOOP = () => void 0;
798
+ function isObject(value) {
799
+ return value !== null && typeof value === "object";
800
+ }
801
+ function isRealSignal(value) {
802
+ return typeof AbortSignal !== "undefined" && value instanceof AbortSignal;
803
+ }
804
+ function isCancellationRequested(source) {
805
+ if (!source) return false;
806
+ for (const candidate of [source.signal, source.cancellationToken]) {
807
+ if (!isObject(candidate)) continue;
808
+ if (candidate.aborted === true || candidate.isCancellationRequested === true) return true;
809
+ }
810
+ return false;
811
+ }
812
+ function linkAbortSignal(source) {
813
+ if (!source) return { signal: void 0, dispose: NOOP };
814
+ const candidates = [];
815
+ for (const candidate of [source.signal, source.cancellationToken]) {
816
+ if (isObject(candidate) && !candidates.includes(candidate)) candidates.push(candidate);
817
+ }
818
+ if (candidates.length === 0) return { signal: void 0, dispose: NOOP };
819
+ const real = candidates.filter(isRealSignal);
820
+ if (candidates.length === 1 && real.length === 1) {
821
+ return { signal: real[0], dispose: NOOP };
822
+ }
823
+ const controller = new AbortController();
824
+ const cleanups = [];
825
+ let polled = [];
826
+ let timer;
827
+ const fire = (reason) => {
828
+ if (controller.signal.aborted) return;
829
+ try {
830
+ controller.abort(reason);
831
+ } catch {
832
+ controller.abort();
833
+ }
834
+ };
835
+ const dispose = () => {
836
+ if (timer !== void 0) {
837
+ clearInterval(timer);
838
+ timer = void 0;
839
+ }
840
+ polled = [];
841
+ for (const cleanup of cleanups.splice(0)) {
842
+ try {
843
+ cleanup();
844
+ } catch {
845
+ }
846
+ }
847
+ };
848
+ for (const candidate of candidates) {
849
+ if (candidate.aborted === true || candidate.isCancellationRequested === true) {
850
+ fire(isRealSignal(candidate) ? candidate.reason : void 0);
851
+ return { signal: controller.signal, dispose };
852
+ }
853
+ }
854
+ for (const candidate of candidates) {
855
+ if (typeof candidate.addEventListener === "function") {
856
+ const onAbort = () => fire(isRealSignal(candidate) ? candidate.reason : void 0);
857
+ candidate.addEventListener("abort", onAbort, { once: true });
858
+ cleanups.push(() => candidate.removeEventListener?.("abort", onAbort));
859
+ continue;
860
+ }
861
+ if (typeof candidate.onCancellationRequested === "function") {
862
+ let handle;
863
+ try {
864
+ handle = candidate.onCancellationRequested(() => fire());
865
+ } catch {
866
+ handle = void 0;
867
+ }
868
+ if (isObject(handle) && typeof handle.dispose === "function") {
869
+ cleanups.push(() => handle.dispose());
870
+ }
871
+ polled.push(candidate);
872
+ continue;
873
+ }
874
+ if ("isCancellationRequested" in candidate || "aborted" in candidate) {
875
+ polled.push(candidate);
876
+ }
877
+ }
878
+ if (polled.length > 0) {
879
+ timer = setInterval(() => {
880
+ for (const candidate of polled) {
881
+ if (candidate.aborted === true || candidate.isCancellationRequested === true) {
882
+ fire();
883
+ dispose();
884
+ return;
885
+ }
886
+ }
887
+ }, POLL_INTERVAL_MS);
888
+ timer.unref?.();
889
+ }
890
+ return { signal: controller.signal, dispose };
891
+ }
892
+ function abortableSleep(ms, signal) {
893
+ if (!signal) return new Promise((resolve) => setTimeout(resolve, ms));
894
+ if (signal.aborted) return Promise.reject(abortReason(signal));
895
+ return new Promise((resolve, reject) => {
896
+ const onAbort = () => {
897
+ clearTimeout(timer);
898
+ reject(abortReason(signal));
899
+ };
900
+ const timer = setTimeout(() => {
901
+ signal.removeEventListener("abort", onAbort);
902
+ resolve();
903
+ }, ms);
904
+ signal.addEventListener("abort", onAbort, { once: true });
905
+ });
906
+ }
907
+ function abortReason(signal) {
908
+ if (signal.reason !== void 0) return signal.reason;
909
+ const error = new Error("This operation was aborted");
910
+ error.name = "AbortError";
911
+ return error;
912
+ }
913
+
561
914
  // src/model.ts
562
915
  function isSmartModel(m) {
563
916
  return !!m && typeof m === "object" && typeof m.invoke === "function";
@@ -566,6 +919,10 @@ function withTools(model, tools, options) {
566
919
  if (model?.bindTools) return model.bindTools(tools, options);
567
920
  return model;
568
921
  }
922
+ function withLinkedSignal(options, signal) {
923
+ if (!signal || options?.signal === signal) return options;
924
+ return { ...options || {}, signal };
925
+ }
569
926
  function fromLangchainModel(lcModel) {
570
927
  if (!lcModel) throw new Error("fromLangchainModel: model is undefined/null");
571
928
  const normalizeContent = (content) => {
@@ -601,7 +958,13 @@ function fromLangchainModel(lcModel) {
601
958
  const adapted = {
602
959
  invoke: async (messages, options) => {
603
960
  const lcMessages = messages.map(toLC);
604
- const response = await lcModel.invoke(lcMessages, options);
961
+ const link = linkAbortSignal(options);
962
+ let response;
963
+ try {
964
+ response = await lcModel.invoke(lcMessages, withLinkedSignal(options, link.signal));
965
+ } finally {
966
+ link.dispose();
967
+ }
605
968
  if (response && typeof response === "object") {
606
969
  const content = response.content ?? response.text ?? "";
607
970
  return {
@@ -619,10 +982,15 @@ function fromLangchainModel(lcModel) {
619
982
  stream: async function* (messages, options) {
620
983
  if (typeof lcModel.stream !== "function") return;
621
984
  const lcMessages = messages.map(toLC);
622
- const streamResult = lcModel.stream(lcMessages, options);
623
- const stream = typeof streamResult?.then === "function" ? await streamResult : streamResult;
624
- for await (const chunk of stream) {
625
- yield chunk;
985
+ const link = linkAbortSignal(options);
986
+ try {
987
+ const streamResult = lcModel.stream(lcMessages, withLinkedSignal(options, link.signal));
988
+ const stream = typeof streamResult?.then === "function" ? await streamResult : streamResult;
989
+ for await (const chunk of stream) {
990
+ yield chunk;
991
+ }
992
+ } finally {
993
+ link.dispose();
626
994
  }
627
995
  },
628
996
  bindTools: (tools, options) => {
@@ -801,6 +1169,9 @@ function safe(v) {
801
1169
  const n = Number(v);
802
1170
  return Number.isFinite(n) && n >= 0 ? n : 0;
803
1171
  }
1172
+
1173
+ // src/utils/tracing.ts
1174
+ init_content();
804
1175
  var DEFAULT_COGNIPEER_URL = "https://console.cognipeer.com/api/client/v1/tracing/sessions";
805
1176
  function fileSink(path2) {
806
1177
  return { type: "file", path: path2 };
@@ -1545,6 +1916,12 @@ function buildMessageLabel(role, index) {
1545
1916
  const base = `${normalized.charAt(0).toUpperCase()}${normalized.slice(1)} Message`;
1546
1917
  return index > 1 ? `${base} #${index}` : base;
1547
1918
  }
1919
+ function structuredMessageParts(content) {
1920
+ if (!hasMediaPart(content)) return void 0;
1921
+ const cloned = sanitizeTracePayload(content);
1922
+ if (!Array.isArray(cloned)) return void 0;
1923
+ return cloned.map((part) => typeof part === "string" ? { type: "text", text: part } : part);
1924
+ }
1548
1925
  function toDisplayString(value) {
1549
1926
  const sanitized = sanitizeTracePayload(value);
1550
1927
  if (sanitized == null) return "";
@@ -1553,7 +1930,9 @@ function toDisplayString(value) {
1553
1930
  return sanitized.map((item) => toDisplayString(item)).filter((part) => part && part.trim().length > 0).join("\n");
1554
1931
  }
1555
1932
  if (typeof sanitized === "object") {
1556
- if (typeof sanitized.text === "string" && Object.keys(sanitized).length === 1) {
1933
+ const media = describeContentPart(sanitized);
1934
+ if (media) return media;
1935
+ if (typeof sanitized.text === "string" && (Object.keys(sanitized).length === 1 || sanitized.type === "text")) {
1557
1936
  return sanitized.text;
1558
1937
  }
1559
1938
  if (typeof sanitized.content === "string") {
@@ -1625,11 +2004,13 @@ function convertMessageListToSections(messageList) {
1625
2004
  if (!content || !content.trim().length) continue;
1626
2005
  }
1627
2006
  }
2007
+ const parts = structuredMessageParts(message?.content);
1628
2008
  sections.push({
1629
2009
  kind: "message",
1630
2010
  label: buildMessageLabel(role, next),
1631
2011
  role,
1632
2012
  content,
2013
+ ...parts ? { parts } : {},
1633
2014
  metadata: typeof message?.name === "string" ? { name: message.name } : void 0
1634
2015
  });
1635
2016
  }
@@ -2057,50 +2438,63 @@ function fromNativeProvider(provider, options) {
2057
2438
  modelName,
2058
2439
  capabilities: resolveCapabilities(provider.providerName),
2059
2440
  invoke: async (messages, _invokeOptions) => {
2060
- const request = buildRequest(messages, boundTools, options, _invokeOptions);
2061
- const response = await provider.complete(request);
2062
- return toBaseChatMessage(response);
2441
+ const link = linkAbortSignal(_invokeOptions);
2442
+ try {
2443
+ const request = buildRequest(messages, boundTools, options, _invokeOptions);
2444
+ if (link.signal) request.signal = link.signal;
2445
+ const response = await provider.complete(request);
2446
+ return toBaseChatMessage(response);
2447
+ } finally {
2448
+ link.dispose();
2449
+ }
2063
2450
  },
2064
2451
  stream: async function* (messages, _invokeOptions) {
2065
- const request = buildRequest(messages, boundTools, options, _invokeOptions);
2066
- request.stream = true;
2067
- let fullContent = "";
2068
- let allToolCalls = [];
2069
- let lastUsage;
2070
- let reasoningBlocks;
2071
- const toolCallBuffers = /* @__PURE__ */ new Map();
2072
- for await (const chunk of provider.completeStream(request)) {
2073
- if (chunk.delta.content) {
2074
- fullContent += chunk.delta.content;
2075
- yield chunk.delta.content;
2076
- }
2077
- if (chunk.delta.reasoning?.blocks?.length) {
2078
- reasoningBlocks = chunk.delta.reasoning.blocks;
2079
- }
2080
- if (chunk.delta.toolCalls) {
2081
- for (const tc of chunk.delta.toolCalls) {
2082
- if (tc.id) {
2083
- const existing = toolCallBuffers.get(tc.id);
2084
- if (existing) {
2085
- if (tc.arguments) existing.arguments += tc.arguments;
2086
- } else {
2087
- toolCallBuffers.set(tc.id, {
2088
- id: tc.id,
2089
- name: tc.name ?? "",
2090
- arguments: tc.arguments ?? ""
2091
- });
2452
+ const link = linkAbortSignal(_invokeOptions);
2453
+ try {
2454
+ const request = buildRequest(messages, boundTools, options, _invokeOptions);
2455
+ request.stream = true;
2456
+ if (link.signal) request.signal = link.signal;
2457
+ let fullContent = "";
2458
+ let allToolCalls = [];
2459
+ let lastUsage;
2460
+ let reasoningBlocks;
2461
+ const toolCallBuffers = /* @__PURE__ */ new Map();
2462
+ for await (const chunk of provider.completeStream(request)) {
2463
+ if (chunk.delta.content) {
2464
+ fullContent += chunk.delta.content;
2465
+ yield chunk.delta.content;
2466
+ }
2467
+ if (chunk.delta.reasoning?.blocks?.length) {
2468
+ reasoningBlocks = chunk.delta.reasoning.blocks;
2469
+ }
2470
+ if (chunk.delta.toolCalls) {
2471
+ for (const tc of chunk.delta.toolCalls) {
2472
+ if (tc.id) {
2473
+ const existing = toolCallBuffers.get(tc.id);
2474
+ if (existing) {
2475
+ if (tc.arguments) existing.arguments += tc.arguments;
2476
+ } else {
2477
+ toolCallBuffers.set(tc.id, {
2478
+ id: tc.id,
2479
+ name: tc.name ?? "",
2480
+ arguments: tc.arguments ?? ""
2481
+ });
2482
+ }
2092
2483
  }
2093
2484
  }
2094
2485
  }
2486
+ if (chunk.usage) lastUsage = chunk.usage;
2095
2487
  }
2096
- if (chunk.usage) lastUsage = chunk.usage;
2097
- }
2098
- allToolCalls = [...toolCallBuffers.values()];
2099
- const finalMessage = assembleMessage(fullContent, allToolCalls, lastUsage);
2100
- if (reasoningBlocks?.length) {
2101
- finalMessage.reasoning = { blocks: reasoningBlocks };
2488
+ if (link.signal?.aborted) return;
2489
+ allToolCalls = [...toolCallBuffers.values()];
2490
+ const finalMessage = assembleMessage(fullContent, allToolCalls, lastUsage);
2491
+ if (reasoningBlocks?.length) {
2492
+ finalMessage.reasoning = { blocks: reasoningBlocks };
2493
+ }
2494
+ yield finalMessage;
2495
+ } finally {
2496
+ link.dispose();
2102
2497
  }
2103
- yield finalMessage;
2104
2498
  },
2105
2499
  bindTools: (tools, _bindOptions) => {
2106
2500
  const strict = _bindOptions?.strict ?? false;
@@ -2543,157 +2937,28 @@ function resolveCapabilities(provider) {
2543
2937
  };
2544
2938
  case "bedrock":
2545
2939
  return {
2546
- structuredOutput: "tool_based",
2547
- strictToolCalling: false,
2548
- streaming: false,
2549
- // streaming uses binary protocol
2550
- provider: "bedrock"
2551
- };
2552
- case "vertex":
2553
- return {
2554
- structuredOutput: "native",
2555
- strictToolCalling: false,
2556
- streaming: true,
2557
- provider: "google"
2558
- };
2559
- default:
2560
- return { provider };
2561
- }
2562
- }
2563
-
2564
- // src/smart/toolResponses.ts
2565
- init_utilTokens();
2566
-
2567
- // src/utils/content.ts
2568
- function contentToString(content) {
2569
- try {
2570
- if (content == null) return "";
2571
- if (typeof content === "string") return content;
2572
- if (Array.isArray(content)) {
2573
- return content.map((p) => {
2574
- if (!p || typeof p !== "object") return String(p);
2575
- if (p.type === "text") return String(p.text ?? "");
2576
- if (p.type === "image_url") {
2577
- const img = p.image_url;
2578
- const url = typeof img === "string" ? img : img?.url;
2579
- const detail = typeof img === "string" ? void 0 : img?.detail;
2580
- return `[image:${url || "unknown"}${detail ? ` detail=${detail}` : ""}]`;
2581
- }
2582
- return JSON.stringify(p);
2583
- }).join("\n");
2584
- }
2585
- return JSON.stringify(content);
2586
- } catch {
2587
- return String(content);
2588
- }
2589
- }
2590
- function mergeContentsToString(contents) {
2591
- return contents.map((c) => contentToString(c)).join("\n");
2592
- }
2593
- function safeStringify(value, pretty = false) {
2594
- if (value == null) return "";
2595
- if (typeof value === "string") return value;
2596
- try {
2597
- return JSON.stringify(value, null, pretty ? 2 : void 0) ?? String(value);
2598
- } catch {
2599
- return String(value);
2600
- }
2601
- }
2602
- function extractMessageText2(message) {
2603
- if (!message) return "";
2604
- const content = message.content;
2605
- if (typeof content === "string") return content;
2606
- if (Array.isArray(content)) {
2607
- return content.map((part) => typeof part === "string" ? part : part?.text ?? part?.content ?? "").join("");
2608
- }
2609
- return "";
2610
- }
2611
- function textFromContent(content) {
2612
- if (typeof content === "string") return content;
2613
- if (!Array.isArray(content)) return "";
2614
- return content.filter((part) => isTextPart(part)).map((part) => part.text ?? "").join("\n");
2615
- }
2616
- function isTextPart(part) {
2617
- return !!part && typeof part === "object" && part.type === "text";
2618
- }
2619
- function mapTextParts(content, fn) {
2620
- if (typeof content === "string") return fn(content);
2621
- if (!Array.isArray(content)) return content;
2622
- return content.map((part) => isTextPart(part) ? { ...part, text: fn(part.text) } : part);
2623
- }
2624
- function replaceTextContent(content, text) {
2625
- if (typeof content === "string" || content == null) return text;
2626
- if (!Array.isArray(content)) return text;
2627
- const textIndexes = content.reduce((acc, part, index) => {
2628
- if (isTextPart(part)) acc.push(index);
2629
- return acc;
2630
- }, []);
2631
- if (textIndexes.length === 0) {
2632
- return text.length > 0 ? [{ type: "text", text }, ...content] : content;
2633
- }
2634
- const [first, ...rest] = textIndexes;
2635
- const dropped = new Set(rest);
2636
- return content.map((part, index) => index === first ? { ...part, text } : part).filter((_part, index) => !dropped.has(index));
2637
- }
2638
- function normalizeSource(source) {
2639
- if (!source || typeof source !== "object") return {};
2640
- const src = source;
2641
- if (src.type === "base64" && typeof src.data === "string") {
2642
- return {
2643
- sourceType: "base64",
2644
- mediaType: typeof src.mediaType === "string" ? src.mediaType : void 0,
2645
- // base64 encodes 3 bytes per 4 characters; padding makes this an upper bound.
2646
- approxBytes: Math.floor(src.data.length * 3 / 4)
2647
- };
2648
- }
2649
- if (src.type === "url" && typeof src.url === "string") {
2650
- return {
2651
- sourceType: "url",
2652
- url: src.url,
2653
- mediaType: typeof src.mediaType === "string" ? src.mediaType : void 0
2654
- };
2940
+ structuredOutput: "tool_based",
2941
+ strictToolCalling: false,
2942
+ streaming: false,
2943
+ // streaming uses binary protocol
2944
+ provider: "bedrock"
2945
+ };
2946
+ case "vertex":
2947
+ return {
2948
+ structuredOutput: "native",
2949
+ strictToolCalling: false,
2950
+ streaming: true,
2951
+ provider: "google"
2952
+ };
2953
+ default:
2954
+ return { provider };
2655
2955
  }
2656
- return {};
2657
- }
2658
- function collectAttachments(content) {
2659
- if (!Array.isArray(content)) return [];
2660
- const attachments = [];
2661
- content.forEach((part, index) => {
2662
- if (!part || typeof part !== "object") return;
2663
- const type = part.type;
2664
- if (!type || type === "text") return;
2665
- if (type === "image" || type === "audio" || type === "video" || type === "file") {
2666
- attachments.push({
2667
- index,
2668
- kind: type,
2669
- fileName: typeof part.fileName === "string" ? part.fileName : void 0,
2670
- ...normalizeSource(part.source)
2671
- });
2672
- return;
2673
- }
2674
- if (type === "image_url") {
2675
- const image = part.image_url;
2676
- const url = typeof image === "string" ? image : image?.url;
2677
- if (typeof url === "string" && url.startsWith("data:")) {
2678
- const comma = url.indexOf(",");
2679
- const header = url.slice(5, comma);
2680
- attachments.push({
2681
- index,
2682
- kind: "image",
2683
- sourceType: "base64",
2684
- mediaType: header.split(";")[0] || void 0,
2685
- approxBytes: Math.floor((url.length - comma - 1) * 3 / 4)
2686
- });
2687
- } else {
2688
- attachments.push({ index, kind: "image", sourceType: "url", url });
2689
- }
2690
- return;
2691
- }
2692
- attachments.push({ index, kind: "unknown" });
2693
- });
2694
- return attachments;
2695
2956
  }
2696
2957
 
2958
+ // src/smart/toolResponses.ts
2959
+ init_utilTokens();
2960
+ init_content();
2961
+
2697
2962
  // src/smart/toolArgCoercion.ts
2698
2963
  var PLACEHOLDER_TEXT = /* @__PURE__ */ new Set(["", "null", "undefined", "none", "nil", "n/a", "na"]);
2699
2964
  var ENVELOPE_KEYS = ["input", "args", "arguments", "params", "parameters", "payload"];
@@ -3581,6 +3846,7 @@ function detectVolatileContent(text, limit = 20) {
3581
3846
 
3582
3847
  // src/smart/contextPilot/jsonCrusher.ts
3583
3848
  init_utilTokens();
3849
+ init_content();
3584
3850
  var CONTEXT_PILOT_JSON_MARKER_KEY = "__contextPilotDropped";
3585
3851
  function findCompressibleArray(output, minItems) {
3586
3852
  if (Array.isArray(output)) {
@@ -3793,6 +4059,7 @@ function compressSearchOutput(text, config, ccrStore) {
3793
4059
 
3794
4060
  // src/smart/contextPilot/pipeline.ts
3795
4061
  init_utilTokens();
4062
+ init_content();
3796
4063
  function createContextPilotRuntime(config) {
3797
4064
  return {
3798
4065
  ccrStore: new CCRStore({ ttlMs: config.ccr.ttlMs, maxEntries: config.ccr.maxEntries }),
@@ -4166,6 +4433,8 @@ function createAgentCoreNode(opts) {
4166
4433
  const streamingEnabled = Boolean(state.ctx?.__streaming);
4167
4434
  const cancellationToken = state.ctx?.__cancellationToken;
4168
4435
  const abortSignal = state.ctx?.__abortSignal;
4436
+ const onProgress = state.ctx?.__onProgress;
4437
+ const cancelRequested = () => isCancellationRequested({ signal: abortSignal, cancellationToken });
4169
4438
  const resolvedForCachePilot = getResolvedSmartConfig(opts, runtime);
4170
4439
  if (resolvedForCachePilot.contextPilot.enabled && resolvedForCachePilot.contextPilot.cacheAlignment.enabled) {
4171
4440
  const ctxForCacheWarning = state.ctx = state.ctx || {};
@@ -4324,6 +4593,29 @@ ${append}`;
4324
4593
  let response;
4325
4594
  let modelAttempt = 0;
4326
4595
  const maxModelRetries = host?.maxModelRetries ?? 0;
4596
+ const finishCancelledTurn = (partialText) => {
4597
+ const reason = abortSignal?.aborted ? "aborted" : "cancelled";
4598
+ const ctx = state.ctx = state.ctx || {};
4599
+ ctx.__cancelled = { stage: "agent", reason, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
4600
+ recordTraceEvent(traceSession, {
4601
+ type: "ai_call",
4602
+ label: "Assistant Cancelled",
4603
+ actor: { scope: "agent", name: actorName, role: "assistant", version: actorVersion },
4604
+ // "skipped", not "error": the call did not fail, the caller ended it —
4605
+ // and an "error" would flip the whole session to error.
4606
+ status: "skipped",
4607
+ durationMs: Date.now() - start,
4608
+ requestBytes: promptBytes,
4609
+ model: getModelName(runtime.model || opts.model),
4610
+ provider: getProviderName(runtime.model || opts.model),
4611
+ messageList: state.messages,
4612
+ toolDefinitions: traceToolDefinitions
4613
+ });
4614
+ onEvent?.({ type: "cancelled", stage: "agent", reason });
4615
+ onProgress?.({ stage: "agent", message: "Cancelled", detail: { reason } });
4616
+ const partial = partialText.trim().length > 0 ? [{ role: "assistant", content: partialText }] : [];
4617
+ return { messages: [...state.messages, ...partial], usage: state.usage };
4618
+ };
4327
4619
  while (true) {
4328
4620
  start = Date.now();
4329
4621
  if (shortCircuited !== void 0) {
@@ -4339,14 +4631,16 @@ ${append}`;
4339
4631
  toolDefinitions: traceToolDefinitions
4340
4632
  });
4341
4633
  } else {
4634
+ let streamedText = "";
4342
4635
  try {
4343
4636
  const normalizedMessages = normalizeBedrockToolPairing([...wireMessages]);
4344
4637
  debugToolPairing(normalizedMessages);
4345
4638
  if (streamingEnabled && typeof modelWithTools.stream === "function") {
4346
- let streamedText = "";
4347
4639
  let streamedMessage;
4640
+ let cutByCancel = false;
4348
4641
  for await (const chunk of modelWithTools.stream(normalizedMessages, invokeParams)) {
4349
- if (cancellationToken && cancellationToken.isCancellationRequested || abortSignal?.aborted) {
4642
+ if (cancelRequested()) {
4643
+ cutByCancel = true;
4350
4644
  break;
4351
4645
  }
4352
4646
  if (chunk && typeof chunk === "object" && chunk.role) {
@@ -4360,6 +4654,7 @@ ${append}`;
4360
4654
  onEvent?.({ type: "stream", text });
4361
4655
  }
4362
4656
  }
4657
+ if (cutByCancel) return finishCancelledTurn(streamedText);
4363
4658
  if (streamedMessage) {
4364
4659
  response = { ...streamedMessage };
4365
4660
  if (response.content == null || response.content === "") {
@@ -4372,6 +4667,7 @@ ${append}`;
4372
4667
  response = await modelWithTools.invoke(normalizedMessages, invokeParams);
4373
4668
  }
4374
4669
  } catch (err) {
4670
+ if (cancelRequested()) return finishCancelledTurn(streamedText);
4375
4671
  const durationMs2 = Date.now() - start;
4376
4672
  recordTraceEvent(traceSession, {
4377
4673
  type: "ai_call",
@@ -4469,6 +4765,7 @@ ${append}`;
4469
4765
  }
4470
4766
 
4471
4767
  // src/utils/traceSections.ts
4768
+ init_content();
4472
4769
  function truncate(text, max = 500) {
4473
4770
  if (!text) return "";
4474
4771
  return text.length > max ? `${text.slice(0, max)}\u2026` : text;
@@ -6359,6 +6656,9 @@ function isCompactedToolContent(content) {
6359
6656
  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"));
6360
6657
  }
6361
6658
 
6659
+ // src/agent.ts
6660
+ init_content();
6661
+
6362
6662
  // src/structuredOutput/manager.ts
6363
6663
  var StructuredOutputManager = class {
6364
6664
  constructor(schema, strategy, config) {
@@ -6591,6 +6891,7 @@ function buildSubagentCatalogBlock(subagents, policy, toolNames) {
6591
6891
  }
6592
6892
 
6593
6893
  // src/plugins/host.ts
6894
+ init_content();
6594
6895
  var DEFAULT_PRIORITY = 100;
6595
6896
  var DEFAULT_TIMEOUT_MS = 1e4;
6596
6897
  var HOOK_SPECS = {
@@ -7127,6 +7428,7 @@ function performanceNow() {
7127
7428
  }
7128
7429
 
7129
7430
  // src/plugins/session.ts
7431
+ init_content();
7130
7432
  async function openPluginSession(runHost, params) {
7131
7433
  let messages = params.messages;
7132
7434
  const startGate = await runHost.runGate("sessionStart", {
@@ -7596,6 +7898,7 @@ function createAgent(opts) {
7596
7898
  onProgress?.({ stage: "agent", message: "Invoking model" });
7597
7899
  if (cancelIfRequested("before_agent")) break;
7598
7900
  state = publish({ ...state, ...await agentCore(state) });
7901
+ if (state.ctx?.__cancelled) break;
7599
7902
  onProgress?.({ stage: "agent", message: "Model response received" });
7600
7903
  if (checkpointIfRequested("after_agent")) break;
7601
7904
  const postGuardrails = getGuardrailConfig(state);
@@ -7666,7 +7969,7 @@ function createAgent(opts) {
7666
7969
  if (toolCalls.length === 0) {
7667
7970
  if (soManager && !state.ctx?.__finalizedDueToStructuredOutput && !state.ctx?.__structuredOutputForceFinalize && !state.ctx?.__guardrailBlocked) {
7668
7971
  if (soManager.strategy.kind === "native") {
7669
- const assistantText = extractMessageText2(lastMsg);
7972
+ const assistantText = extractMessageText(lastMsg);
7670
7973
  if (assistantText) {
7671
7974
  const parsed = soManager.parseFromContent(assistantText);
7672
7975
  if (parsed.success) {
@@ -7722,7 +8025,7 @@ function createAgent(opts) {
7722
8025
  if (soManager && !state.ctx?.__finalizedDueToStructuredOutput && !structuredFinalizeBlocked) {
7723
8026
  const lastForParse = state.messages[state.messages.length - 1];
7724
8027
  if (lastForParse?.role === "assistant") {
7725
- const assistantText = extractMessageText2(lastForParse);
8028
+ const assistantText = extractMessageText(lastForParse);
7726
8029
  if (assistantText) {
7727
8030
  const parsed = soManager.parseFromContent(assistantText);
7728
8031
  if (parsed.success) {
@@ -7984,7 +8287,7 @@ function createAgent(opts) {
7984
8287
  const isTransientSummarizationExit = !!res.ctx?.__needsSummarization;
7985
8288
  const finalAssistantMsg = isTransientSummarizationExit ? void 0 : getLastAssistantMessage(res.messages);
7986
8289
  const finalIsSyntheticSummary = !isTransientSummarizationExit && finalAssistantMsg && isSyntheticSummaryMessage(finalAssistantMsg);
7987
- let content = isTransientSummarizationExit || finalIsSyntheticSummary ? "" : extractMessageText2(finalAssistantMsg);
8290
+ let content = isTransientSummarizationExit || finalIsSyntheticSummary ? "" : extractMessageText(finalAssistantMsg);
7988
8291
  const finalAnswerBlocked = Boolean(
7989
8292
  isTransientSummarizationExit || res.ctx?.__awaitingApproval || res.ctx?.__awaitingUserQuestion || res.ctx?.__cancelled || res.ctx?.__paused || res.ctx?.__limitBreached
7990
8293
  );
@@ -8243,9 +8546,11 @@ function createAgentNode(opts) {
8243
8546
 
8244
8547
  // src/nodes/contextSummarize.ts
8245
8548
  init_utilTokens();
8549
+ init_content();
8246
8550
 
8247
8551
  // src/smart/contextPolicy.ts
8248
8552
  init_utilTokens();
8553
+ init_content();
8249
8554
  function collectRecentTurns(messages, lastTurnsToKeep) {
8250
8555
  if (lastTurnsToKeep <= 0) return [];
8251
8556
  const systemPrefix = messages.filter((message, index) => index === 0 && message.role === "system");
@@ -8307,7 +8612,7 @@ function isClampProtected(message, index, firstUserIndex) {
8307
8612
  function clampToBudget(messages, maxContextTokens) {
8308
8613
  let working = [...messages];
8309
8614
  while (working.length > 2) {
8310
- const tokenCount = countApproxTokens(working.map(extractMessageText2).join("\n"));
8615
+ const tokenCount = countApproxTokens(working.map(extractMessageText).join("\n"));
8311
8616
  if (tokenCount <= maxContextTokens) return working;
8312
8617
  const firstUserIndex = working.findIndex((message) => message.role === "user");
8313
8618
  const firstNonSystem = working.findIndex((message, index) => !isClampProtected(message, index, firstUserIndex));
@@ -8647,7 +8952,7 @@ function createContextSummarizeNode(opts) {
8647
8952
  let content = "";
8648
8953
  if (typeof m.content === "string") content = m.content;
8649
8954
  else if (Array.isArray(m.content)) {
8650
- content = m.content.map((c) => c.text || JSON.stringify(c)).join(" ");
8955
+ content = m.content.map((c) => contentPartToText(c, (part) => JSON.stringify(part))).join(" ");
8651
8956
  }
8652
8957
  if (m.role === "tool" && isSummarizedToolPlaceholder(content)) {
8653
8958
  const historyEntry = findToolHistoryEntry(state, m.tool_call_id, m.name);
@@ -9492,6 +9797,9 @@ async function writeSummaryFactsToMemory(store, config, summary, sourceTurn) {
9492
9797
  return store.get(config.memory.scope, { limit: config.context.lastTurnsToKeep + summary.stable_facts.length });
9493
9798
  }
9494
9799
 
9800
+ // src/smart/index.ts
9801
+ init_content();
9802
+
9495
9803
  // src/smart/skills/types.ts
9496
9804
  var DEFAULT_SKILL_POLICY = {
9497
9805
  maxOpenSkills: 4,
@@ -10506,7 +10814,7 @@ function createSmartAgent(opts) {
10506
10814
  ].join("\n");
10507
10815
  function latestUserPrompt(messages) {
10508
10816
  const latest = [...messages].reverse().find((message) => message.role === "user");
10509
- return latest ? extractMessageText2(latest) : "";
10817
+ return latest ? extractMessageText(latest) : "";
10510
10818
  }
10511
10819
  async function syncMemory(state) {
10512
10820
  const query = latestUserPrompt(state.messages || []);
@@ -11217,6 +11525,132 @@ async function runSmartAgentEvalHarness(params) {
11217
11525
  }
11218
11526
  return results;
11219
11527
  }
11528
+
11529
+ // src/providers/base.ts
11530
+ var DEFAULT_RETRY = {
11531
+ maxRetries: 3,
11532
+ baseDelayMs: 500,
11533
+ maxDelayMs: 8e3
11534
+ };
11535
+ var BaseProvider = class {
11536
+ constructor() {
11537
+ this.retryPolicy = DEFAULT_RETRY;
11538
+ }
11539
+ /**
11540
+ * Helper concrete providers can wrap their fetch with. Retries 429/5xx
11541
+ * with exponential backoff and respects Retry-After if the response
11542
+ * carries one.
11543
+ *
11544
+ * `signal` is the call's cancellation: a run that is cancelled while the
11545
+ * provider is backing off must not sit out the delay, nor start another attempt.
11546
+ */
11547
+ async doFetchWithRetry(execute, signal) {
11548
+ const policy = this.retryPolicy;
11549
+ const maxRetries = Math.max(0, policy.maxRetries ?? DEFAULT_RETRY.maxRetries);
11550
+ const baseDelay = Math.max(0, policy.baseDelayMs ?? DEFAULT_RETRY.baseDelayMs);
11551
+ const maxDelay = Math.max(baseDelay, policy.maxDelayMs ?? DEFAULT_RETRY.maxDelayMs);
11552
+ let lastResp;
11553
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
11554
+ if (signal?.aborted) throw abortReason(signal);
11555
+ const res = await execute();
11556
+ const isRetryable = res.status === 429 || res.status >= 500 && res.status < 600;
11557
+ if (!isRetryable) return res;
11558
+ const predicate = policy.shouldRetry;
11559
+ if (predicate && !predicate({ status: res.status }, attempt)) return res;
11560
+ if (attempt === maxRetries) {
11561
+ lastResp = res;
11562
+ break;
11563
+ }
11564
+ const retryAfter = res.headers.get("retry-after");
11565
+ let delay2 = Math.min(maxDelay, baseDelay * Math.pow(2, attempt));
11566
+ if (retryAfter) {
11567
+ const asNumber = Number(retryAfter);
11568
+ if (!Number.isNaN(asNumber)) delay2 = Math.min(maxDelay, Math.max(delay2, asNumber * 1e3));
11569
+ }
11570
+ try {
11571
+ await res.text();
11572
+ } catch {
11573
+ }
11574
+ await abortableSleep(delay2, signal);
11575
+ }
11576
+ return lastResp;
11577
+ }
11578
+ };
11579
+
11580
+ // src/providers/types.ts
11581
+ function emptyUsage() {
11582
+ return {
11583
+ inputTokens: 0,
11584
+ outputTokens: 0,
11585
+ totalTokens: 0,
11586
+ cachedInputTokens: 0,
11587
+ cachedWriteTokens: 0,
11588
+ cachedOutputTokens: 0,
11589
+ reasoningTokens: 0
11590
+ };
11591
+ }
11592
+ var ProviderError = class extends Error {
11593
+ constructor(message, provider, statusCode, responseBody) {
11594
+ super(message);
11595
+ this.provider = provider;
11596
+ this.statusCode = statusCode;
11597
+ this.responseBody = responseBody;
11598
+ this.name = "ProviderError";
11599
+ }
11600
+ };
11601
+
11602
+ // src/providers/jev.ts
11603
+ var JEV_DEFAULT_BASE_URL = "https://api.typesafe.ai";
11604
+ var JevProvider = class extends BaseProvider {
11605
+ constructor(config) {
11606
+ super();
11607
+ this.providerName = "jev";
11608
+ this.apiKey = config.apiKey;
11609
+ this.baseURL = (config.baseURL ?? JEV_DEFAULT_BASE_URL).replace(/\/$/, "");
11610
+ this.defaultModel = config.defaultModel;
11611
+ this.defaultHeaders = config.defaultHeaders ?? {};
11612
+ if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
11613
+ }
11614
+ /** Ask System One questions about `state`. */
11615
+ async systemOne(request, options) {
11616
+ const model = request.model ?? this.defaultModel;
11617
+ const body = {
11618
+ ...model ? { model } : {},
11619
+ state: request.state,
11620
+ questions: request.questions
11621
+ };
11622
+ const res = await this.doFetchWithRetry(
11623
+ () => fetch(`${this.baseURL}/v1/systemone`, {
11624
+ method: "POST",
11625
+ headers: {
11626
+ "Content-Type": "application/json",
11627
+ Authorization: `Bearer ${this.apiKey}`,
11628
+ ...this.defaultHeaders
11629
+ },
11630
+ body: JSON.stringify(body),
11631
+ signal: options?.signal
11632
+ })
11633
+ );
11634
+ if (!res.ok) {
11635
+ const text = await res.text().catch(() => "");
11636
+ throw new ProviderError(`Jev API error ${res.status}: ${text}`, this.providerName, res.status, text);
11637
+ }
11638
+ return await res.json();
11639
+ }
11640
+ async complete(_request) {
11641
+ throw new ProviderError(
11642
+ 'Jev is a decision model and has no chat completion; use systemOne() or agentVerdictRule({ engine: "jev" })',
11643
+ this.providerName
11644
+ );
11645
+ }
11646
+ // eslint-disable-next-line require-yield
11647
+ async *completeStream(_request) {
11648
+ throw new ProviderError("Jev does not stream; use systemOne()", this.providerName);
11649
+ }
11650
+ };
11651
+
11652
+ // src/guardrails/checks.ts
11653
+ init_content();
11220
11654
  var Ajv = AjvModule?.default ?? AjvModule;
11221
11655
  var defaultAjv = new Ajv({ allErrors: true });
11222
11656
  defaultAjv.opts.strict = false;
@@ -11366,14 +11800,82 @@ function defaultPayload(context) {
11366
11800
  2
11367
11801
  );
11368
11802
  }
11803
+ var DEFAULT_JEV_THRESHOLD = 0.5;
11804
+ var JEV_QUESTION_KEY = "shouldBlock";
11805
+ 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.";
11806
+ var DEFAULT_JEV_CRITERIA = {
11807
+ true: "The payload is unsafe, non-compliant, or otherwise warrants blocking.",
11808
+ false: "The payload is benign and the agent should be allowed to continue."
11809
+ };
11810
+ function resolveJevClient(config) {
11811
+ if (config.client) return config.client;
11812
+ const apiKey = config.apiKey ?? process.env.TYPESAFE_API_KEY;
11813
+ if (!apiKey) {
11814
+ throw new Error(
11815
+ "Jev engine requires an API key: pass `jev.apiKey`, set TYPESAFE_API_KEY, or pass a `jev.client`."
11816
+ );
11817
+ }
11818
+ return new JevProvider({
11819
+ provider: "jev",
11820
+ apiKey,
11821
+ baseURL: config.baseURL ?? process.env.TYPESAFE_BASE_URL
11822
+ });
11823
+ }
11369
11824
  function agentVerdictRule(options) {
11370
11825
  const payloadBuilder = options.payloadBuilder || defaultPayload;
11371
11826
  const fallbackDisposition = options.dispositionFallback || "block";
11827
+ const engine = options.engine || "llm";
11828
+ const jevOptions = options.jev || {};
11829
+ const jevThreshold = typeof jevOptions.threshold === "number" ? jevOptions.threshold : DEFAULT_JEV_THRESHOLD;
11830
+ let jevClient;
11831
+ async function evaluateWithJev(context) {
11832
+ const client = jevClient ?? (jevClient = resolveJevClient(jevOptions));
11833
+ const instructions = jevOptions.question ? jevOptions.question(context) : DEFAULT_JEV_QUESTION;
11834
+ const result = await client.systemOne({
11835
+ state: payloadBuilder(context),
11836
+ questions: {
11837
+ [JEV_QUESTION_KEY]: {
11838
+ type: "noul",
11839
+ instructions,
11840
+ criteria: jevOptions.criteria ?? DEFAULT_JEV_CRITERIA
11841
+ }
11842
+ },
11843
+ ...jevOptions.model ? { model: jevOptions.model } : {}
11844
+ });
11845
+ const answer = result?.answers?.[JEV_QUESTION_KEY];
11846
+ const probability = typeof answer?.noul === "number" ? answer.noul : void 0;
11847
+ if (probability === void 0) {
11848
+ return {
11849
+ passed: false,
11850
+ disposition: fallbackDisposition,
11851
+ reason: "Jev engine did not return a noul probability.",
11852
+ details: { jevModel: result?.model, jevUsage: result?.usage }
11853
+ };
11854
+ }
11855
+ const passed = probability < jevThreshold;
11856
+ return {
11857
+ passed,
11858
+ disposition: passed ? "allow" : fallbackDisposition,
11859
+ reason: passed ? void 0 : `Jev risk probability ${probability.toFixed(3)} met or exceeded threshold ${jevThreshold}.`,
11860
+ details: {
11861
+ jevProbability: probability,
11862
+ jevThreshold,
11863
+ jevModel: result?.model,
11864
+ jevUsage: result?.usage
11865
+ }
11866
+ };
11867
+ }
11372
11868
  return {
11373
11869
  id: options.id,
11374
11870
  title: options.title || "Agent-based guardrail",
11375
11871
  description: options.description,
11376
11872
  async evaluate(context) {
11873
+ if (engine === "jev") {
11874
+ return evaluateWithJev(context);
11875
+ }
11876
+ if (!options.agent) {
11877
+ throw new Error("agentVerdictRule requires an `agent` when using the default 'llm' engine.");
11878
+ }
11377
11879
  const payload = payloadBuilder(context);
11378
11880
  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).";
11379
11881
  const review = await options.agent.invoke({
@@ -11589,6 +12091,7 @@ function isHookImplemented(hook) {
11589
12091
  }
11590
12092
 
11591
12093
  // src/plugins/builtin/guardrail.ts
12094
+ init_content();
11592
12095
  var ALLOW = { action: "allow" };
11593
12096
  var RETRYABLE_STATUS = /* @__PURE__ */ new Set([408, 425, 429, 500, 502, 503, 504]);
11594
12097
  var RetryableGuardrailError = class extends Error {
@@ -11875,7 +12378,7 @@ function createGuardrailPlugin(options) {
11875
12378
  return { decision: "deny", reason: verdict.message ?? "Request blocked by guardrail policy." };
11876
12379
  },
11877
12380
  postModelCall: async ({ message }, ctx) => {
11878
- const text = extractMessageText2(message);
12381
+ const text = extractMessageText(message);
11879
12382
  if (!text) return void 0;
11880
12383
  const verdict = await check({ phase: "output", content: text, hook: "postModelCall" }, ctx);
11881
12384
  if (!raiseIfFailed(verdict, ctx) || verdict.action === "allow") return void 0;
@@ -12145,6 +12648,7 @@ function portkeyGuardrail(config = {}) {
12145
12648
  }
12146
12649
 
12147
12650
  // src/plugins/builtin/piiRedaction.ts
12651
+ init_content();
12148
12652
  function isValidTckn(value) {
12149
12653
  const digits = value.replace(/\D/g, "");
12150
12654
  if (digits.length !== 11 || digits[0] === "0") return false;
@@ -12264,7 +12768,7 @@ function piiRedaction(config = {}) {
12264
12768
  },
12265
12769
  postModelCall: ({ message }, ctx) => {
12266
12770
  if (!applied.has("modelOutput")) return void 0;
12267
- const text = extractMessageText2(message);
12771
+ const text = extractMessageText(message);
12268
12772
  if (!text) return void 0;
12269
12773
  const result = redactText(text, detectors, mask);
12270
12774
  if (result.findings.length === 0) return void 0;
@@ -14671,74 +15175,8 @@ function languageGuard(config) {
14671
15175
  };
14672
15176
  }
14673
15177
 
14674
- // src/providers/types.ts
14675
- function emptyUsage() {
14676
- return {
14677
- inputTokens: 0,
14678
- outputTokens: 0,
14679
- totalTokens: 0,
14680
- cachedInputTokens: 0,
14681
- cachedWriteTokens: 0,
14682
- cachedOutputTokens: 0,
14683
- reasoningTokens: 0
14684
- };
14685
- }
14686
- var ProviderError = class extends Error {
14687
- constructor(message, provider, statusCode, responseBody) {
14688
- super(message);
14689
- this.provider = provider;
14690
- this.statusCode = statusCode;
14691
- this.responseBody = responseBody;
14692
- this.name = "ProviderError";
14693
- }
14694
- };
14695
-
14696
- // src/providers/base.ts
14697
- var DEFAULT_RETRY = {
14698
- maxRetries: 3,
14699
- baseDelayMs: 500,
14700
- maxDelayMs: 8e3
14701
- };
14702
- var BaseProvider = class {
14703
- constructor() {
14704
- this.retryPolicy = DEFAULT_RETRY;
14705
- }
14706
- /**
14707
- * Helper concrete providers can wrap their fetch with. Retries 429/5xx
14708
- * with exponential backoff and respects Retry-After if the response
14709
- * carries one.
14710
- */
14711
- async doFetchWithRetry(execute) {
14712
- const policy = this.retryPolicy;
14713
- const maxRetries = Math.max(0, policy.maxRetries ?? DEFAULT_RETRY.maxRetries);
14714
- const baseDelay = Math.max(0, policy.baseDelayMs ?? DEFAULT_RETRY.baseDelayMs);
14715
- const maxDelay = Math.max(baseDelay, policy.maxDelayMs ?? DEFAULT_RETRY.maxDelayMs);
14716
- let lastResp;
14717
- for (let attempt = 0; attempt <= maxRetries; attempt++) {
14718
- const res = await execute();
14719
- const isRetryable = res.status === 429 || res.status >= 500 && res.status < 600;
14720
- if (!isRetryable) return res;
14721
- const predicate = policy.shouldRetry;
14722
- if (predicate && !predicate({ status: res.status }, attempt)) return res;
14723
- if (attempt === maxRetries) {
14724
- lastResp = res;
14725
- break;
14726
- }
14727
- const retryAfter = res.headers.get("retry-after");
14728
- let delay2 = Math.min(maxDelay, baseDelay * Math.pow(2, attempt));
14729
- if (retryAfter) {
14730
- const asNumber = Number(retryAfter);
14731
- if (!Number.isNaN(asNumber)) delay2 = Math.min(maxDelay, Math.max(delay2, asNumber * 1e3));
14732
- }
14733
- try {
14734
- await res.text();
14735
- } catch {
14736
- }
14737
- await new Promise((r) => setTimeout(r, delay2));
14738
- }
14739
- return lastResp;
14740
- }
14741
- };
15178
+ // src/index.ts
15179
+ init_content();
14742
15180
 
14743
15181
  // src/providers/utils/sse.ts
14744
15182
  async function* parseSSEStream(body, signal) {
@@ -14747,7 +15185,7 @@ async function* parseSSEStream(body, signal) {
14747
15185
  let buffer = "";
14748
15186
  try {
14749
15187
  while (true) {
14750
- if (signal?.aborted) ;
15188
+ if (signal?.aborted) throw abortReason(signal);
14751
15189
  const { done, value } = await reader.read();
14752
15190
  if (done) break;
14753
15191
  buffer += decoder.decode(value, { stream: true });
@@ -14764,6 +15202,7 @@ async function* parseSSEStream(body, signal) {
14764
15202
  if (event) yield event;
14765
15203
  }
14766
15204
  } finally {
15205
+ reader.cancel().catch(() => void 0);
14767
15206
  reader.releaseLock();
14768
15207
  }
14769
15208
  }
@@ -14984,12 +15423,12 @@ function sanitizeBedrockDocName(name, fallback = "document") {
14984
15423
  // src/providers/utils/jsonSchemaRefs.ts
14985
15424
  var DEFINITION_KEYS = ["definitions", "$defs"];
14986
15425
  function inlineJsonSchemaRefs(schema) {
14987
- if (!isObject(schema) || !containsRef(schema)) return schema;
15426
+ if (!isObject2(schema) || !containsRef(schema)) return schema;
14988
15427
  const root = structuredClone(schema);
14989
15428
  const selfReaching = /* @__PURE__ */ new Map();
14990
15429
  const targetOf = (ref) => {
14991
15430
  const target = resolvePointer(root, ref);
14992
- return isObject(target) ? target : void 0;
15431
+ return isObject2(target) ? target : void 0;
14993
15432
  };
14994
15433
  const reachesItself = (target) => {
14995
15434
  const known = selfReaching.get(target);
@@ -14997,7 +15436,7 @@ function inlineJsonSchemaRefs(schema) {
14997
15436
  const seen = /* @__PURE__ */ new Set();
14998
15437
  const walk = (node) => {
14999
15438
  if (Array.isArray(node)) return node.some(walk);
15000
- if (!isObject(node)) return false;
15439
+ if (!isObject2(node)) return false;
15001
15440
  if (typeof node.$ref === "string") {
15002
15441
  const next = targetOf(node.$ref);
15003
15442
  if (next === target) return true;
@@ -15015,7 +15454,7 @@ function inlineJsonSchemaRefs(schema) {
15015
15454
  const keptRefs = /* @__PURE__ */ new Set();
15016
15455
  const expand = (node) => {
15017
15456
  if (Array.isArray(node)) return node.map(expand);
15018
- if (!isObject(node)) return node;
15457
+ if (!isObject2(node)) return node;
15019
15458
  if (typeof node.$ref === "string") {
15020
15459
  const target = targetOf(node.$ref);
15021
15460
  if (target && !reachesItself(target)) {
@@ -15037,7 +15476,7 @@ function inlineJsonSchemaRefs(schema) {
15037
15476
  for (const key of DEFINITION_KEYS) delete result[key];
15038
15477
  for (const key of DEFINITION_KEYS) {
15039
15478
  const block = root[key];
15040
- if (!isObject(block)) continue;
15479
+ if (!isObject2(block)) continue;
15041
15480
  const needed = neededEntries(key, block, keptRefs);
15042
15481
  if (needed.length === 0) continue;
15043
15482
  const kept = {};
@@ -15065,13 +15504,13 @@ function collectRefs(node, into) {
15065
15504
  node.forEach((child) => collectRefs(child, into));
15066
15505
  return;
15067
15506
  }
15068
- if (!isObject(node)) return;
15507
+ if (!isObject2(node)) return;
15069
15508
  if (typeof node.$ref === "string") into.push(node.$ref);
15070
15509
  for (const [k, value] of Object.entries(node)) if (k !== "$ref") collectRefs(value, into);
15071
15510
  }
15072
15511
  function containsRef(node) {
15073
15512
  if (Array.isArray(node)) return node.some(containsRef);
15074
- if (!isObject(node)) return false;
15513
+ if (!isObject2(node)) return false;
15075
15514
  if (typeof node.$ref === "string") return true;
15076
15515
  return Object.values(node).some(containsRef);
15077
15516
  }
@@ -15088,7 +15527,7 @@ function resolvePointer(document, ref) {
15088
15527
  if (Array.isArray(current)) {
15089
15528
  if (!/^\d+$/.test(segment)) return void 0;
15090
15529
  current = current[Number(segment)];
15091
- } else if (isObject(current) && Object.prototype.hasOwnProperty.call(current, segment)) {
15530
+ } else if (isObject2(current) && Object.prototype.hasOwnProperty.call(current, segment)) {
15092
15531
  current = current[segment];
15093
15532
  } else {
15094
15533
  return void 0;
@@ -15096,7 +15535,7 @@ function resolvePointer(document, ref) {
15096
15535
  }
15097
15536
  return current;
15098
15537
  }
15099
- function isObject(value) {
15538
+ function isObject2(value) {
15100
15539
  return typeof value === "object" && value !== null && !Array.isArray(value);
15101
15540
  }
15102
15541
 
@@ -15152,7 +15591,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15152
15591
  return this.completeResponses(request);
15153
15592
  }
15154
15593
  const body = this.buildRequestBody(request, false);
15155
- const res = await this.doFetch(body);
15594
+ const res = await this.doFetch(body, request.signal);
15156
15595
  const json = await res.json();
15157
15596
  return this.parseResponse(json);
15158
15597
  }
@@ -15177,13 +15616,13 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15177
15616
  return;
15178
15617
  }
15179
15618
  const body = this.buildRequestBody(request, true);
15180
- const res = await this.doFetch(body);
15619
+ const res = await this.doFetch(body, request.signal);
15181
15620
  if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
15182
15621
  let id = "";
15183
15622
  let model = "";
15184
15623
  const toolCallBuffers = /* @__PURE__ */ new Map();
15185
15624
  let usage;
15186
- for await (const event of parseSSEStream(res.body)) {
15625
+ for await (const event of parseSSEStream(res.body, request.signal)) {
15187
15626
  if (event.data === "[DONE]") break;
15188
15627
  let chunk;
15189
15628
  try {
@@ -15278,7 +15717,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15278
15717
  async completeResponses(request) {
15279
15718
  const body = this.buildResponsesBody(request);
15280
15719
  if (this.isResponsesApiModel(request)) adaptChatExtrasForResponses(body, request.extra);
15281
- const res = await this.responsesFetch(body);
15720
+ const res = await this.responsesFetch(body, request.signal);
15282
15721
  const json = await res.json();
15283
15722
  return this.parseResponsesResponse(json, request.model || this.defaultModel);
15284
15723
  }
@@ -15294,13 +15733,13 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15294
15733
  const body = this.buildResponsesBody(request);
15295
15734
  adaptChatExtrasForResponses(body, request.extra);
15296
15735
  body.stream = true;
15297
- const res = await this.responsesFetch(body);
15736
+ const res = await this.responsesFetch(body, request.signal);
15298
15737
  if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
15299
15738
  let id = "";
15300
15739
  let model = modelId;
15301
15740
  const calls = /* @__PURE__ */ new Map();
15302
15741
  let final;
15303
- for await (const event of parseSSEStream(res.body)) {
15742
+ for await (const event of parseSSEStream(res.body, request.signal)) {
15304
15743
  if (event.data === "[DONE]") break;
15305
15744
  let data;
15306
15745
  try {
@@ -15468,7 +15907,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15468
15907
  });
15469
15908
  return { role, content };
15470
15909
  }
15471
- async responsesFetch(body) {
15910
+ async responsesFetch(body, signal) {
15472
15911
  body.input = expandResponsesInput(body.input);
15473
15912
  const url = `${this.baseURL}/responses`;
15474
15913
  const headers = {
@@ -15477,7 +15916,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15477
15916
  ...this.defaultHeaders
15478
15917
  };
15479
15918
  const payload = JSON.stringify(body);
15480
- const res = await this.doFetchWithRetry(() => fetch(url, { method: "POST", headers, body: payload }));
15919
+ const res = await this.doFetchWithRetry(() => fetch(url, { method: "POST", headers, body: payload, signal }), signal);
15481
15920
  if (!res.ok) {
15482
15921
  const text = await res.text().catch(() => "");
15483
15922
  throw new ProviderError(
@@ -15598,7 +16037,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15598
16037
  }
15599
16038
  return { type: "function", function: fn };
15600
16039
  }
15601
- async doFetch(body) {
16040
+ async doFetch(body, signal) {
15602
16041
  const url = `${this.baseURL}/chat/completions`;
15603
16042
  const headers = {
15604
16043
  "Content-Type": "application/json",
@@ -15606,7 +16045,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15606
16045
  ...this.defaultHeaders
15607
16046
  };
15608
16047
  const payload = JSON.stringify(body);
15609
- const res = await this.doFetchWithRetry(() => fetch(url, { method: "POST", headers, body: payload }));
16048
+ const res = await this.doFetchWithRetry(() => fetch(url, { method: "POST", headers, body: payload, signal }), signal);
15610
16049
  if (!res.ok) {
15611
16050
  const text = await res.text().catch(() => "");
15612
16051
  throw new ProviderError(
@@ -15742,13 +16181,13 @@ var AnthropicProvider = class extends BaseProvider {
15742
16181
  }
15743
16182
  async complete(request) {
15744
16183
  const body = this.buildRequestBody(request, false);
15745
- const res = await this.doFetch(body);
16184
+ const res = await this.doFetch(body, request.signal);
15746
16185
  const json = await res.json();
15747
16186
  return this.parseResponse(json);
15748
16187
  }
15749
16188
  async *completeStream(request) {
15750
16189
  const body = this.buildRequestBody(request, true);
15751
- const res = await this.doFetch(body);
16190
+ const res = await this.doFetch(body, request.signal);
15752
16191
  if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
15753
16192
  let id = "";
15754
16193
  let model = "";
@@ -15758,7 +16197,7 @@ var AnthropicProvider = class extends BaseProvider {
15758
16197
  let cacheCreationInputTokens = 0;
15759
16198
  const currentToolCalls = /* @__PURE__ */ new Map();
15760
16199
  const reasoningBlocks = /* @__PURE__ */ new Map();
15761
- for await (const event of parseSSEStream(res.body)) {
16200
+ for await (const event of parseSSEStream(res.body, request.signal)) {
15762
16201
  let data;
15763
16202
  try {
15764
16203
  data = JSON.parse(event.data);
@@ -16038,7 +16477,7 @@ var AnthropicProvider = class extends BaseProvider {
16038
16477
  input_schema: t.parameters
16039
16478
  };
16040
16479
  }
16041
- async doFetch(body) {
16480
+ async doFetch(body, signal) {
16042
16481
  const url = `${this.baseURL}/v1/messages`;
16043
16482
  const headers = {
16044
16483
  "Content-Type": "application/json",
@@ -16047,7 +16486,7 @@ var AnthropicProvider = class extends BaseProvider {
16047
16486
  ...this.defaultHeaders
16048
16487
  };
16049
16488
  const payload = JSON.stringify(body);
16050
- const res = await this.doFetchWithRetry(() => fetch(url, { method: "POST", headers, body: payload }));
16489
+ const res = await this.doFetchWithRetry(() => fetch(url, { method: "POST", headers, body: payload, signal }), signal);
16051
16490
  if (!res.ok) {
16052
16491
  const text = await res.text().catch(() => "");
16053
16492
  throw new ProviderError(
@@ -16157,7 +16596,7 @@ var AzureProvider = class extends OpenAIProvider {
16157
16596
  this.deploymentName = config.deploymentName;
16158
16597
  this.azureApiKey = config.apiKey;
16159
16598
  }
16160
- async doFetch(body) {
16599
+ async doFetch(body, signal) {
16161
16600
  const deployment = this.deploymentName ?? body.model;
16162
16601
  if (!deployment) {
16163
16602
  throw new ProviderError("Azure requires a deploymentName or model", this.providerName);
@@ -16171,7 +16610,8 @@ var AzureProvider = class extends OpenAIProvider {
16171
16610
  "api-key": this.azureApiKey,
16172
16611
  ...this.defaultHeaders
16173
16612
  },
16174
- body: JSON.stringify(bodyWithoutModel)
16613
+ body: JSON.stringify(bodyWithoutModel),
16614
+ signal
16175
16615
  });
16176
16616
  if (!res.ok) {
16177
16617
  const text = await res.text().catch(() => "");
@@ -16187,7 +16627,7 @@ var AzureProvider = class extends OpenAIProvider {
16187
16627
  /** Azure exposes the Responses API at /openai/responses with api-key auth.
16188
16628
  * Reasoning summaries require a preview api-version; callers can override via
16189
16629
  * the `apiVersion` config. */
16190
- async responsesFetch(body) {
16630
+ async responsesFetch(body, signal) {
16191
16631
  body.input = expandAzureResponsesInput(body.input);
16192
16632
  const deployment = this.deploymentName ?? body.model;
16193
16633
  if (!deployment) {
@@ -16202,7 +16642,8 @@ var AzureProvider = class extends OpenAIProvider {
16202
16642
  "api-key": this.azureApiKey,
16203
16643
  ...this.defaultHeaders
16204
16644
  },
16205
- body: payload
16645
+ body: payload,
16646
+ signal
16206
16647
  });
16207
16648
  if (!res.ok) {
16208
16649
  const text = await res.text().catch(() => "");
@@ -16270,7 +16711,7 @@ var BedrockProvider = class extends BaseProvider {
16270
16711
  async complete(request) {
16271
16712
  const modelId = request.model || this.defaultModel;
16272
16713
  const body = this.buildConverseBody(request);
16273
- const json = await this.doFetch(modelId, body);
16714
+ const json = await this.doFetch(modelId, body, request.signal);
16274
16715
  return this.parseResponse(json, modelId);
16275
16716
  }
16276
16717
  async *completeStream(request) {
@@ -16447,7 +16888,7 @@ var BedrockProvider = class extends BaseProvider {
16447
16888
  }
16448
16889
  };
16449
16890
  }
16450
- async doFetch(modelId, body) {
16891
+ async doFetch(modelId, body, signal) {
16451
16892
  const host = `bedrock-runtime.${this.region}.amazonaws.com`;
16452
16893
  const url = `https://${host}/model/${encodeURIComponent(modelId)}/converse`;
16453
16894
  const bodyStr = JSON.stringify(body);
@@ -16465,8 +16906,8 @@ var BedrockProvider = class extends BaseProvider {
16465
16906
  service: "bedrock",
16466
16907
  credentials: this.credentials
16467
16908
  });
16468
- return fetch(url, { method: "POST", headers, body: bodyStr });
16469
- });
16909
+ return fetch(url, { method: "POST", headers, body: bodyStr, signal });
16910
+ }, signal);
16470
16911
  if (!res.ok) {
16471
16912
  const text = await res.text().catch(() => "");
16472
16913
  throw new ProviderError(
@@ -16599,7 +17040,7 @@ var VertexProvider = class extends BaseProvider {
16599
17040
  const modelId = request.model || this.defaultModel;
16600
17041
  const body = this.buildGeminiBody(request);
16601
17042
  const url = this.buildUrl(modelId, false);
16602
- const res = await this.doFetch(url, body);
17043
+ const res = await this.doFetch(url, body, request.signal);
16603
17044
  const json = await res.json();
16604
17045
  return this.parseResponse(json, modelId);
16605
17046
  }
@@ -16607,11 +17048,11 @@ var VertexProvider = class extends BaseProvider {
16607
17048
  const modelId = request.model || this.defaultModel;
16608
17049
  const body = this.buildGeminiBody(request);
16609
17050
  const url = this.buildUrl(modelId, true);
16610
- const res = await this.doFetch(url, body);
17051
+ const res = await this.doFetch(url, body, request.signal);
16611
17052
  if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
16612
17053
  const contentType = res.headers.get("content-type") ?? "";
16613
17054
  if (contentType.includes("text/event-stream")) {
16614
- for await (const event of parseSSEStream(res.body)) {
17055
+ for await (const event of parseSSEStream(res.body, request.signal)) {
16615
17056
  if (event.data === "[DONE]") break;
16616
17057
  let chunk;
16617
17058
  try {
@@ -16653,6 +17094,7 @@ var VertexProvider = class extends BaseProvider {
16653
17094
  }
16654
17095
  }
16655
17096
  } finally {
17097
+ reader.cancel().catch(() => void 0);
16656
17098
  reader.releaseLock();
16657
17099
  }
16658
17100
  }
@@ -16864,7 +17306,7 @@ var VertexProvider = class extends BaseProvider {
16864
17306
  const tokenJson = await tokenRes.json();
16865
17307
  return tokenJson.access_token;
16866
17308
  }
16867
- async doFetch(url, body) {
17309
+ async doFetch(url, body, signal) {
16868
17310
  const token = await this.getAccessToken();
16869
17311
  const res = await fetch(url, {
16870
17312
  method: "POST",
@@ -16873,7 +17315,8 @@ var VertexProvider = class extends BaseProvider {
16873
17315
  Authorization: `Bearer ${token}`,
16874
17316
  ...this.defaultHeaders
16875
17317
  },
16876
- body: JSON.stringify(body)
17318
+ body: JSON.stringify(body),
17319
+ signal
16877
17320
  });
16878
17321
  if (!res.ok) {
16879
17322
  const text = await res.text().catch(() => "");
@@ -17012,11 +17455,13 @@ function createProvider(config) {
17012
17455
  return new BedrockProvider(config);
17013
17456
  case "vertex":
17014
17457
  return new VertexProvider(config);
17458
+ case "jev":
17459
+ return new JevProvider(config);
17015
17460
  default:
17016
17461
  throw new Error(`Unknown provider: ${config.provider}`);
17017
17462
  }
17018
17463
  }
17019
17464
 
17020
- export { ASK_USER_TOOL_NAME, AnthropicProvider, AzureProvider, BaseProvider, BedrockProvider, CCRStore, CONSOLE_HOOK_MAP, CONTEXT_PILOT_JSON_MARKER_KEY, CONTROL_PLANE_TOOL_NAMES, DEFAULT_MAX_TOOL_INPUT_FIELD_CHARS, DEFAULT_PROFILE_CONFIGS, DEFAULT_SKILL_POLICY, DEFAULT_SUBAGENT_POLICY, DEFAULT_SUBAGENT_TOOL_NAMES, DEFAULT_TOOL_INPUT_DIGEST_HEAD_CHARS, DELEGATION_TOOL_NAMES, DedupTracker, GuardrailPhase, HOOK_CONTRACT_VERSION, HOOK_NAMES, HookTimeoutError, InMemoryMemoryStore, NativeJsonSchemaStrategy, OpenAICompatibleProvider, OpenAIProvider, PREOPEN_TOOL_CALL_PREFIX, ProviderError, SMALL_TIER_SKILL_POLICY, StructuredOutputManager, TOOL_INPUT_DIGEST_KEY, ToolBasedStrategy, VertexProvider, agentVerdictRule, appendBoundTools, auditLog, azureContentSafety, bedrockGuardrail, budgetGuard, buildHandoffTools, buildResponseFormatSection, buildSkillHeaderBlock, buildSubagentCatalogBlock, buildSystemPrompt, buildToolDefinitionsSection, canOpenSkill, canSpawn, captureSnapshot, checkpointing, codePresenceRule, coerceToolArgs, cognipeerGuardrail, cognipeerSink, collectAttachments, collectToolRetentionDeclarations, composeToolSets, compressDiffOutput, compressJsonOutput, compressLogOutput, compressSearchOutput, compressTextOutput, compressToolOutput, contentToString, conversationHistory, countApproxTokens, countMessagesTokens, createAgent, createAgentNode, createAskUserQuestionTool, createBindSkillToolsTool, createCodeGuardrail, createContextPilotRuntime, createContextSummarizeNode, createContextTools, createDelegateTool, createGetToolResponseTool, createGuardrail, createGuardrailPlugin, createJsonGuardrail, createManageTodoListAliasTool, createManageTodoTool, createOpenSkillTool, createParallelTool, createPluginHost, createProvider, createRegexGuardrail, createResolverNode, createSearchSkillsTool, createSkillRegistryRef, createSkillTools, createSmartAgent, createSpawnTool, createSubagentRegistryRef, createSubagentTools, createTool, createToolLimitFinalizeNode, createToolsNode, customCallbackRule, customGuardrail, customSink, dedupeToolsByName, defaultTokenCounter, defineHook, definePlugin, detectLanguage, detectTextFormat, detectVolatileContent, digestToolInputArguments, digestToolInputValue, emptyUsage, evaluateGuardrails, extractLatestUserQuery, extractMessageText2 as extractMessageText, fileCheckpointStore, fileSink, findSubagent, formatZodError, fromLangchainModel, fromLangchainTools, fromNativeProvider, generateSpanId, generateTraceId, getModelCapabilities, getNestedValue, getResolvedSmartConfig, getTokenCounter, hasToolResponseRecoveryReference, httpGuardrail, httpSink, inMemoryCheckpointStore, inMemoryConversationStore, isHookImplemented, isOpenAIHostedEndpoint, isSmartModel, isValidIban, isValidLuhn, isValidTckn, jsonSchemaRule, defaultBuildPayload as langfuseDefaultPayload, langfuseTracing, languageGuard, loadSkillsFromDisk, mapConsoleHookVerdict, mapTextParts, mcp, mediaPolicy, normalizeSmartAgentOptions, normalizeVerdicts, openAIModeration, otelTracing, otlpSink, outputGuard, parseApprovalDecision, parseSkillFrontmatter, pathSandbox, piiRedaction, pluginCapabilities, portkeyGateway, portkeyGuardrail, preopenSkills, preopenToolCallId, prepareStrictToolMenu, promptInjectionGuard, rateLimit, readMemoryFacts, redactText, regexGuardrail, regexRule, replaceTextContent, resolveAvailableSkills, resolveAvailableSubagents, resolveInputRetention, resolveMemoryStore, resolveReasoning, resolveStrategy, resolveSubagentTools, resolveSummarizationRetention, resolveToolApprovalState, resolveUserQuestionState, responseCache, restoreSnapshot, restoreToolCalls, runSmartAgentEvalHarness, scoreItemsByRelevance, searchSkills, seedChildMessages, selectTopIndicesInOrder, sessionMetrics, setTokenCounter, startStreamingSession, summarizeObject, textFromContent, toStrictCompatible, toStrictToolSchema, tokenize, toolPolicy, traceSessionToOtlp, validateReasoningConfig, validateToolArgs, webhookApproval, withTools, withinDepth, writeSummaryFactsToMemory };
17465
+ export { ASK_USER_TOOL_NAME, AnthropicProvider, AzureProvider, BaseProvider, BedrockProvider, CCRStore, CONSOLE_HOOK_MAP, CONTEXT_PILOT_JSON_MARKER_KEY, CONTROL_PLANE_TOOL_NAMES, DEFAULT_MAX_TOOL_INPUT_FIELD_CHARS, DEFAULT_PROFILE_CONFIGS, DEFAULT_SKILL_POLICY, DEFAULT_SUBAGENT_POLICY, DEFAULT_SUBAGENT_TOOL_NAMES, DEFAULT_TOOL_INPUT_DIGEST_HEAD_CHARS, DELEGATION_TOOL_NAMES, DedupTracker, GuardrailPhase, HOOK_CONTRACT_VERSION, HOOK_NAMES, HookTimeoutError, InMemoryMemoryStore, JevProvider, NativeJsonSchemaStrategy, OpenAICompatibleProvider, OpenAIProvider, PREOPEN_TOOL_CALL_PREFIX, ProviderError, SMALL_TIER_SKILL_POLICY, StructuredOutputManager, TOOL_INPUT_DIGEST_KEY, ToolBasedStrategy, VertexProvider, agentVerdictRule, appendBoundTools, auditLog, azureContentSafety, bedrockGuardrail, budgetGuard, buildHandoffTools, buildResponseFormatSection, buildSkillHeaderBlock, buildSubagentCatalogBlock, buildSystemPrompt, buildToolDefinitionsSection, canOpenSkill, canSpawn, captureSnapshot, checkpointing, codePresenceRule, coerceToolArgs, cognipeerGuardrail, cognipeerSink, collectAttachments, collectToolRetentionDeclarations, composeToolSets, compressDiffOutput, compressJsonOutput, compressLogOutput, compressSearchOutput, compressTextOutput, compressToolOutput, contentPartToText, contentToString, conversationHistory, countApproxTokens, countMessagesTokens, createAgent, createAgentNode, createAskUserQuestionTool, createBindSkillToolsTool, createCodeGuardrail, createContextPilotRuntime, createContextSummarizeNode, createContextTools, createDelegateTool, createGetToolResponseTool, createGuardrail, createGuardrailPlugin, createJsonGuardrail, createManageTodoListAliasTool, createManageTodoTool, createOpenSkillTool, createParallelTool, createPluginHost, createProvider, createRegexGuardrail, createResolverNode, createSearchSkillsTool, createSkillRegistryRef, createSkillTools, createSmartAgent, createSpawnTool, createSubagentRegistryRef, createSubagentTools, createTool, createToolLimitFinalizeNode, createToolsNode, customCallbackRule, customGuardrail, customSink, dedupeToolsByName, defaultTokenCounter, defineHook, definePlugin, describeContentPart, detectLanguage, detectTextFormat, detectVolatileContent, digestToolInputArguments, digestToolInputValue, emptyUsage, evaluateGuardrails, extractLatestUserQuery, extractMessageText, fileCheckpointStore, fileSink, findSubagent, formatZodError, fromLangchainModel, fromLangchainTools, fromNativeProvider, generateSpanId, generateTraceId, getModelCapabilities, getNestedValue, getResolvedSmartConfig, getTokenCounter, hasMediaPart, hasToolResponseRecoveryReference, httpGuardrail, httpSink, inMemoryCheckpointStore, inMemoryConversationStore, isHookImplemented, isOpenAIHostedEndpoint, isSmartModel, isValidIban, isValidLuhn, isValidTckn, jsonSchemaRule, defaultBuildPayload as langfuseDefaultPayload, langfuseTracing, languageGuard, loadSkillsFromDisk, mapConsoleHookVerdict, mapTextParts, mcp, mediaKindOf, mediaPolicy, normalizeSmartAgentOptions, normalizeVerdicts, openAIModeration, otelTracing, otlpSink, outputGuard, parseApprovalDecision, parseSkillFrontmatter, pathSandbox, piiRedaction, pluginCapabilities, portkeyGateway, portkeyGuardrail, preopenSkills, preopenToolCallId, prepareStrictToolMenu, promptInjectionGuard, rateLimit, readMemoryFacts, redactText, regexGuardrail, regexRule, replaceTextContent, resolveAvailableSkills, resolveAvailableSubagents, resolveInputRetention, resolveMemoryStore, resolveReasoning, resolveStrategy, resolveSubagentTools, resolveSummarizationRetention, resolveToolApprovalState, resolveUserQuestionState, responseCache, restoreSnapshot, restoreToolCalls, runSmartAgentEvalHarness, scoreItemsByRelevance, searchSkills, seedChildMessages, selectTopIndicesInOrder, sessionMetrics, setTokenCounter, startStreamingSession, summarizeObject, textFromContent, toStrictCompatible, toStrictToolSchema, tokenize, toolPolicy, traceSessionToOtlp, validateReasoningConfig, validateToolArgs, webhookApproval, withTools, withinDepth, writeSummaryFactsToMemory };
17021
17466
  //# sourceMappingURL=index.mjs.map
17022
17467
  //# sourceMappingURL=index.mjs.map