@cognipeer/agent-sdk 0.10.6 → 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.mjs CHANGED
@@ -2431,6 +2431,15 @@ function estimatePayloadBytes(value) {
2431
2431
  }
2432
2432
  }
2433
2433
  }
2434
+ function toMessageUsage(u) {
2435
+ return {
2436
+ prompt_tokens: u.inputTokens,
2437
+ completion_tokens: u.outputTokens,
2438
+ total_tokens: u.totalTokens,
2439
+ prompt_tokens_details: { cached_tokens: u.cachedInputTokens, cache_write_tokens: u.cachedWriteTokens },
2440
+ completion_tokens_details: { reasoning_tokens: u.reasoningTokens }
2441
+ };
2442
+ }
2434
2443
  function fromNativeProvider(provider, options) {
2435
2444
  let boundTools = options?.__tools;
2436
2445
  const modelName = options?.model ?? provider.defaultModel ?? provider.providerName;
@@ -2440,8 +2449,9 @@ function fromNativeProvider(provider, options) {
2440
2449
  invoke: async (messages, _invokeOptions) => {
2441
2450
  const link = linkAbortSignal(_invokeOptions);
2442
2451
  try {
2443
- const request = buildRequest(messages, boundTools, options, _invokeOptions);
2452
+ let request = buildRequest(messages, boundTools, options, _invokeOptions);
2444
2453
  if (link.signal) request.signal = link.signal;
2454
+ request = await applyTransform(request);
2445
2455
  const response = await provider.complete(request);
2446
2456
  return toBaseChatMessage(response);
2447
2457
  } finally {
@@ -2451,33 +2461,46 @@ function fromNativeProvider(provider, options) {
2451
2461
  stream: async function* (messages, _invokeOptions) {
2452
2462
  const link = linkAbortSignal(_invokeOptions);
2453
2463
  try {
2454
- const request = buildRequest(messages, boundTools, options, _invokeOptions);
2464
+ let request = buildRequest(messages, boundTools, options, _invokeOptions);
2455
2465
  request.stream = true;
2456
2466
  if (link.signal) request.signal = link.signal;
2467
+ request = await applyTransform(request);
2457
2468
  let fullContent = "";
2458
2469
  let allToolCalls = [];
2459
2470
  let lastUsage;
2460
2471
  let reasoningBlocks;
2472
+ let reasoningText = "";
2473
+ let finishReason;
2474
+ let responseModel;
2461
2475
  const toolCallBuffers = /* @__PURE__ */ new Map();
2462
2476
  for await (const chunk of provider.completeStream(request)) {
2463
2477
  if (chunk.delta.content) {
2464
2478
  fullContent += chunk.delta.content;
2465
2479
  yield chunk.delta.content;
2466
2480
  }
2481
+ if (chunk.model) responseModel = chunk.model;
2482
+ if (chunk.finishReason) finishReason = chunk.finishReason;
2467
2483
  if (chunk.delta.reasoning?.blocks?.length) {
2468
2484
  reasoningBlocks = chunk.delta.reasoning.blocks;
2469
2485
  }
2486
+ const reasoningDelta = chunk.delta.reasoning?.summary;
2487
+ if (reasoningDelta) {
2488
+ reasoningText += reasoningDelta;
2489
+ yield { type: "reasoning", reasoning_content: reasoningDelta };
2490
+ }
2470
2491
  if (chunk.delta.toolCalls) {
2471
2492
  for (const tc of chunk.delta.toolCalls) {
2472
2493
  if (tc.id) {
2473
2494
  const existing = toolCallBuffers.get(tc.id);
2474
2495
  if (existing) {
2475
2496
  if (tc.arguments) existing.arguments += tc.arguments;
2497
+ if (tc.thoughtSignature) existing.thoughtSignature = tc.thoughtSignature;
2476
2498
  } else {
2477
2499
  toolCallBuffers.set(tc.id, {
2478
2500
  id: tc.id,
2479
2501
  name: tc.name ?? "",
2480
- arguments: tc.arguments ?? ""
2502
+ arguments: tc.arguments ?? "",
2503
+ ...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {}
2481
2504
  });
2482
2505
  }
2483
2506
  }
@@ -2488,8 +2511,18 @@ function fromNativeProvider(provider, options) {
2488
2511
  if (link.signal?.aborted) return;
2489
2512
  allToolCalls = [...toolCallBuffers.values()];
2490
2513
  const finalMessage = assembleMessage(fullContent, allToolCalls, lastUsage);
2491
- if (reasoningBlocks?.length) {
2492
- finalMessage.reasoning = { blocks: reasoningBlocks };
2514
+ if (reasoningBlocks?.length || reasoningText) {
2515
+ finalMessage.reasoning = {
2516
+ ...reasoningBlocks?.length ? { blocks: reasoningBlocks } : {},
2517
+ ...reasoningText ? { summary: reasoningText } : {}
2518
+ };
2519
+ }
2520
+ if (finishReason || responseModel) {
2521
+ finalMessage.response_metadata = {
2522
+ ...finalMessage.response_metadata ?? {},
2523
+ ...finishReason ? { finish_reason: finishReason } : {},
2524
+ ...responseModel ? { model_name: responseModel } : {}
2525
+ };
2493
2526
  }
2494
2527
  yield finalMessage;
2495
2528
  } finally {
@@ -2503,6 +2536,11 @@ function fromNativeProvider(provider, options) {
2503
2536
  }
2504
2537
  };
2505
2538
  return adapted;
2539
+ async function applyTransform(req) {
2540
+ if (!options?.transformRequest) return req;
2541
+ const out = await options.transformRequest(req);
2542
+ return out ?? req;
2543
+ }
2506
2544
  function buildRequest(messages, tools, opts, invokeOptions) {
2507
2545
  const req = {
2508
2546
  model: opts?.model ?? modelName,
@@ -2510,6 +2548,10 @@ function fromNativeProvider(provider, options) {
2510
2548
  };
2511
2549
  if (opts?.temperature != null) req.temperature = opts.temperature;
2512
2550
  if (opts?.maxTokens != null) req.maxTokens = opts.maxTokens;
2551
+ if (opts?.topP != null) req.topP = opts.topP;
2552
+ if (opts?.stop?.length) req.stop = opts.stop;
2553
+ if (opts?.presencePenalty != null) req.presencePenalty = opts.presencePenalty;
2554
+ if (opts?.frequencyPenalty != null) req.frequencyPenalty = opts.frequencyPenalty;
2513
2555
  if (tools?.length) req.tools = tools;
2514
2556
  if (opts?.extra) req.extra = opts.extra;
2515
2557
  const reasoningOverride = invokeOptions?.reasoning;
@@ -2562,7 +2604,8 @@ function toUnifiedMessage(msg) {
2562
2604
  unified.toolCalls = msg.tool_calls.map((tc) => ({
2563
2605
  id: tc.id,
2564
2606
  name: tc.function?.name ?? tc.name ?? "",
2565
- arguments: tc.function?.arguments ?? tc.arguments ?? "{}"
2607
+ arguments: tc.function?.arguments ?? tc.arguments ?? "{}",
2608
+ ...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {}
2566
2609
  }));
2567
2610
  }
2568
2611
  const reasoning = msg.reasoning;
@@ -2836,29 +2879,16 @@ function toToolDefinition(tool, strict) {
2836
2879
  }
2837
2880
  return { name, description, parameters, ...useStrict ? { strict: true } : {} };
2838
2881
  }
2882
+ function legacyTokenUsage(u) {
2883
+ return { ...toMessageUsage(u), cached_tokens: u.cachedInputTokens, cache_write_tokens: u.cachedWriteTokens };
2884
+ }
2839
2885
  function toBaseChatMessage(response) {
2840
2886
  const msg = {
2841
2887
  role: "assistant",
2842
2888
  content: response.content ?? "",
2843
- usage: {
2844
- prompt_tokens: response.usage.inputTokens,
2845
- completion_tokens: response.usage.outputTokens,
2846
- total_tokens: response.usage.totalTokens,
2847
- prompt_tokens_details: {
2848
- cached_tokens: response.usage.cachedInputTokens
2849
- },
2850
- completion_tokens_details: {
2851
- reasoning_tokens: response.usage.reasoningTokens
2852
- }
2853
- },
2889
+ usage: toMessageUsage(response.usage),
2854
2890
  response_metadata: {
2855
- token_usage: {
2856
- prompt_tokens: response.usage.inputTokens,
2857
- completion_tokens: response.usage.outputTokens,
2858
- total_tokens: response.usage.totalTokens,
2859
- cached_tokens: response.usage.cachedInputTokens,
2860
- cache_write_tokens: response.usage.cachedWriteTokens
2861
- },
2891
+ token_usage: legacyTokenUsage(response.usage),
2862
2892
  finish_reason: response.finishReason,
2863
2893
  model_name: response.model
2864
2894
  }
@@ -2867,7 +2897,8 @@ function toBaseChatMessage(response) {
2867
2897
  msg.tool_calls = response.toolCalls.map((tc) => ({
2868
2898
  id: tc.id,
2869
2899
  type: "function",
2870
- function: { name: tc.name, arguments: tc.arguments }
2900
+ function: { name: tc.name, arguments: tc.arguments },
2901
+ ...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {}
2871
2902
  }));
2872
2903
  }
2873
2904
  if (response.reasoning && (response.reasoning.blocks?.length || response.reasoning.summary)) {
@@ -2881,32 +2912,15 @@ function assembleMessage(content, toolCalls, usage) {
2881
2912
  content
2882
2913
  };
2883
2914
  if (usage) {
2884
- msg.usage = {
2885
- prompt_tokens: usage.inputTokens,
2886
- completion_tokens: usage.outputTokens,
2887
- total_tokens: usage.totalTokens,
2888
- prompt_tokens_details: {
2889
- cached_tokens: usage.cachedInputTokens
2890
- },
2891
- completion_tokens_details: {
2892
- reasoning_tokens: usage.reasoningTokens
2893
- }
2894
- };
2895
- msg.response_metadata = {
2896
- token_usage: {
2897
- prompt_tokens: usage.inputTokens,
2898
- completion_tokens: usage.outputTokens,
2899
- total_tokens: usage.totalTokens,
2900
- cached_tokens: usage.cachedInputTokens,
2901
- cache_write_tokens: usage.cachedWriteTokens
2902
- }
2903
- };
2915
+ msg.usage = toMessageUsage(usage);
2916
+ msg.response_metadata = { token_usage: legacyTokenUsage(usage) };
2904
2917
  }
2905
2918
  if (toolCalls.length > 0) {
2906
2919
  msg.tool_calls = toolCalls.map((tc) => ({
2907
2920
  id: tc.id,
2908
2921
  type: "function",
2909
- function: { name: tc.name, arguments: tc.arguments }
2922
+ function: { name: tc.name, arguments: tc.arguments },
2923
+ ...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {}
2910
2924
  }));
2911
2925
  }
2912
2926
  return msg;
@@ -2939,8 +2953,8 @@ function resolveCapabilities(provider) {
2939
2953
  return {
2940
2954
  structuredOutput: "tool_based",
2941
2955
  strictToolCalling: false,
2942
- streaming: false,
2943
- // streaming uses binary protocol
2956
+ streaming: true,
2957
+ // ConverseStream (AWS event-stream frames)
2944
2958
  provider: "bedrock"
2945
2959
  };
2946
2960
  case "vertex":
@@ -4646,6 +4660,10 @@ ${append}`;
4646
4660
  if (chunk && typeof chunk === "object" && chunk.role) {
4647
4661
  streamedMessage = chunk;
4648
4662
  }
4663
+ if (chunk && typeof chunk === "object" && chunk.type === "reasoning" && typeof chunk.reasoning_content === "string") {
4664
+ onEvent?.({ type: "reasoning", text: chunk.reasoning_content });
4665
+ continue;
4666
+ }
4649
4667
  const text = extractText2(chunk);
4650
4668
  const isAssembledMessage = Boolean(chunk && typeof chunk === "object" && chunk.role) && text.length > 0 && text === streamedText;
4651
4669
  if (text && !isAssembledMessage) {
@@ -11526,6 +11544,28 @@ async function runSmartAgentEvalHarness(params) {
11526
11544
  return results;
11527
11545
  }
11528
11546
 
11547
+ // src/providers/types.ts
11548
+ function emptyUsage() {
11549
+ return {
11550
+ inputTokens: 0,
11551
+ outputTokens: 0,
11552
+ totalTokens: 0,
11553
+ cachedInputTokens: 0,
11554
+ cachedWriteTokens: 0,
11555
+ cachedOutputTokens: 0,
11556
+ reasoningTokens: 0
11557
+ };
11558
+ }
11559
+ var ProviderError = class extends Error {
11560
+ constructor(message, provider, statusCode, responseBody) {
11561
+ super(message);
11562
+ this.provider = provider;
11563
+ this.statusCode = statusCode;
11564
+ this.responseBody = responseBody;
11565
+ this.name = "ProviderError";
11566
+ }
11567
+ };
11568
+
11529
11569
  // src/providers/base.ts
11530
11570
  var DEFAULT_RETRY = {
11531
11571
  maxRetries: 3,
@@ -11536,6 +11576,55 @@ var BaseProvider = class {
11536
11576
  constructor() {
11537
11577
  this.retryPolicy = DEFAULT_RETRY;
11538
11578
  }
11579
+ /** Applies the transport options shared by every provider config. */
11580
+ configureTransport(config) {
11581
+ this.fetchImpl = config.fetch;
11582
+ this.timeoutMs = typeof config.timeoutMs === "number" && config.timeoutMs > 0 ? config.timeoutMs : void 0;
11583
+ }
11584
+ /**
11585
+ * The single HTTP entry point for every provider call site. Uses the
11586
+ * configured `fetch` and applies `timeoutMs`: the timer covers the time until
11587
+ * the response HEADERS arrive and is cleared after that, so a long-running
11588
+ * stream is never cut by it (use the request `signal` to cancel a stream).
11589
+ * A timeout surfaces as a `ProviderError` with status 408. The caller's
11590
+ * `signal` still aborts the request as before.
11591
+ */
11592
+ async httpFetch(url, init = {}) {
11593
+ const doFetch = this.fetchImpl ?? fetch;
11594
+ const timeoutMs = this.timeoutMs;
11595
+ if (!timeoutMs) return doFetch(url, init);
11596
+ const controller = new AbortController();
11597
+ const outer = init.signal ?? void 0;
11598
+ let timedOut = false;
11599
+ const onOuterAbort = () => controller.abort(outer?.reason);
11600
+ if (outer) {
11601
+ if (outer.aborted) controller.abort(outer.reason);
11602
+ else outer.addEventListener("abort", onOuterAbort, { once: true });
11603
+ }
11604
+ const timer = setTimeout(() => {
11605
+ timedOut = true;
11606
+ controller.abort(new Error(`timed out after ${timeoutMs}ms`));
11607
+ }, timeoutMs);
11608
+ try {
11609
+ const res = await doFetch(url, { ...init, signal: controller.signal });
11610
+ return res;
11611
+ } catch (err) {
11612
+ if (timedOut) {
11613
+ throw new ProviderError(`${this.providerName} request timed out after ${timeoutMs}ms`, this.providerName, 408);
11614
+ }
11615
+ throw err;
11616
+ } finally {
11617
+ clearTimeout(timer);
11618
+ }
11619
+ }
11620
+ /**
11621
+ * Embeds `request.input`. Implemented by the providers that have an
11622
+ * embeddings endpoint (OpenAI, Azure, openai-compatible, Bedrock, Vertex);
11623
+ * the others reject with a 400 ProviderError.
11624
+ */
11625
+ async embed(_request) {
11626
+ throw new ProviderError(`${this.providerName} does not support embeddings`, this.providerName, 400);
11627
+ }
11539
11628
  /**
11540
11629
  * Helper concrete providers can wrap their fetch with. Retries 429/5xx
11541
11630
  * with exponential backoff and respects Retry-After if the response
@@ -11577,34 +11666,13 @@ var BaseProvider = class {
11577
11666
  }
11578
11667
  };
11579
11668
 
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
11669
  // src/providers/jev.ts
11603
11670
  var JEV_DEFAULT_BASE_URL = "https://api.typesafe.ai";
11604
11671
  var JevProvider = class extends BaseProvider {
11605
11672
  constructor(config) {
11606
11673
  super();
11607
11674
  this.providerName = "jev";
11675
+ this.configureTransport(config);
11608
11676
  this.apiKey = config.apiKey;
11609
11677
  this.baseURL = (config.baseURL ?? JEV_DEFAULT_BASE_URL).replace(/\/$/, "");
11610
11678
  this.defaultModel = config.defaultModel;
@@ -11620,7 +11688,7 @@ var JevProvider = class extends BaseProvider {
11620
11688
  questions: request.questions
11621
11689
  };
11622
11690
  const res = await this.doFetchWithRetry(
11623
- () => fetch(`${this.baseURL}/v1/systemone`, {
11691
+ () => this.httpFetch(`${this.baseURL}/v1/systemone`, {
11624
11692
  method: "POST",
11625
11693
  headers: {
11626
11694
  "Content-Type": "application/json",
@@ -13856,12 +13924,12 @@ function responseCache(config = {}) {
13856
13924
  };
13857
13925
  }
13858
13926
  function signRequest(req) {
13859
- const now = /* @__PURE__ */ new Date();
13927
+ const now = req.now ?? /* @__PURE__ */ new Date();
13860
13928
  const dateStamp = toDateStamp(now);
13861
13929
  const amzDate = toAmzDate(now);
13862
13930
  const parsed = new URL(req.url);
13863
13931
  const host = parsed.host;
13864
- const canonicalUri = parsed.pathname || "/";
13932
+ const canonicalUri = (parsed.pathname || "/").split("/").map((seg) => encodeURIComponent(seg).replace(/[!'()*]/g, (c) => "%" + c.charCodeAt(0).toString(16).toUpperCase())).join("/");
13865
13933
  const canonicalQuerystring = sortQueryParams(parsed.searchParams);
13866
13934
  const headers = {
13867
13935
  ...req.headers,
@@ -15178,73 +15246,6 @@ function languageGuard(config) {
15178
15246
  // src/index.ts
15179
15247
  init_content();
15180
15248
 
15181
- // src/providers/utils/sse.ts
15182
- async function* parseSSEStream(body, signal) {
15183
- const reader = body.getReader();
15184
- const decoder = new TextDecoder();
15185
- let buffer = "";
15186
- try {
15187
- while (true) {
15188
- if (signal?.aborted) throw abortReason(signal);
15189
- const { done, value } = await reader.read();
15190
- if (done) break;
15191
- buffer += decoder.decode(value, { stream: true });
15192
- const parts = buffer.split(/\r?\n\r?\n/);
15193
- buffer = parts.pop() ?? "";
15194
- for (const part of parts) {
15195
- if (!part.trim()) continue;
15196
- const event = parseSSEBlock(part);
15197
- if (event) yield event;
15198
- }
15199
- }
15200
- if (buffer.trim()) {
15201
- const event = parseSSEBlock(buffer);
15202
- if (event) yield event;
15203
- }
15204
- } finally {
15205
- reader.cancel().catch(() => void 0);
15206
- reader.releaseLock();
15207
- }
15208
- }
15209
- function parseSSEBlock(block) {
15210
- let event;
15211
- let id;
15212
- let retry;
15213
- const dataLines = [];
15214
- for (const line of block.split(/\r?\n/)) {
15215
- if (line.startsWith(":")) continue;
15216
- const colonIdx = line.indexOf(":");
15217
- let field;
15218
- let value;
15219
- if (colonIdx === -1) {
15220
- field = line;
15221
- value = "";
15222
- } else {
15223
- field = line.slice(0, colonIdx);
15224
- value = line.slice(colonIdx + 1);
15225
- if (value.startsWith(" ")) value = value.slice(1);
15226
- }
15227
- switch (field) {
15228
- case "event":
15229
- event = value;
15230
- break;
15231
- case "data":
15232
- dataLines.push(value);
15233
- break;
15234
- case "id":
15235
- id = value;
15236
- break;
15237
- case "retry": {
15238
- const n = parseInt(value, 10);
15239
- if (!isNaN(n)) retry = n;
15240
- break;
15241
- }
15242
- }
15243
- }
15244
- if (dataLines.length === 0) return null;
15245
- return { event, data: dataLines.join("\n"), id, retry };
15246
- }
15247
-
15248
15249
  // src/providers/utils/reasoning.ts
15249
15250
  var ANTHROPIC_EFFORT_BUDGET = {
15250
15251
  // 0 = off. `applyAnthropicReasoning` bails on a falsy budget and emits no
@@ -15266,6 +15267,7 @@ var GEMINI_EFFORT_BUDGET = {
15266
15267
  high: 12e3
15267
15268
  };
15268
15269
  var THINKING_OUTPUT_RESERVE = 1024;
15270
+ var MIN_THINKING_BUDGET = 1024;
15269
15271
  var THINKING_MIN_MAX_TOKENS = 4096;
15270
15272
  function applyOpenAIReasoning(body, reasoning, mode = "legacy_effort") {
15271
15273
  if (!reasoning) return;
@@ -15281,8 +15283,48 @@ function applyOpenAIReasoning(body, reasoning, mode = "legacy_effort") {
15281
15283
  if (reasoning.providerExtras) Object.assign(body, reasoning.providerExtras);
15282
15284
  }
15283
15285
  }
15284
- function applyAnthropicReasoning(body, reasoning) {
15286
+ function supportsAdaptiveThinking(model) {
15287
+ if (typeof model !== "string") return false;
15288
+ const id = model.toLowerCase();
15289
+ const at = id.indexOf("claude-");
15290
+ if (at < 0) return false;
15291
+ for (const tok of id.slice(at + 7).split("-")) {
15292
+ if (tok === "fable") return true;
15293
+ const m = /^(\d+)(?:@|$)/.exec(tok);
15294
+ if (m) {
15295
+ if (m[1].length <= 2) return Number(m[1]) >= 5;
15296
+ return false;
15297
+ }
15298
+ }
15299
+ return false;
15300
+ }
15301
+ function resolveThinkingForm(model, mode) {
15302
+ if (mode === "adaptive" || mode === "budget") return mode;
15303
+ return supportsAdaptiveThinking(model) ? "adaptive" : "budget";
15304
+ }
15305
+ function applyAdaptiveThinking(_body, reasoning, setThinking, setOutputConfig) {
15306
+ const requested = normalizeEffort(reasoning.effort);
15307
+ if (requested === "none") return false;
15308
+ let effort;
15309
+ if (requested) effort = requested === "minimal" ? "low" : requested;
15310
+ else if (typeof reasoning.budgetTokens === "number" && reasoning.budgetTokens > 0) {
15311
+ effort = reasoning.budgetTokens <= ANTHROPIC_EFFORT_BUDGET.low ? "low" : reasoning.budgetTokens <= ANTHROPIC_EFFORT_BUDGET.medium ? "medium" : "high";
15312
+ }
15313
+ if (!effort) return false;
15314
+ const thinking = { type: "adaptive" };
15315
+ if (reasoning.includeThoughts !== false) thinking.display = "summarized";
15316
+ if (reasoning.providerExtras) Object.assign(thinking, reasoning.providerExtras);
15317
+ setThinking({ thinking });
15318
+ setOutputConfig({ effort });
15319
+ return true;
15320
+ }
15321
+ function applyAnthropicReasoning(body, reasoning, opts) {
15285
15322
  if (!reasoning) return;
15323
+ if (resolveThinkingForm(opts?.model ?? body.model, opts?.mode) === "adaptive") {
15324
+ const on = applyAdaptiveThinking(body, reasoning, (extra) => body.thinking = extra.thinking, (o) => body.output_config = { ...body.output_config ?? {}, ...o });
15325
+ if (on) stripSamplingParams(body, ["temperature", "top_p", "top_k"]);
15326
+ return;
15327
+ }
15286
15328
  let budget = resolveBudget(reasoning, ANTHROPIC_EFFORT_BUDGET);
15287
15329
  if (!budget) return;
15288
15330
  const currentMax = typeof body.max_tokens === "number" ? body.max_tokens : 0;
@@ -15290,14 +15332,20 @@ function applyAnthropicReasoning(body, reasoning) {
15290
15332
  if (currentMax < requiredMax) {
15291
15333
  body.max_tokens = requiredMax;
15292
15334
  }
15293
- budget = clampBudget(budget, body.max_tokens);
15335
+ budget = Math.max(MIN_THINKING_BUDGET, clampBudget(budget, body.max_tokens));
15294
15336
  const thinking = { type: "enabled", budget_tokens: budget };
15295
15337
  if (reasoning.providerExtras) Object.assign(thinking, reasoning.providerExtras);
15296
15338
  body.thinking = thinking;
15297
15339
  stripSamplingParams(body, ["temperature", "top_p", "top_k"]);
15298
15340
  }
15299
- function applyBedrockReasoning(body, reasoning) {
15341
+ function applyBedrockReasoning(body, reasoning, opts) {
15300
15342
  if (!reasoning) return;
15343
+ if (resolveThinkingForm(opts?.model ?? body.modelId, opts?.mode) === "adaptive") {
15344
+ const fields = () => body.additionalModelRequestFields ?? (body.additionalModelRequestFields = {});
15345
+ const on = applyAdaptiveThinking(body, reasoning, (extra2) => fields().thinking = extra2.thinking, (o) => fields().output_config = { ...fields().output_config ?? {}, ...o });
15346
+ if (on && body.inferenceConfig) stripSamplingParams(body.inferenceConfig, ["temperature", "topP"]);
15347
+ return;
15348
+ }
15301
15349
  let budget = resolveBudget(reasoning, ANTHROPIC_EFFORT_BUDGET);
15302
15350
  if (!budget) return;
15303
15351
  const inference = body.inferenceConfig ?? (body.inferenceConfig = {});
@@ -15306,7 +15354,7 @@ function applyBedrockReasoning(body, reasoning) {
15306
15354
  if (currentMax < requiredMax) {
15307
15355
  inference.maxTokens = requiredMax;
15308
15356
  }
15309
- budget = clampBudget(budget, inference.maxTokens);
15357
+ budget = Math.max(MIN_THINKING_BUDGET, clampBudget(budget, inference.maxTokens));
15310
15358
  const extra = body.additionalModelRequestFields ?? (body.additionalModelRequestFields = {});
15311
15359
  const thinking = { type: "enabled", budget_tokens: budget };
15312
15360
  if (reasoning.providerExtras) Object.assign(thinking, reasoning.providerExtras);
@@ -15316,8 +15364,9 @@ function applyBedrockReasoning(body, reasoning) {
15316
15364
  function applyGeminiReasoning(generationConfig, reasoning) {
15317
15365
  if (!reasoning) return;
15318
15366
  const budget = resolveBudget(reasoning, GEMINI_EFFORT_BUDGET);
15319
- if (budget == null) return;
15320
- const thinkingConfig = { thinkingBudget: budget };
15367
+ const level = typeof reasoning.thinkingLevel === "string" && reasoning.thinkingLevel ? reasoning.thinkingLevel : void 0;
15368
+ if (budget == null && !level) return;
15369
+ const thinkingConfig = level && budget !== 0 ? { thinkingLevel: level } : { thinkingBudget: budget ?? 0 };
15321
15370
  if (reasoning.includeThoughts) thinkingConfig.includeThoughts = true;
15322
15371
  if (reasoning.providerExtras) Object.assign(thinkingConfig, reasoning.providerExtras);
15323
15372
  generationConfig.thinkingConfig = thinkingConfig;
@@ -15348,6 +15397,73 @@ function resolveBudget(reasoning, effortBudget) {
15348
15397
  return void 0;
15349
15398
  }
15350
15399
 
15400
+ // src/providers/utils/sse.ts
15401
+ async function* parseSSEStream(body, signal) {
15402
+ const reader = body.getReader();
15403
+ const decoder = new TextDecoder();
15404
+ let buffer = "";
15405
+ try {
15406
+ while (true) {
15407
+ if (signal?.aborted) throw abortReason(signal);
15408
+ const { done, value } = await reader.read();
15409
+ if (done) break;
15410
+ buffer += decoder.decode(value, { stream: true });
15411
+ const parts = buffer.split(/\r?\n\r?\n/);
15412
+ buffer = parts.pop() ?? "";
15413
+ for (const part of parts) {
15414
+ if (!part.trim()) continue;
15415
+ const event = parseSSEBlock(part);
15416
+ if (event) yield event;
15417
+ }
15418
+ }
15419
+ if (buffer.trim()) {
15420
+ const event = parseSSEBlock(buffer);
15421
+ if (event) yield event;
15422
+ }
15423
+ } finally {
15424
+ reader.cancel().catch(() => void 0);
15425
+ reader.releaseLock();
15426
+ }
15427
+ }
15428
+ function parseSSEBlock(block) {
15429
+ let event;
15430
+ let id;
15431
+ let retry;
15432
+ const dataLines = [];
15433
+ for (const line of block.split(/\r?\n/)) {
15434
+ if (line.startsWith(":")) continue;
15435
+ const colonIdx = line.indexOf(":");
15436
+ let field;
15437
+ let value;
15438
+ if (colonIdx === -1) {
15439
+ field = line;
15440
+ value = "";
15441
+ } else {
15442
+ field = line.slice(0, colonIdx);
15443
+ value = line.slice(colonIdx + 1);
15444
+ if (value.startsWith(" ")) value = value.slice(1);
15445
+ }
15446
+ switch (field) {
15447
+ case "event":
15448
+ event = value;
15449
+ break;
15450
+ case "data":
15451
+ dataLines.push(value);
15452
+ break;
15453
+ case "id":
15454
+ id = value;
15455
+ break;
15456
+ case "retry": {
15457
+ const n = parseInt(value, 10);
15458
+ if (!isNaN(n)) retry = n;
15459
+ break;
15460
+ }
15461
+ }
15462
+ }
15463
+ if (dataLines.length === 0) return null;
15464
+ return { event, data: dataLines.join("\n"), id, retry };
15465
+ }
15466
+
15351
15467
  // src/providers/utils/media.ts
15352
15468
  var EXTENSION_MIME = {
15353
15469
  jpg: "image/jpeg",
@@ -15539,11 +15655,64 @@ function isObject2(value) {
15539
15655
  return typeof value === "object" && value !== null && !Array.isArray(value);
15540
15656
  }
15541
15657
 
15658
+ // src/providers/utils/embeddings.ts
15659
+ function chunkArray(items, size) {
15660
+ const n = Math.max(1, Math.floor(size));
15661
+ const out = [];
15662
+ for (let i = 0; i < items.length; i += n) out.push(items.slice(i, i + n));
15663
+ return out;
15664
+ }
15665
+ async function mapWithConcurrency(items, limit, fn, signal) {
15666
+ const results = new Array(items.length);
15667
+ let next = 0;
15668
+ let failure;
15669
+ let failed = false;
15670
+ const worker = async () => {
15671
+ while (!failed) {
15672
+ if (signal?.aborted) throw signal.reason ?? new Error("aborted");
15673
+ const i = next++;
15674
+ if (i >= items.length) return;
15675
+ try {
15676
+ results[i] = await fn(items[i], i);
15677
+ } catch (err) {
15678
+ failed = true;
15679
+ failure = err;
15680
+ return;
15681
+ }
15682
+ }
15683
+ };
15684
+ await Promise.all(Array.from({ length: Math.min(Math.max(1, limit), items.length) }, worker));
15685
+ if (failed) throw failure;
15686
+ return results;
15687
+ }
15688
+ function decodeBase64Vector(b64) {
15689
+ const buf = Buffer.from(b64, "base64");
15690
+ const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
15691
+ const out = new Array(Math.floor(buf.byteLength / 4));
15692
+ for (let i = 0; i < out.length; i++) out[i] = view.getFloat32(i * 4, true);
15693
+ return out;
15694
+ }
15695
+ function assertVectorCount(provider, vectors, expected) {
15696
+ if (vectors.length !== expected) {
15697
+ throw new ProviderError(
15698
+ `${provider} embeddings returned ${vectors.length} vectors for ${expected} inputs`,
15699
+ provider,
15700
+ 502
15701
+ );
15702
+ }
15703
+ }
15704
+ function requireEmbeddingModel(provider, model) {
15705
+ if (!model) throw new ProviderError(`${provider} embeddings require a model`, provider, 400);
15706
+ return model;
15707
+ }
15708
+
15542
15709
  // src/providers/openai.ts
15543
- var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15710
+ var OpenAIProvider = class extends BaseProvider {
15544
15711
  constructor(config) {
15545
15712
  super();
15546
15713
  this.providerName = "openai";
15714
+ this.configureTransport(config);
15715
+ this.maxTokensParam = config.maxTokensParam ?? "auto";
15547
15716
  this.apiKey = config.apiKey;
15548
15717
  this.baseURL = (config.baseURL ?? "https://api.openai.com/v1").replace(/\/$/, "");
15549
15718
  this.defaultModel = config.defaultModel ?? "gpt-4o";
@@ -15551,10 +15720,14 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15551
15720
  ...config.defaultHeaders,
15552
15721
  ...config.organization ? { "OpenAI-Organization": config.organization } : {}
15553
15722
  };
15554
- this.responsesApi = config.responsesApi ?? "auto";
15555
- const ownInstance = new.target === _OpenAIProvider;
15556
- this.responsesApiModels = ownInstance ? [...config.responsesApiModels ?? []] : [];
15557
- this.responsesStreaming = ownInstance && config.responsesStreaming === true;
15723
+ const legacy = config.responsesApi;
15724
+ const explicit = config.api === "chat" || config.api === "responses" ? config.api : void 0;
15725
+ this.responsesApi = explicit === "responses" ? "always" : explicit === "chat" ? "never" : legacy ?? (config._autoMeansChat ? "never" : "auto");
15726
+ this.apiExplicitChat = explicit === "chat" || explicit === void 0 && legacy === "never";
15727
+ this.apiExplicitResponses = this.responsesApi === "always";
15728
+ this.apiResponsesNative = explicit === "responses";
15729
+ this.responsesApiModels = [...config.responsesApiModels ?? []];
15730
+ this.responsesStreaming = config.responsesStreaming ?? this.apiResponsesNative;
15558
15731
  if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
15559
15732
  }
15560
15733
  /** True when the caller listed this request's model in `responsesApiModels`. */
@@ -15580,9 +15753,10 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15580
15753
  * A model listed in `responsesApiModels` is the caller stating the answer
15581
15754
  * for that model alone; `never` still overrides it. */
15582
15755
  useResponsesApi(request) {
15583
- if (this.responsesApi === "never") return false;
15584
- if (this.responsesApi === "always") return true;
15756
+ if (this.apiExplicitChat) return false;
15757
+ if (this.apiExplicitResponses) return true;
15585
15758
  if (this.isResponsesApiModel(request)) return true;
15759
+ if (this.responsesApi !== "auto") return false;
15586
15760
  if (!request.reasoning) return false;
15587
15761
  return isReasoningModel(request.model || this.defaultModel);
15588
15762
  }
@@ -15597,7 +15771,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15597
15771
  }
15598
15772
  async *completeStream(request) {
15599
15773
  if (this.useResponsesApi(request)) {
15600
- if (this.responsesStreaming && this.isResponsesApiModel(request)) {
15774
+ if (this.responsesStreaming && (this.apiResponsesNative || this.isResponsesApiModel(request))) {
15601
15775
  yield* this.streamResponses(request);
15602
15776
  return;
15603
15777
  }
@@ -15647,9 +15821,14 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15647
15821
  delta: {},
15648
15822
  finishReason: mapFinishReason(choice.finish_reason)
15649
15823
  };
15824
+ if (typeof choice.finish_reason === "string") out.rawFinishReason = choice.finish_reason;
15825
+ const fields = pickProviderFields(chunk, delta, choice);
15826
+ if (fields) out.providerFields = fields;
15650
15827
  if (delta.content) {
15651
15828
  out.delta.content = delta.content;
15652
15829
  }
15830
+ const reasoningDelta = extractReasoningText(delta);
15831
+ if (reasoningDelta) out.delta.reasoning = { summary: reasoningDelta };
15653
15832
  if (delta.tool_calls) {
15654
15833
  const partials = [];
15655
15834
  for (const tc of delta.tool_calls) {
@@ -15661,7 +15840,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15661
15840
  if (tc.id) buf.id = tc.id;
15662
15841
  if (tc.function?.name) buf.name = tc.function.name;
15663
15842
  if (tc.function?.arguments) buf.arguments += tc.function.arguments;
15664
- partials.push({ id: buf.id, name: buf.name || void 0, arguments: tc.function?.arguments });
15843
+ partials.push({ id: buf.id, name: buf.name || void 0, arguments: tc.function?.arguments, index: idx });
15665
15844
  }
15666
15845
  out.delta.toolCalls = partials;
15667
15846
  }
@@ -15669,6 +15848,51 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15669
15848
  yield out;
15670
15849
  }
15671
15850
  }
15851
+ // ─── Embeddings ──────────────────────────────────────────────────────────
15852
+ /** POST /embeddings, batched (default 2048 inputs per request, the OpenAI cap). */
15853
+ async embed(request) {
15854
+ const model = requireEmbeddingModel(this.providerName, request.model);
15855
+ const batches = chunkArray(request.input, request.batchSize ?? 2048);
15856
+ const vectors = [];
15857
+ const raw = [];
15858
+ let inputTokens = 0;
15859
+ let totalTokens = 0;
15860
+ let responseModel = model;
15861
+ for (const batch of batches) {
15862
+ const body = { model, input: batch };
15863
+ if (request.dimensions != null) body.dimensions = request.dimensions;
15864
+ if (request.encodingFormat) body.encoding_format = request.encodingFormat;
15865
+ if (request.extra) Object.assign(body, request.extra);
15866
+ const res = await this.embeddingsFetch(body, request.signal);
15867
+ const json = await res.json();
15868
+ raw.push(json);
15869
+ const data = Array.isArray(json.data) ? [...json.data] : [];
15870
+ data.sort((a, b) => (a.index ?? 0) - (b.index ?? 0));
15871
+ for (const d of data) {
15872
+ vectors.push(typeof d.embedding === "string" ? decodeBase64Vector(d.embedding) : d.embedding);
15873
+ }
15874
+ inputTokens += json.usage?.prompt_tokens ?? 0;
15875
+ totalTokens += json.usage?.total_tokens ?? json.usage?.prompt_tokens ?? 0;
15876
+ responseModel = json.model ?? responseModel;
15877
+ }
15878
+ assertVectorCount(this.providerName, vectors, request.input.length);
15879
+ return { model: responseModel, vectors, usage: { inputTokens, totalTokens }, raw };
15880
+ }
15881
+ async embeddingsFetch(body, signal) {
15882
+ const url = `${this.baseURL}/embeddings`;
15883
+ const headers = {
15884
+ "Content-Type": "application/json",
15885
+ Authorization: `Bearer ${this.apiKey}`,
15886
+ ...this.defaultHeaders
15887
+ };
15888
+ const payload = JSON.stringify(body);
15889
+ const res = await this.doFetchWithRetry(() => this.httpFetch(url, { method: "POST", headers, body: payload, signal }), signal);
15890
+ if (!res.ok) {
15891
+ const text = await res.text().catch(() => "");
15892
+ throw new ProviderError(`OpenAI embeddings API error ${res.status}: ${text}`, this.providerName, res.status, text);
15893
+ }
15894
+ return res;
15895
+ }
15672
15896
  // ─── Internals ───────────────────────────────────────────────────────────
15673
15897
  buildRequestBody(request, stream) {
15674
15898
  const body = {
@@ -15676,15 +15900,27 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15676
15900
  messages: request.messages.map((m) => this.toOpenAIMessage(m)),
15677
15901
  stream
15678
15902
  };
15679
- if (stream) {
15903
+ if (stream && request.streamUsage !== false) {
15680
15904
  body.stream_options = { include_usage: true };
15681
15905
  }
15682
- if (request.temperature != null) body.temperature = request.temperature;
15683
- if (request.maxTokens != null) body.max_tokens = request.maxTokens;
15684
- if (request.topP != null) body.top_p = request.topP;
15906
+ const modelId = String(body.model);
15907
+ const reasoningModel = isReasoningModel(modelId) && !/chat/i.test(modelId);
15908
+ if (request.temperature != null && !reasoningModel) body.temperature = request.temperature;
15909
+ if (request.maxTokens != null) {
15910
+ const useCompletionTokens = this.maxTokensParam === "max_completion_tokens" || this.maxTokensParam === "auto" && isReasoningModel(modelId);
15911
+ body[useCompletionTokens ? "max_completion_tokens" : "max_tokens"] = request.maxTokens;
15912
+ }
15913
+ if (request.topP != null && !reasoningModel) body.top_p = request.topP;
15685
15914
  if (request.stop) body.stop = request.stop;
15915
+ if (request.presencePenalty != null) body.presence_penalty = request.presencePenalty;
15916
+ if (request.frequencyPenalty != null) body.frequency_penalty = request.frequencyPenalty;
15917
+ if (request.seed != null) body.seed = request.seed;
15918
+ if (request.n != null) body.n = request.n;
15919
+ if (request.logprobs != null) body.logprobs = request.logprobs;
15920
+ if (request.topLogprobs != null) body.top_logprobs = request.topLogprobs;
15686
15921
  if (request.tools?.length) {
15687
15922
  body.tools = request.tools.map((t) => this.toOpenAITool(t));
15923
+ if (request.parallelToolCalls != null) body.parallel_tool_calls = request.parallelToolCalls;
15688
15924
  }
15689
15925
  if (request.toolChoice != null && request.tools?.length) {
15690
15926
  if (typeof request.toolChoice === "string") {
@@ -15716,7 +15952,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15716
15952
  // ─── Responses API (reasoning models) ──────────────────────────────────────
15717
15953
  async completeResponses(request) {
15718
15954
  const body = this.buildResponsesBody(request);
15719
- if (this.isResponsesApiModel(request)) adaptChatExtrasForResponses(body, request.extra);
15955
+ if (this.apiResponsesNative || this.isResponsesApiModel(request)) adaptChatExtrasForResponses(body, request.extra);
15720
15956
  const res = await this.responsesFetch(body, request.signal);
15721
15957
  const json = await res.json();
15722
15958
  return this.parseResponsesResponse(json, request.model || this.defaultModel);
@@ -15739,6 +15975,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15739
15975
  let model = modelId;
15740
15976
  const calls = /* @__PURE__ */ new Map();
15741
15977
  let final;
15978
+ let streamedSummary = false;
15742
15979
  for await (const event of parseSSEStream(res.body, request.signal)) {
15743
15980
  if (event.data === "[DONE]") break;
15744
15981
  let data;
@@ -15756,19 +15993,28 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15756
15993
  case "response.output_text.delta":
15757
15994
  if (data.delta) yield { id, model, delta: { content: data.delta } };
15758
15995
  break;
15996
+ case "response.reasoning_summary_part.added":
15997
+ if (streamedSummary) yield { id, model, delta: { reasoning: { summary: "\n\n" } } };
15998
+ break;
15999
+ case "response.reasoning_summary_text.delta":
16000
+ if (typeof data.delta === "string" && data.delta) {
16001
+ streamedSummary = true;
16002
+ yield { id, model, delta: { reasoning: { summary: data.delta } } };
16003
+ }
16004
+ break;
15759
16005
  case "response.output_item.added": {
15760
16006
  const item = data.item;
15761
16007
  if (item?.type !== "function_call") break;
15762
- const call = { callId: item.call_id ?? item.id ?? "", name: item.name ?? "", arguments: item.arguments ?? "" };
16008
+ const call = { callId: item.call_id ?? item.id ?? "", name: item.name ?? "", arguments: item.arguments ?? "", index: calls.size };
15763
16009
  calls.set(item.id ?? call.callId, call);
15764
- yield { id, model, delta: { toolCalls: [{ id: call.callId, name: call.name, arguments: call.arguments }] } };
16010
+ yield { id, model, delta: { toolCalls: [{ id: call.callId, name: call.name, arguments: call.arguments, index: call.index }] } };
15765
16011
  break;
15766
16012
  }
15767
16013
  case "response.function_call_arguments.delta": {
15768
16014
  const call = calls.get(data.item_id);
15769
16015
  if (!call || !data.delta) break;
15770
16016
  call.arguments += data.delta;
15771
- yield { id, model, delta: { toolCalls: [{ id: call.callId, arguments: data.delta }] } };
16017
+ yield { id, model, delta: { toolCalls: [{ id: call.callId, arguments: data.delta, index: call.index }] } };
15772
16018
  break;
15773
16019
  }
15774
16020
  case "response.output_item.done": {
@@ -15777,13 +16023,13 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15777
16023
  const full = typeof item.arguments === "string" ? item.arguments : "";
15778
16024
  const call = calls.get(item.id ?? item.call_id);
15779
16025
  if (!call) {
15780
- const added = { callId: item.call_id ?? item.id ?? "", name: item.name ?? "", arguments: full };
16026
+ const added = { callId: item.call_id ?? item.id ?? "", name: item.name ?? "", arguments: full, index: calls.size };
15781
16027
  calls.set(item.id ?? added.callId, added);
15782
- yield { id, model, delta: { toolCalls: [{ id: added.callId, name: added.name, arguments: full }] } };
16028
+ yield { id, model, delta: { toolCalls: [{ id: added.callId, name: added.name, arguments: full, index: added.index }] } };
15783
16029
  } else if (full.length > call.arguments.length && full.startsWith(call.arguments)) {
15784
16030
  const rest = full.slice(call.arguments.length);
15785
16031
  call.arguments = full;
15786
- yield { id, model, delta: { toolCalls: [{ id: call.callId, arguments: rest }] } };
16032
+ yield { id, model, delta: { toolCalls: [{ id: call.callId, arguments: rest, index: call.index }] } };
15787
16033
  }
15788
16034
  break;
15789
16035
  }
@@ -15806,7 +16052,8 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15806
16052
  yield {
15807
16053
  id: final?.id || id,
15808
16054
  model: final?.model || model,
15809
- delta: final?.reasoning ? { reasoning: final.reasoning } : {},
16055
+ // Summary text already went out as deltas; do not repeat it.
16056
+ delta: final?.reasoning && !streamedSummary ? { reasoning: final.reasoning } : {},
15810
16057
  usage: final?.usage,
15811
16058
  finishReason: final?.finishReason ?? (calls.size > 0 ? "tool_calls" : "stop")
15812
16059
  };
@@ -15916,7 +16163,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
15916
16163
  ...this.defaultHeaders
15917
16164
  };
15918
16165
  const payload = JSON.stringify(body);
15919
- const res = await this.doFetchWithRetry(() => fetch(url, { method: "POST", headers, body: payload, signal }), signal);
16166
+ const res = await this.doFetchWithRetry(() => this.httpFetch(url, { method: "POST", headers, body: payload, signal }), signal);
15920
16167
  if (!res.ok) {
15921
16168
  const text = await res.text().catch(() => "");
15922
16169
  throw new ProviderError(
@@ -16045,7 +16292,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
16045
16292
  ...this.defaultHeaders
16046
16293
  };
16047
16294
  const payload = JSON.stringify(body);
16048
- const res = await this.doFetchWithRetry(() => fetch(url, { method: "POST", headers, body: payload, signal }), signal);
16295
+ const res = await this.doFetchWithRetry(() => this.httpFetch(url, { method: "POST", headers, body: payload, signal }), signal);
16049
16296
  if (!res.ok) {
16050
16297
  const text = await res.text().catch(() => "");
16051
16298
  throw new ProviderError(
@@ -16065,6 +16312,8 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
16065
16312
  name: tc.function?.name ?? "",
16066
16313
  arguments: tc.function?.arguments ?? "{}"
16067
16314
  }));
16315
+ const reasoningText = extractReasoningText(message);
16316
+ const providerFields = pickProviderFields(json, message, choice);
16068
16317
  return {
16069
16318
  id: json.id ?? "",
16070
16319
  model: json.model ?? "",
@@ -16072,6 +16321,9 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
16072
16321
  toolCalls,
16073
16322
  usage: this.extractUsage(json.usage),
16074
16323
  finishReason: mapFinishReason(choice?.finish_reason),
16324
+ ...typeof choice?.finish_reason === "string" ? { rawFinishReason: choice.finish_reason } : {},
16325
+ ...providerFields ? { providerFields } : {},
16326
+ ...reasoningText ? { reasoning: { summary: reasoningText } } : {},
16075
16327
  raw: json
16076
16328
  };
16077
16329
  }
@@ -16090,6 +16342,23 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
16090
16342
  };
16091
16343
  }
16092
16344
  };
16345
+ function extractReasoningText(src) {
16346
+ if (!src || typeof src !== "object") return void 0;
16347
+ for (const key of ["reasoning_content", "reasoning"]) {
16348
+ const v = src[key];
16349
+ if (typeof v === "string" && v.length > 0) return v;
16350
+ }
16351
+ return void 0;
16352
+ }
16353
+ function pickProviderFields(top, message, choice) {
16354
+ const out = {};
16355
+ if (top?.system_fingerprint != null) out.system_fingerprint = top.system_fingerprint;
16356
+ if (top?.service_tier != null) out.service_tier = top.service_tier;
16357
+ if (message?.annotations != null) out.annotations = message.annotations;
16358
+ if (message?.refusal != null) out.refusal = message.refusal;
16359
+ if (choice?.logprobs != null) out.logprobs = choice.logprobs;
16360
+ return Object.keys(out).length > 0 ? out : void 0;
16361
+ }
16093
16362
  function isReasoningModel(model) {
16094
16363
  if (!model) return false;
16095
16364
  const m = model.toLowerCase();
@@ -16166,36 +16435,86 @@ function mapFinishReason(reason) {
16166
16435
  }
16167
16436
  }
16168
16437
 
16438
+ // src/providers/utils/toolChoice.ts
16439
+ function supportsForcedToolChoice(model) {
16440
+ if (typeof model !== "string") return true;
16441
+ const id = model.toLowerCase();
16442
+ const at = id.indexOf("claude-");
16443
+ if (at < 0) return true;
16444
+ const toks = id.slice(at + 7).split("-");
16445
+ let family = false;
16446
+ for (const tok of toks) {
16447
+ if (tok === "sonnet" || tok === "opus") {
16448
+ family = true;
16449
+ continue;
16450
+ }
16451
+ const m = /^(\d+)(?:@|:|$)/.exec(tok);
16452
+ if (m) {
16453
+ if (m[1].length > 2) continue;
16454
+ if (Number(m[1]) < 5) return true;
16455
+ if (family) return false;
16456
+ return !toks.some((t) => t === "sonnet" || t === "opus");
16457
+ }
16458
+ }
16459
+ return true;
16460
+ }
16461
+ function forcedToolChoiceRejected(text) {
16462
+ const t = text.toLowerCase();
16463
+ return t.indexOf("tool_choice") >= 0 && t.indexOf("not supported for this model") >= 0;
16464
+ }
16465
+
16169
16466
  // src/providers/anthropic.ts
16467
+ var DEFAULT_MAX_TOKENS = 4096;
16468
+ function normalizeExplicitThinking(body) {
16469
+ const t = body.thinking;
16470
+ if (t == null) {
16471
+ delete body.thinking;
16472
+ return;
16473
+ }
16474
+ if (t.type !== "enabled") return;
16475
+ const budget = typeof t.budget_tokens === "number" ? t.budget_tokens : 0;
16476
+ if (budget > 0 && (typeof body.max_tokens !== "number" || body.max_tokens <= budget)) {
16477
+ body.max_tokens = budget + 1024;
16478
+ }
16479
+ for (const k of ["temperature", "top_p", "top_k"]) delete body[k];
16480
+ }
16481
+ function thinkingFormRejected(text) {
16482
+ const t = text.toLowerCase();
16483
+ if (t.indexOf("thinking.type.enabled") >= 0 && t.indexOf("not supported") >= 0) return "enabled";
16484
+ if (t.indexOf("thinking.type.adaptive") >= 0 && t.indexOf("not supported") >= 0 && t.indexOf("thinking.type.enabled") < 0) return "adaptive";
16485
+ return void 0;
16486
+ }
16170
16487
  var AnthropicProvider = class extends BaseProvider {
16171
16488
  constructor(config) {
16172
16489
  super();
16173
16490
  this.providerName = "anthropic";
16491
+ this.configureTransport(config);
16174
16492
  this.apiKey = config.apiKey;
16175
16493
  this.baseURL = (config.baseURL ?? "https://api.anthropic.com").replace(/\/$/, "");
16176
16494
  this.defaultModel = config.defaultModel ?? "claude-sonnet-4-20250514";
16177
16495
  this.defaultHeaders = config.defaultHeaders ?? {};
16178
16496
  this.anthropicVersion = config.anthropicVersion ?? "2023-06-01";
16497
+ this.thinkingMode = config.thinkingMode ?? "auto";
16179
16498
  this.promptCachingEnabled = config.prompt_caching?.enabled === true;
16180
16499
  if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
16181
16500
  }
16182
16501
  async complete(request) {
16183
- const body = this.buildRequestBody(request, false);
16184
- const res = await this.doFetch(body, request.signal);
16502
+ const res = await this.send(request, false);
16185
16503
  const json = await res.json();
16186
16504
  return this.parseResponse(json);
16187
16505
  }
16188
16506
  async *completeStream(request) {
16189
- const body = this.buildRequestBody(request, true);
16190
- const res = await this.doFetch(body, request.signal);
16507
+ const res = await this.send(request, true);
16191
16508
  if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
16192
16509
  let id = "";
16193
16510
  let model = "";
16194
16511
  let inputTokens = 0;
16195
16512
  let outputTokens = 0;
16513
+ let thinkingTokens = 0;
16196
16514
  let cacheReadInputTokens = 0;
16197
16515
  let cacheCreationInputTokens = 0;
16198
16516
  const currentToolCalls = /* @__PURE__ */ new Map();
16517
+ let toolOrdinal = 0;
16199
16518
  const reasoningBlocks = /* @__PURE__ */ new Map();
16200
16519
  for await (const event of parseSSEStream(res.body, request.signal)) {
16201
16520
  let data;
@@ -16224,8 +16543,11 @@ var AnthropicProvider = class extends BaseProvider {
16224
16543
  currentToolCalls.set(idx, {
16225
16544
  id: block.id ?? "",
16226
16545
  name: block.name ?? "",
16227
- arguments: ""
16546
+ arguments: "",
16547
+ ordinal: toolOrdinal++
16228
16548
  });
16549
+ const opened = currentToolCalls.get(idx);
16550
+ yield { id, model, delta: { toolCalls: [{ id: opened.id, name: opened.name, arguments: "", index: opened.ordinal }] } };
16229
16551
  } else if (block?.type === "thinking") {
16230
16552
  reasoningBlocks.set(idx, { type: "thinking", text: block.thinking ?? "", signature: block.signature });
16231
16553
  } else if (block?.type === "redacted_thinking") {
@@ -16263,7 +16585,7 @@ var AnthropicProvider = class extends BaseProvider {
16263
16585
  id,
16264
16586
  model,
16265
16587
  delta: {
16266
- toolCalls: [{ id: tc.id, name: tc.name, arguments: delta.partial_json }]
16588
+ toolCalls: [{ id: tc.id, name: tc.name, arguments: delta.partial_json, index: tc.ordinal }]
16267
16589
  }
16268
16590
  };
16269
16591
  }
@@ -16276,8 +16598,10 @@ var AnthropicProvider = class extends BaseProvider {
16276
16598
  const delta = data.delta;
16277
16599
  if (data.usage) {
16278
16600
  outputTokens = data.usage.output_tokens ?? outputTokens;
16601
+ thinkingTokens = data.usage.output_tokens_details?.thinking_tokens ?? thinkingTokens;
16279
16602
  }
16280
16603
  const finishReason = mapAnthropicStopReason(delta?.stop_reason);
16604
+ const rawFinishReason = typeof delta?.stop_reason === "string" ? delta.stop_reason : void 0;
16281
16605
  const usage = {
16282
16606
  inputTokens,
16283
16607
  outputTokens,
@@ -16285,7 +16609,7 @@ var AnthropicProvider = class extends BaseProvider {
16285
16609
  cachedInputTokens: cacheReadInputTokens,
16286
16610
  cachedWriteTokens: cacheCreationInputTokens,
16287
16611
  cachedOutputTokens: 0,
16288
- reasoningTokens: 0
16612
+ reasoningTokens: thinkingTokens
16289
16613
  };
16290
16614
  const blocks = [...reasoningBlocks.values()].filter(
16291
16615
  (b) => b.type === "thinking" && b.signature || b.type === "redacted_thinking" && b.data
@@ -16295,6 +16619,7 @@ var AnthropicProvider = class extends BaseProvider {
16295
16619
  model,
16296
16620
  delta: blocks.length > 0 ? { reasoning: { blocks } } : {},
16297
16621
  finishReason,
16622
+ ...rawFinishReason ? { rawFinishReason } : {},
16298
16623
  usage
16299
16624
  };
16300
16625
  break;
@@ -16309,12 +16634,12 @@ var AnthropicProvider = class extends BaseProvider {
16309
16634
  }
16310
16635
  }
16311
16636
  // ─── Internals ───────────────────────────────────────────────────────────
16312
- buildRequestBody(request, stream) {
16637
+ buildRequestBody(request, stream, modeOverride, downgradeToolChoice = false) {
16313
16638
  const { system, messages } = this.splitSystemMessages(request.messages);
16314
16639
  const body = {
16315
16640
  model: request.model || this.defaultModel,
16316
16641
  messages: this.toAnthropicMessages(messages),
16317
- max_tokens: request.maxTokens ?? 4096,
16642
+ max_tokens: request.maxTokens ?? DEFAULT_MAX_TOKENS,
16318
16643
  stream
16319
16644
  };
16320
16645
  if (system) {
@@ -16335,18 +16660,27 @@ var AnthropicProvider = class extends BaseProvider {
16335
16660
  body.tools = tools;
16336
16661
  }
16337
16662
  if (request.toolChoice != null) {
16663
+ const forceOk = !downgradeToolChoice && supportsForcedToolChoice(body.model);
16338
16664
  if (request.toolChoice === "auto") {
16339
16665
  body.tool_choice = { type: "auto" };
16340
16666
  } else if (request.toolChoice === "required") {
16341
- body.tool_choice = { type: "any" };
16667
+ body.tool_choice = forceOk ? { type: "any" } : { type: "auto" };
16342
16668
  } else if (request.toolChoice === "none") ; else {
16343
- body.tool_choice = { type: "tool", name: request.toolChoice.name };
16669
+ body.tool_choice = forceOk ? { type: "tool", name: request.toolChoice.name } : { type: "auto" };
16344
16670
  }
16345
16671
  }
16346
16672
  if (request.extra) {
16347
16673
  Object.assign(body, request.extra);
16348
16674
  }
16349
- applyAnthropicReasoning(body, request.reasoning);
16675
+ const explicitThinking = request.extra && typeof request.extra === "object" && "thinking" in request.extra;
16676
+ if (explicitThinking) {
16677
+ normalizeExplicitThinking(body);
16678
+ } else {
16679
+ applyAnthropicReasoning(body, request.reasoning, { model: body.model, mode: modeOverride ?? this.thinkingMode });
16680
+ }
16681
+ if (typeof body.max_tokens !== "number" || !(body.max_tokens > 0)) {
16682
+ body.max_tokens = DEFAULT_MAX_TOKENS;
16683
+ }
16350
16684
  return body;
16351
16685
  }
16352
16686
  splitSystemMessages(messages) {
@@ -16477,6 +16811,34 @@ var AnthropicProvider = class extends BaseProvider {
16477
16811
  input_schema: t.parameters
16478
16812
  };
16479
16813
  }
16814
+ /** Builds and sends the request; retries once with the other thinking form
16815
+ * when the upstream rejects the one we picked. */
16816
+ async send(request, stream) {
16817
+ let mode;
16818
+ let downgrade = false;
16819
+ let flippedThinking = false;
16820
+ for (; ; ) {
16821
+ const body = this.buildRequestBody(request, stream, mode, downgrade);
16822
+ try {
16823
+ return await this.doFetch(body, request.signal);
16824
+ } catch (err) {
16825
+ if (!(err instanceof ProviderError) || err.statusCode !== 400) throw err;
16826
+ const text = String(err.responseBody ?? err.message);
16827
+ if (!downgrade && body.tool_choice && body.tool_choice.type !== "auto" && forcedToolChoiceRejected(text)) {
16828
+ downgrade = true;
16829
+ continue;
16830
+ }
16831
+ const explicit = request.extra && typeof request.extra === "object" && "thinking" in request.extra;
16832
+ if (flippedThinking || explicit || !request.reasoning) throw err;
16833
+ const wrong = thinkingFormRejected(text);
16834
+ if (!wrong) throw err;
16835
+ const used = resolveThinkingForm(request.model ?? this.defaultModel, this.thinkingMode);
16836
+ if (wrong === "enabled" && used !== "budget" || wrong === "adaptive" && used !== "adaptive") throw err;
16837
+ mode = wrong === "enabled" ? "adaptive" : "budget";
16838
+ flippedThinking = true;
16839
+ }
16840
+ }
16841
+ }
16480
16842
  async doFetch(body, signal) {
16481
16843
  const url = `${this.baseURL}/v1/messages`;
16482
16844
  const headers = {
@@ -16486,7 +16848,7 @@ var AnthropicProvider = class extends BaseProvider {
16486
16848
  ...this.defaultHeaders
16487
16849
  };
16488
16850
  const payload = JSON.stringify(body);
16489
- const res = await this.doFetchWithRetry(() => fetch(url, { method: "POST", headers, body: payload, signal }), signal);
16851
+ const res = await this.doFetchWithRetry(() => this.httpFetch(url, { method: "POST", headers, body: payload, signal }), signal);
16490
16852
  if (!res.ok) {
16491
16853
  const text = await res.text().catch(() => "");
16492
16854
  throw new ProviderError(
@@ -16531,10 +16893,9 @@ var AnthropicProvider = class extends BaseProvider {
16531
16893
  cachedInputTokens: usage.cache_read_input_tokens ?? 0,
16532
16894
  cachedWriteTokens: usage.cache_creation_input_tokens ?? 0,
16533
16895
  cachedOutputTokens: 0,
16534
- // Anthropic bills thinking tokens inside `output_tokens` and does not
16535
- // expose a separate count, so reasoningTokens stays 0 here (cost is still
16536
- // captured via outputTokens). See docs for the limitation.
16537
- reasoningTokens: 0
16896
+ // Thinking tokens are billed inside `output_tokens`; newer models also
16897
+ // report the split as `output_tokens_details.thinking_tokens`.
16898
+ reasoningTokens: usage.output_tokens_details?.thinking_tokens ?? 0
16538
16899
  };
16539
16900
  return {
16540
16901
  id: json.id ?? "",
@@ -16543,6 +16904,7 @@ var AnthropicProvider = class extends BaseProvider {
16543
16904
  toolCalls,
16544
16905
  usage: tokenUsage,
16545
16906
  finishReason: mapAnthropicStopReason(json.stop_reason),
16907
+ ...typeof json.stop_reason === "string" ? { rawFinishReason: json.stop_reason } : {},
16546
16908
  reasoning: reasoningBlocks.length > 0 ? { blocks: reasoningBlocks, summary: summaryParts.join("\n").trim() || void 0 } : void 0,
16547
16909
  raw: json
16548
16910
  };
@@ -16588,7 +16950,15 @@ var AzureProvider = class extends OpenAIProvider {
16588
16950
  provider: "openai",
16589
16951
  apiKey: config.apiKey,
16590
16952
  defaultModel: config.defaultModel ?? config.deploymentName ?? "gpt-4o",
16591
- defaultHeaders: config.defaultHeaders
16953
+ defaultHeaders: config.defaultHeaders,
16954
+ retry: config.retry,
16955
+ fetch: config.fetch,
16956
+ timeoutMs: config.timeoutMs,
16957
+ maxTokensParam: config.maxTokensParam,
16958
+ api: config.api,
16959
+ responsesApi: config.responsesApi,
16960
+ responsesApiModels: config.responsesApiModels,
16961
+ responsesStreaming: config.responsesStreaming
16592
16962
  });
16593
16963
  this.providerName = "azure";
16594
16964
  this.endpoint = config.endpoint.replace(/\/$/, "");
@@ -16603,16 +16973,17 @@ var AzureProvider = class extends OpenAIProvider {
16603
16973
  }
16604
16974
  const url = `${this.endpoint}/openai/deployments/${deployment}/chat/completions?api-version=${this.apiVersion}`;
16605
16975
  const { model: _model, ...bodyWithoutModel } = body;
16606
- const res = await fetch(url, {
16976
+ const payload = JSON.stringify(bodyWithoutModel);
16977
+ const res = await this.doFetchWithRetry(() => this.httpFetch(url, {
16607
16978
  method: "POST",
16608
16979
  headers: {
16609
16980
  "Content-Type": "application/json",
16610
16981
  "api-key": this.azureApiKey,
16611
16982
  ...this.defaultHeaders
16612
16983
  },
16613
- body: JSON.stringify(bodyWithoutModel),
16984
+ body: payload,
16614
16985
  signal
16615
- });
16986
+ }), signal);
16616
16987
  if (!res.ok) {
16617
16988
  const text = await res.text().catch(() => "");
16618
16989
  throw new ProviderError(
@@ -16624,6 +16995,32 @@ var AzureProvider = class extends OpenAIProvider {
16624
16995
  }
16625
16996
  return res;
16626
16997
  }
16998
+ /** Azure embeddings: the deployment named by the request's model (falling back
16999
+ * to the configured deployment) in the path, api-key auth. */
17000
+ async embeddingsFetch(body, signal) {
17001
+ const deployment = body.model || this.deploymentName;
17002
+ if (!deployment) {
17003
+ throw new ProviderError("Azure embeddings require a deployment name or model", this.providerName, 400);
17004
+ }
17005
+ const url = `${this.endpoint}/openai/deployments/${deployment}/embeddings?api-version=${this.apiVersion}`;
17006
+ const { model: _model, ...bodyWithoutModel } = body;
17007
+ const payload = JSON.stringify(bodyWithoutModel);
17008
+ const res = await this.doFetchWithRetry(() => this.httpFetch(url, {
17009
+ method: "POST",
17010
+ headers: {
17011
+ "Content-Type": "application/json",
17012
+ "api-key": this.azureApiKey,
17013
+ ...this.defaultHeaders
17014
+ },
17015
+ body: payload,
17016
+ signal
17017
+ }), signal);
17018
+ if (!res.ok) {
17019
+ const text = await res.text().catch(() => "");
17020
+ throw new ProviderError(`Azure OpenAI embeddings API error ${res.status}: ${text}`, this.providerName, res.status, text);
17021
+ }
17022
+ return res;
17023
+ }
16627
17024
  /** Azure exposes the Responses API at /openai/responses with api-key auth.
16628
17025
  * Reasoning summaries require a preview api-version; callers can override via
16629
17026
  * the `apiVersion` config. */
@@ -16635,7 +17032,7 @@ var AzureProvider = class extends OpenAIProvider {
16635
17032
  }
16636
17033
  const url = `${this.endpoint}/openai/responses?api-version=${this.apiVersion}`;
16637
17034
  const payload = JSON.stringify({ ...body, model: deployment });
16638
- const res = await fetch(url, {
17035
+ const res = await this.doFetchWithRetry(() => this.httpFetch(url, {
16639
17036
  method: "POST",
16640
17037
  headers: {
16641
17038
  "Content-Type": "application/json",
@@ -16644,7 +17041,7 @@ var AzureProvider = class extends OpenAIProvider {
16644
17041
  },
16645
17042
  body: payload,
16646
17043
  signal
16647
- });
17044
+ }), signal);
16648
17045
  if (!res.ok) {
16649
17046
  const text = await res.text().catch(() => "");
16650
17047
  throw new ProviderError(
@@ -16680,20 +17077,155 @@ var OpenAICompatibleProvider = class extends OpenAIProvider {
16680
17077
  apiKey: config.apiKey,
16681
17078
  baseURL: config.baseURL,
16682
17079
  defaultModel: config.defaultModel,
16683
- defaultHeaders: config.defaultHeaders
17080
+ defaultHeaders: config.defaultHeaders,
17081
+ organization: config.organization,
17082
+ retry: config.retry,
17083
+ fetch: config.fetch,
17084
+ timeoutMs: config.timeoutMs,
17085
+ maxTokensParam: config.maxTokensParam,
17086
+ api: config.api,
17087
+ // Unlike OpenAI / Azure, "auto" on a compatible server means Chat
17088
+ // Completions (the 0.11 default): the model name is the operator's.
17089
+ // `responsesApiModels` still applies; `responsesApi: "auto"` opts in.
17090
+ _autoMeansChat: true,
17091
+ responsesApi: config.responsesApi,
17092
+ responsesApiModels: config.responsesApiModels,
17093
+ responsesStreaming: config.responsesStreaming
16684
17094
  });
16685
17095
  this.providerName = "openai-compatible";
16686
17096
  }
16687
17097
  };
16688
17098
 
17099
+ // src/providers/utils/eventStream.ts
17100
+ var EventStreamError = class extends Error {
17101
+ constructor(message) {
17102
+ super(message);
17103
+ this.name = "EventStreamError";
17104
+ }
17105
+ };
17106
+ var CRC_TABLE = (() => {
17107
+ const table = new Uint32Array(256);
17108
+ for (let n = 0; n < 256; n++) {
17109
+ let c = n;
17110
+ for (let k = 0; k < 8; k++) c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
17111
+ table[n] = c >>> 0;
17112
+ }
17113
+ return table;
17114
+ })();
17115
+ function crc32(bytes, start = 0, end = bytes.length) {
17116
+ let c = 4294967295;
17117
+ for (let i = start; i < end; i++) c = CRC_TABLE[(c ^ bytes[i]) & 255] ^ c >>> 8;
17118
+ return (c ^ 4294967295) >>> 0;
17119
+ }
17120
+ function decodeFrame(frame) {
17121
+ const view = new DataView(frame.buffer, frame.byteOffset, frame.byteLength);
17122
+ const total = view.getUint32(0);
17123
+ const headersLen = view.getUint32(4);
17124
+ if (total !== frame.byteLength) throw new EventStreamError("event-stream frame length mismatch");
17125
+ if (crc32(frame, 0, 8) !== view.getUint32(8)) throw new EventStreamError("event-stream prelude CRC mismatch");
17126
+ if (crc32(frame, 0, total - 4) !== view.getUint32(total - 4)) throw new EventStreamError("event-stream message CRC mismatch");
17127
+ if (12 + headersLen > total - 4) throw new EventStreamError("event-stream headers overflow frame");
17128
+ const headers = {};
17129
+ const td = new TextDecoder();
17130
+ let o = 12;
17131
+ const headersEnd = 12 + headersLen;
17132
+ while (o < headersEnd) {
17133
+ const nameLen = frame[o++];
17134
+ const name = td.decode(frame.subarray(o, o + nameLen));
17135
+ o += nameLen;
17136
+ const type = frame[o++];
17137
+ switch (type) {
17138
+ case 0:
17139
+ headers[name] = true;
17140
+ break;
17141
+ case 1:
17142
+ headers[name] = false;
17143
+ break;
17144
+ case 2:
17145
+ headers[name] = view.getInt8(o);
17146
+ o += 1;
17147
+ break;
17148
+ case 3:
17149
+ headers[name] = view.getInt16(o);
17150
+ o += 2;
17151
+ break;
17152
+ case 4:
17153
+ headers[name] = view.getInt32(o);
17154
+ o += 4;
17155
+ break;
17156
+ case 5:
17157
+ headers[name] = view.getBigInt64(o);
17158
+ o += 8;
17159
+ break;
17160
+ case 6: {
17161
+ const len = view.getUint16(o);
17162
+ o += 2;
17163
+ headers[name] = frame.slice(o, o + len);
17164
+ o += len;
17165
+ break;
17166
+ }
17167
+ case 7: {
17168
+ const len = view.getUint16(o);
17169
+ o += 2;
17170
+ headers[name] = td.decode(frame.subarray(o, o + len));
17171
+ o += len;
17172
+ break;
17173
+ }
17174
+ case 8:
17175
+ headers[name] = view.getBigInt64(o);
17176
+ o += 8;
17177
+ break;
17178
+ case 9:
17179
+ headers[name] = frame.slice(o, o + 16);
17180
+ o += 16;
17181
+ break;
17182
+ default:
17183
+ throw new EventStreamError(`unknown event-stream header type ${type}`);
17184
+ }
17185
+ }
17186
+ return { headers, payload: frame.slice(headersEnd, total - 4) };
17187
+ }
17188
+ async function* parseEventStream(body, signal) {
17189
+ const reader = body.getReader();
17190
+ let buf = new Uint8Array(0);
17191
+ try {
17192
+ while (true) {
17193
+ if (signal?.aborted) throw abortReason(signal);
17194
+ const { done, value } = await reader.read();
17195
+ if (done) break;
17196
+ if (!value?.length) continue;
17197
+ const merged = new Uint8Array(buf.length + value.length);
17198
+ merged.set(buf, 0);
17199
+ merged.set(value, buf.length);
17200
+ buf = merged;
17201
+ while (buf.length >= 12) {
17202
+ const total = new DataView(buf.buffer, buf.byteOffset, buf.byteLength).getUint32(0);
17203
+ if (total < 16) throw new EventStreamError("invalid event-stream frame length");
17204
+ if (buf.length < total) break;
17205
+ yield decodeFrame(buf.subarray(0, total));
17206
+ buf = buf.subarray(total);
17207
+ }
17208
+ }
17209
+ if (buf.length > 0) throw new EventStreamError("event-stream ended inside a frame");
17210
+ } finally {
17211
+ reader.cancel().catch(() => void 0);
17212
+ try {
17213
+ reader.releaseLock();
17214
+ } catch {
17215
+ }
17216
+ }
17217
+ }
17218
+
16689
17219
  // src/providers/bedrock.ts
16690
17220
  var BedrockProvider = class extends BaseProvider {
16691
17221
  constructor(config) {
16692
17222
  super();
16693
17223
  this.providerName = "bedrock";
17224
+ this.configureTransport(config);
16694
17225
  this.region = config.region;
16695
17226
  this.defaultModel = config.defaultModel ?? "anthropic.claude-sonnet-4-20250514-v1:0";
16696
17227
  this.defaultHeaders = config.defaultHeaders ?? {};
17228
+ this.thinkingMode = config.thinkingMode ?? "auto";
16697
17229
  this.promptCachingEnabled = config.prompt_caching?.enabled === true;
16698
17230
  if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
16699
17231
  this.credentials = {
@@ -16710,25 +17242,202 @@ var BedrockProvider = class extends BaseProvider {
16710
17242
  }
16711
17243
  async complete(request) {
16712
17244
  const modelId = request.model || this.defaultModel;
16713
- const body = this.buildConverseBody(request);
16714
- const json = await this.doFetch(modelId, body, request.signal);
16715
- return this.parseResponse(json, modelId);
17245
+ const res = await this.converseFetch(modelId, request, false);
17246
+ return this.parseResponse(await res.json(), modelId);
16716
17247
  }
17248
+ /**
17249
+ * Real streaming over ConverseStream. The response is an AWS event-stream
17250
+ * (binary frames); each frame carries one JSON event: messageStart,
17251
+ * contentBlockStart/Delta/Stop (text, toolUse, reasoningContent),
17252
+ * messageStop and, last, metadata (usage). Text, tool-call argument and
17253
+ * reasoning deltas are yielded as they arrive; one closing chunk carries the
17254
+ * finish reason, usage and the signed reasoning blocks.
17255
+ */
16717
17256
  async *completeStream(request) {
16718
- const response = await this.complete(request);
17257
+ const modelId = request.model || this.defaultModel;
17258
+ const res = await this.converseFetch(modelId, request, true);
17259
+ if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
17260
+ const id = res.headers.get("x-amzn-requestid") ?? "";
17261
+ const toolsByIndex = /* @__PURE__ */ new Map();
17262
+ const reasoningByIndex = /* @__PURE__ */ new Map();
17263
+ let finishReason;
17264
+ let rawFinishReason;
17265
+ let toolOrdinal = 0;
17266
+ let usage;
17267
+ for await (const msg of parseEventStream(res.body, request.signal)) {
17268
+ const messageType = String(msg.headers[":message-type"] ?? "event");
17269
+ const eventType = String(msg.headers[":event-type"] ?? msg.headers[":exception-type"] ?? "");
17270
+ let data = {};
17271
+ const text = new TextDecoder().decode(msg.payload);
17272
+ if (text) {
17273
+ try {
17274
+ data = JSON.parse(text);
17275
+ } catch {
17276
+ data = { message: text };
17277
+ }
17278
+ }
17279
+ if (messageType === "exception" || messageType === "error") {
17280
+ const code = String(msg.headers[":exception-type"] ?? msg.headers[":error-code"] ?? eventType);
17281
+ throw new ProviderError(
17282
+ `Bedrock stream error ${code}: ${data.message ?? text}`,
17283
+ this.providerName,
17284
+ bedrockExceptionStatus(code),
17285
+ data
17286
+ );
17287
+ }
17288
+ switch (eventType) {
17289
+ case "contentBlockStart": {
17290
+ const idx = data.contentBlockIndex ?? 0;
17291
+ const tu = data.start?.toolUse;
17292
+ if (tu) {
17293
+ const ordinal = toolOrdinal++;
17294
+ toolsByIndex.set(idx, { id: tu.toolUseId ?? "", name: tu.name ?? "", ordinal });
17295
+ yield { id, model: modelId, delta: { toolCalls: [{ id: tu.toolUseId, name: tu.name, arguments: "", index: ordinal }] } };
17296
+ }
17297
+ break;
17298
+ }
17299
+ case "contentBlockDelta": {
17300
+ const idx = data.contentBlockIndex ?? 0;
17301
+ const d = data.delta ?? {};
17302
+ if (typeof d.text === "string" && d.text) {
17303
+ yield { id, model: modelId, delta: { content: d.text } };
17304
+ } else if (d.toolUse) {
17305
+ const tc = toolsByIndex.get(idx);
17306
+ if (tc && typeof d.toolUse.input === "string" && d.toolUse.input) {
17307
+ yield { id, model: modelId, delta: { toolCalls: [{ id: tc.id, name: tc.name, arguments: d.toolUse.input, index: tc.ordinal }] } };
17308
+ }
17309
+ } else if (d.reasoningContent) {
17310
+ const rc = d.reasoningContent;
17311
+ const blk = reasoningByIndex.get(idx) ?? { type: "thinking", text: "" };
17312
+ if (typeof rc.text === "string" && rc.text) {
17313
+ blk.text = (blk.text ?? "") + rc.text;
17314
+ reasoningByIndex.set(idx, blk);
17315
+ yield { id, model: modelId, delta: { reasoning: { summary: rc.text } } };
17316
+ }
17317
+ if (typeof rc.signature === "string" && rc.signature) {
17318
+ blk.signature = (blk.signature ?? "") + rc.signature;
17319
+ reasoningByIndex.set(idx, blk);
17320
+ }
17321
+ if (rc.redactedContent) {
17322
+ reasoningByIndex.set(idx, { type: "redacted_thinking", data: rc.redactedContent });
17323
+ }
17324
+ }
17325
+ break;
17326
+ }
17327
+ case "messageStop":
17328
+ finishReason = mapBedrockStopReason(data.stopReason);
17329
+ if (typeof data.stopReason === "string") rawFinishReason = data.stopReason;
17330
+ break;
17331
+ case "metadata": {
17332
+ const u = data.usage ?? {};
17333
+ usage = {
17334
+ inputTokens: u.inputTokens ?? 0,
17335
+ outputTokens: u.outputTokens ?? 0,
17336
+ totalTokens: u.totalTokens ?? (u.inputTokens ?? 0) + (u.outputTokens ?? 0),
17337
+ cachedInputTokens: u.cacheReadInputTokens ?? u.cacheReadInputTokenCount ?? 0,
17338
+ cachedWriteTokens: u.cacheWriteInputTokens ?? u.cacheWriteInputTokenCount ?? 0,
17339
+ cachedOutputTokens: 0,
17340
+ reasoningTokens: 0
17341
+ };
17342
+ break;
17343
+ }
17344
+ }
17345
+ }
17346
+ const blocks = [...reasoningByIndex.values()].filter(
17347
+ (b) => b.type === "thinking" && b.signature || b.type === "redacted_thinking" && b.data
17348
+ );
16719
17349
  yield {
16720
- id: response.id,
16721
- model: response.model,
16722
- delta: {
16723
- content: response.content ?? void 0,
16724
- toolCalls: response.toolCalls.length > 0 ? response.toolCalls : void 0
16725
- },
16726
- usage: response.usage,
16727
- finishReason: response.finishReason
17350
+ id,
17351
+ model: modelId,
17352
+ delta: blocks.length > 0 ? { reasoning: { blocks } } : {},
17353
+ finishReason: finishReason ?? "stop",
17354
+ ...rawFinishReason ? { rawFinishReason } : {},
17355
+ usage
16728
17356
  };
16729
17357
  }
17358
+ // ─── Embeddings ──────────────────────────────────────────────────────────
17359
+ /**
17360
+ * InvokeModel embeddings. Supported families (by model id, inference-profile
17361
+ * prefixes such as `us.` allowed):
17362
+ * - Amazon Titan Text Embeddings (v1, v2): one text per call, `dimensions`
17363
+ * (v2: 256/512/1024) and `normalize` via `extra`.
17364
+ * - Cohere Embed (v3, v4): a batch of texts per call (default 96), `inputType`
17365
+ * maps to `input_type`, `dimensions` to `output_dimension` (v4).
17366
+ */
17367
+ async embed(request) {
17368
+ const model = requireEmbeddingModel(this.providerName, request.model);
17369
+ const id = model.toLowerCase();
17370
+ const raw = [];
17371
+ let inputTokens = 0;
17372
+ let vectors = [];
17373
+ if (id.includes("titan-embed")) {
17374
+ const results = await mapWithConcurrency(request.input, 4, async (text) => {
17375
+ const body = { inputText: text };
17376
+ if (request.dimensions != null && !id.includes("titan-embed-text-v1")) body.dimensions = request.dimensions;
17377
+ if (request.extra) Object.assign(body, request.extra);
17378
+ const res = await this.invokeModel(model, body, request.signal);
17379
+ const json = await res.json();
17380
+ return { json, tokens: json.inputTextTokenCount ?? Number(res.headers.get("x-amzn-bedrock-input-token-count") ?? 0) };
17381
+ }, request.signal);
17382
+ for (const r of results) {
17383
+ raw.push(r.json);
17384
+ inputTokens += r.tokens || 0;
17385
+ vectors.push(r.json.embedding ?? r.json.embeddingsByType?.float);
17386
+ }
17387
+ } else if (id.includes("cohere.embed")) {
17388
+ for (const batch of chunkArray(request.input, request.batchSize ?? 96)) {
17389
+ const body = {
17390
+ texts: batch,
17391
+ input_type: request.inputType ?? "search_document",
17392
+ embedding_types: ["float"]
17393
+ };
17394
+ if (request.dimensions != null) body.output_dimension = request.dimensions;
17395
+ if (request.extra) Object.assign(body, request.extra);
17396
+ const res = await this.invokeModel(model, body, request.signal);
17397
+ const json = await res.json();
17398
+ raw.push(json);
17399
+ const emb = Array.isArray(json.embeddings) ? json.embeddings : json.embeddings?.float;
17400
+ vectors.push(...emb ?? []);
17401
+ inputTokens += Number(res.headers.get("x-amzn-bedrock-input-token-count") ?? 0) || 0;
17402
+ }
17403
+ } else {
17404
+ throw new ProviderError(
17405
+ `Bedrock embeddings are supported for Amazon Titan and Cohere Embed models, not "${model}"`,
17406
+ this.providerName,
17407
+ 400
17408
+ );
17409
+ }
17410
+ assertVectorCount(this.providerName, vectors, request.input.length);
17411
+ return { model, vectors, usage: { inputTokens, totalTokens: inputTokens }, raw };
17412
+ }
17413
+ async invokeModel(modelId, body, signal) {
17414
+ const host = `bedrock-runtime.${this.region}.amazonaws.com`;
17415
+ const url = `https://${host}/model/${encodeURIComponent(modelId)}/invoke`;
17416
+ const bodyStr = JSON.stringify(body);
17417
+ const res = await this.doFetchWithRetry(() => {
17418
+ const headers = signRequest({
17419
+ method: "POST",
17420
+ url,
17421
+ headers: {
17422
+ "Content-Type": "application/json",
17423
+ Accept: "application/json",
17424
+ ...this.defaultHeaders
17425
+ },
17426
+ body: bodyStr,
17427
+ region: this.region,
17428
+ service: "bedrock",
17429
+ credentials: this.credentials
17430
+ });
17431
+ return this.httpFetch(url, { method: "POST", headers, body: bodyStr, signal });
17432
+ }, signal);
17433
+ if (!res.ok) {
17434
+ const text = await res.text().catch(() => "");
17435
+ throw new ProviderError(`Bedrock API error ${res.status}: ${text}`, this.providerName, res.status, text);
17436
+ }
17437
+ return res;
17438
+ }
16730
17439
  // ─── Internals ───────────────────────────────────────────────────────────
16731
- buildConverseBody(request) {
17440
+ buildConverseBody(request, downgradeToolChoice = false) {
16732
17441
  const { system, messages } = this.splitSystemMessages(request.messages);
16733
17442
  const body = {
16734
17443
  messages: this.toBedrockMessages(messages)
@@ -16752,8 +17461,9 @@ var BedrockProvider = class extends BaseProvider {
16752
17461
  body.toolConfig = {
16753
17462
  tools
16754
17463
  };
17464
+ const forceOk = !downgradeToolChoice && supportsForcedToolChoice(request.model || this.defaultModel);
16755
17465
  if (request.toolChoice != null) {
16756
- if (request.toolChoice === "auto") {
17466
+ if (request.toolChoice === "auto" || !forceOk && request.toolChoice !== "none") {
16757
17467
  body.toolConfig.toolChoice = { auto: {} };
16758
17468
  } else if (request.toolChoice === "required") {
16759
17469
  body.toolConfig.toolChoice = { any: {} };
@@ -16763,9 +17473,17 @@ var BedrockProvider = class extends BaseProvider {
16763
17473
  }
16764
17474
  }
16765
17475
  if (request.extra) {
16766
- Object.assign(body, request.extra);
17476
+ const fields = { ...request.extra.additionalModelRequestFields ?? {} };
17477
+ const topLevel = { ...request.extra.__top ?? {} };
17478
+ for (const [key, value] of Object.entries(request.extra)) {
17479
+ if (key === "additionalModelRequestFields" || key === "__top") continue;
17480
+ if (CONVERSE_TOP_LEVEL_FIELDS.has(key)) body[key] = value;
17481
+ else fields[key] = value;
17482
+ }
17483
+ Object.assign(body, topLevel);
17484
+ if (Object.keys(fields).length > 0) body.additionalModelRequestFields = fields;
16767
17485
  }
16768
- applyBedrockReasoning(body, request.reasoning);
17486
+ applyBedrockReasoning(body, request.reasoning, { model: request.model || this.defaultModel, mode: this.thinkingMode });
16769
17487
  return body;
16770
17488
  }
16771
17489
  splitSystemMessages(messages) {
@@ -16888,9 +17606,22 @@ var BedrockProvider = class extends BaseProvider {
16888
17606
  }
16889
17607
  };
16890
17608
  }
16891
- async doFetch(modelId, body, signal) {
17609
+ /** Sends the Converse call; retries once with toolChoice auto when the
17610
+ * model rejects forced tool use. */
17611
+ async converseFetch(modelId, request, stream) {
17612
+ const body = this.buildConverseBody(request);
17613
+ try {
17614
+ return await this.doFetch(modelId, body, request.signal, stream);
17615
+ } catch (err) {
17616
+ const tc = body.toolConfig?.toolChoice;
17617
+ if (!(err instanceof ProviderError) || err.statusCode !== 400 || !tc || tc.auto) throw err;
17618
+ if (!forcedToolChoiceRejected(String(err.responseBody ?? err.message))) throw err;
17619
+ return this.doFetch(modelId, this.buildConverseBody(request, true), request.signal, stream);
17620
+ }
17621
+ }
17622
+ async doFetch(modelId, body, signal, stream) {
16892
17623
  const host = `bedrock-runtime.${this.region}.amazonaws.com`;
16893
- const url = `https://${host}/model/${encodeURIComponent(modelId)}/converse`;
17624
+ const url = `https://${host}/model/${encodeURIComponent(modelId)}/${stream ? "converse-stream" : "converse"}`;
16894
17625
  const bodyStr = JSON.stringify(body);
16895
17626
  const res = await this.doFetchWithRetry(() => {
16896
17627
  const headers = signRequest({
@@ -16898,7 +17629,7 @@ var BedrockProvider = class extends BaseProvider {
16898
17629
  url,
16899
17630
  headers: {
16900
17631
  "Content-Type": "application/json",
16901
- Accept: "application/json",
17632
+ Accept: stream ? "application/vnd.amazon.eventstream" : "application/json",
16902
17633
  ...this.defaultHeaders
16903
17634
  },
16904
17635
  body: bodyStr,
@@ -16906,7 +17637,7 @@ var BedrockProvider = class extends BaseProvider {
16906
17637
  service: "bedrock",
16907
17638
  credentials: this.credentials
16908
17639
  });
16909
- return fetch(url, { method: "POST", headers, body: bodyStr, signal });
17640
+ return this.httpFetch(url, { method: "POST", headers, body: bodyStr, signal });
16910
17641
  }, signal);
16911
17642
  if (!res.ok) {
16912
17643
  const text = await res.text().catch(() => "");
@@ -16917,7 +17648,7 @@ var BedrockProvider = class extends BaseProvider {
16917
17648
  text
16918
17649
  );
16919
17650
  }
16920
- return res.json();
17651
+ return res;
16921
17652
  }
16922
17653
  parseResponse(json, modelId) {
16923
17654
  const output = json.output?.message;
@@ -16953,8 +17684,8 @@ var BedrockProvider = class extends BaseProvider {
16953
17684
  inputTokens: usage.inputTokens ?? 0,
16954
17685
  outputTokens: usage.outputTokens ?? 0,
16955
17686
  totalTokens: usage.totalTokens ?? (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0),
16956
- cachedInputTokens: usage.cacheReadInputTokenCount ?? 0,
16957
- cachedWriteTokens: usage.cacheWriteInputTokenCount ?? 0,
17687
+ cachedInputTokens: usage.cacheReadInputTokens ?? usage.cacheReadInputTokenCount ?? 0,
17688
+ cachedWriteTokens: usage.cacheWriteInputTokens ?? usage.cacheWriteInputTokenCount ?? 0,
16958
17689
  cachedOutputTokens: 0,
16959
17690
  // Bedrock bills thinking tokens inside outputTokens; no separate count.
16960
17691
  reasoningTokens: 0
@@ -16966,11 +17697,26 @@ var BedrockProvider = class extends BaseProvider {
16966
17697
  toolCalls,
16967
17698
  usage: tokenUsage,
16968
17699
  finishReason: mapBedrockStopReason(json.stopReason),
17700
+ ...typeof json.stopReason === "string" ? { rawFinishReason: json.stopReason } : {},
16969
17701
  reasoning: reasoningBlocks.length > 0 ? { blocks: reasoningBlocks, summary: summaryParts.join("\n").trim() || void 0 } : void 0,
16970
17702
  raw: json
16971
17703
  };
16972
17704
  }
16973
17705
  };
17706
+ var CONVERSE_TOP_LEVEL_FIELDS = /* @__PURE__ */ new Set([
17707
+ "messages",
17708
+ "system",
17709
+ "inferenceConfig",
17710
+ "toolConfig",
17711
+ "guardrailConfig",
17712
+ "additionalModelRequestFields",
17713
+ "additionalModelResponseFieldPaths",
17714
+ "promptVariables",
17715
+ "requestMetadata",
17716
+ "performanceConfig",
17717
+ "serviceTier",
17718
+ "outputConfig"
17719
+ ]);
16974
17720
  function appendBedrockReasoning(content, blocks) {
16975
17721
  if (!blocks?.length) return;
16976
17722
  for (const b of blocks) {
@@ -16985,6 +17731,23 @@ function appendBedrockReasoning(content, blocks) {
16985
17731
  }
16986
17732
  }
16987
17733
  }
17734
+ function bedrockExceptionStatus(code) {
17735
+ switch (code) {
17736
+ case "throttlingException":
17737
+ return 429;
17738
+ case "validationException":
17739
+ return 400;
17740
+ case "modelTimeoutException":
17741
+ return 408;
17742
+ case "serviceUnavailableException":
17743
+ return 503;
17744
+ case "internalServerException":
17745
+ case "modelStreamErrorException":
17746
+ return 500;
17747
+ default:
17748
+ return void 0;
17749
+ }
17750
+ }
16988
17751
  function mapBedrockStopReason(reason) {
16989
17752
  switch (reason) {
16990
17753
  case "end_turn":
@@ -16993,8 +17756,10 @@ function mapBedrockStopReason(reason) {
16993
17756
  case "tool_use":
16994
17757
  return "tool_calls";
16995
17758
  case "max_tokens":
17759
+ case "model_context_window_exceeded":
16996
17760
  return "length";
16997
17761
  case "content_filtered":
17762
+ case "guardrail_intervened":
16998
17763
  case "guardrail":
16999
17764
  return "content_filter";
17000
17765
  default:
@@ -17024,10 +17789,12 @@ var VertexProvider = class extends BaseProvider {
17024
17789
  super();
17025
17790
  this.providerName = "vertex";
17026
17791
  this.tokenExpiry = 0;
17792
+ this.configureTransport(config);
17027
17793
  this.projectId = config.projectId;
17028
17794
  this.location = config.location ?? "us-central1";
17029
17795
  this.defaultModel = config.defaultModel ?? "gemini-2.0-flash";
17030
17796
  this.defaultHeaders = config.defaultHeaders ?? {};
17797
+ if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
17031
17798
  if (config.accessToken) {
17032
17799
  this.accessToken = config.accessToken;
17033
17800
  this.tokenExpiry = Date.now() + 36e5;
@@ -17050,6 +17817,7 @@ var VertexProvider = class extends BaseProvider {
17050
17817
  const url = this.buildUrl(modelId, true);
17051
17818
  const res = await this.doFetch(url, body, request.signal);
17052
17819
  if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
17820
+ const counter = { next: 0 };
17053
17821
  const contentType = res.headers.get("content-type") ?? "";
17054
17822
  if (contentType.includes("text/event-stream")) {
17055
17823
  for await (const event of parseSSEStream(res.body, request.signal)) {
@@ -17060,7 +17828,7 @@ var VertexProvider = class extends BaseProvider {
17060
17828
  } catch {
17061
17829
  continue;
17062
17830
  }
17063
- yield this.parseStreamChunk(chunk, modelId);
17831
+ yield this.parseStreamChunk(chunk, modelId, counter);
17064
17832
  }
17065
17833
  } else {
17066
17834
  const reader = res.body.getReader();
@@ -17078,7 +17846,7 @@ var VertexProvider = class extends BaseProvider {
17078
17846
  if (!trimmed || trimmed === "[" || trimmed === "]") continue;
17079
17847
  try {
17080
17848
  const chunk = JSON.parse(trimmed);
17081
- yield this.parseStreamChunk(chunk, modelId);
17849
+ yield this.parseStreamChunk(chunk, modelId, counter);
17082
17850
  } catch {
17083
17851
  buffer = line + "\n" + buffer;
17084
17852
  break;
@@ -17089,7 +17857,7 @@ var VertexProvider = class extends BaseProvider {
17089
17857
  if (remaining && remaining !== "[" && remaining !== "]") {
17090
17858
  try {
17091
17859
  const chunk = JSON.parse(remaining);
17092
- yield this.parseStreamChunk(chunk, modelId);
17860
+ yield this.parseStreamChunk(chunk, modelId, counter);
17093
17861
  } catch {
17094
17862
  }
17095
17863
  }
@@ -17100,6 +17868,48 @@ var VertexProvider = class extends BaseProvider {
17100
17868
  }
17101
17869
  }
17102
17870
  // ─── Internals ───────────────────────────────────────────────────────────
17871
+ /**
17872
+ * Vertex `:predict` embeddings (text-embedding-00x, text-multilingual-embedding,
17873
+ * gemini-embedding-001). `inputType` maps to the task type; `dimensions` to
17874
+ * `outputDimensionality`. gemini-embedding takes one instance per request, the
17875
+ * text-embedding models up to `batchSize` (default 100).
17876
+ */
17877
+ async embed(request) {
17878
+ const model = requireEmbeddingModel(this.providerName, request.model);
17879
+ const perRequest = request.batchSize ?? (/gemini-embedding/i.test(model) ? 1 : 100);
17880
+ const url = `https://${this.location}-aiplatform.googleapis.com/v1/projects/${this.projectId}/locations/${this.location}/publishers/google/models/${model}:predict`;
17881
+ const taskType = request.inputType ? Object.prototype.hasOwnProperty.call(GEMINI_TASK_TYPES, request.inputType) ? GEMINI_TASK_TYPES[request.inputType] : request.inputType.toUpperCase() : void 0;
17882
+ const vectors = [];
17883
+ const raw = [];
17884
+ let inputTokens = 0;
17885
+ for (const batch of chunkArray(request.input, perRequest)) {
17886
+ const body = {
17887
+ instances: batch.map((content) => ({ content, ...taskType ? { task_type: taskType } : {} }))
17888
+ };
17889
+ const { parameters: extraParameters, ...extraRest } = request.extra ?? {};
17890
+ const parameters = {
17891
+ ...request.dimensions != null ? { outputDimensionality: request.dimensions } : {},
17892
+ // Caller-supplied parameters are merged in, not replacing the above (an
17893
+ // explicit extra.parameters.outputDimensionality still wins).
17894
+ ...extraParameters && typeof extraParameters === "object" ? extraParameters : {}
17895
+ };
17896
+ if (Object.keys(parameters).length > 0) body.parameters = parameters;
17897
+ Object.assign(body, extraRest);
17898
+ const res = await this.doFetch(url, body, request.signal);
17899
+ const json = await res.json();
17900
+ raw.push(json);
17901
+ for (const p of json.predictions ?? []) {
17902
+ const values = p.embeddings?.values;
17903
+ if (!Array.isArray(values)) {
17904
+ throw new ProviderError("Vertex embeddings response has a prediction without an embeddings.values array", this.providerName, void 0, json);
17905
+ }
17906
+ vectors.push(values);
17907
+ inputTokens += p.embeddings?.statistics?.token_count ?? 0;
17908
+ }
17909
+ }
17910
+ assertVectorCount(this.providerName, vectors, request.input.length);
17911
+ return { model, vectors, usage: { inputTokens, totalTokens: inputTokens }, raw };
17912
+ }
17103
17913
  buildUrl(modelId, stream) {
17104
17914
  const base = `https://${this.location}-aiplatform.googleapis.com/v1`;
17105
17915
  const path2 = `projects/${this.projectId}/locations/${this.location}/publishers/google/models/${modelId}`;
@@ -17197,7 +18007,9 @@ var VertexProvider = class extends BaseProvider {
17197
18007
  functionCall: {
17198
18008
  name: tc.name,
17199
18009
  args: safeJsonParse3(tc.arguments)
17200
- }
18010
+ },
18011
+ // Gemini 3 requires the signature of each functionCall echoed back.
18012
+ ...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {}
17201
18013
  });
17202
18014
  }
17203
18015
  return { role: "model", parts: parts2 };
@@ -17294,7 +18106,7 @@ var VertexProvider = class extends BaseProvider {
17294
18106
  sign.update(signingInput);
17295
18107
  const signature = sign.sign(sa.private_key, "base64url");
17296
18108
  const jwt = `${signingInput}.${signature}`;
17297
- const tokenRes = await fetch("https://oauth2.googleapis.com/token", {
18109
+ const tokenRes = await this.httpFetch("https://oauth2.googleapis.com/token", {
17298
18110
  method: "POST",
17299
18111
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
17300
18112
  body: `grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=${jwt}`
@@ -17308,16 +18120,20 @@ var VertexProvider = class extends BaseProvider {
17308
18120
  }
17309
18121
  async doFetch(url, body, signal) {
17310
18122
  const token = await this.getAccessToken();
17311
- const res = await fetch(url, {
17312
- method: "POST",
17313
- headers: {
17314
- "Content-Type": "application/json",
17315
- Authorization: `Bearer ${token}`,
17316
- ...this.defaultHeaders
17317
- },
17318
- body: JSON.stringify(body),
18123
+ const bodyStr = JSON.stringify(body);
18124
+ const res = await this.doFetchWithRetry(
18125
+ () => this.httpFetch(url, {
18126
+ method: "POST",
18127
+ headers: {
18128
+ "Content-Type": "application/json",
18129
+ Authorization: `Bearer ${token}`,
18130
+ ...this.defaultHeaders
18131
+ },
18132
+ body: bodyStr,
18133
+ signal
18134
+ }),
17319
18135
  signal
17320
- });
18136
+ );
17321
18137
  if (!res.ok) {
17322
18138
  const text = await res.text().catch(() => "");
17323
18139
  throw new ProviderError(
@@ -17347,7 +18163,8 @@ var VertexProvider = class extends BaseProvider {
17347
18163
  toolCalls.push({
17348
18164
  id: `call_${toolCallIdx++}`,
17349
18165
  name: part.functionCall.name,
17350
- arguments: JSON.stringify(part.functionCall.args ?? {})
18166
+ arguments: JSON.stringify(part.functionCall.args ?? {}),
18167
+ ...part.thoughtSignature ? { thoughtSignature: part.thoughtSignature } : {}
17351
18168
  });
17352
18169
  }
17353
18170
  }
@@ -17368,11 +18185,12 @@ var VertexProvider = class extends BaseProvider {
17368
18185
  toolCalls,
17369
18186
  usage: tokenUsage,
17370
18187
  finishReason: mapGeminiFinishReason(candidate?.finishReason),
18188
+ ...typeof candidate?.finishReason === "string" ? { rawFinishReason: candidate.finishReason } : {},
17371
18189
  reasoning: thoughtParts.length > 0 ? { summary: thoughtParts.join("\n").trim() || void 0 } : void 0,
17372
18190
  raw: json
17373
18191
  };
17374
18192
  }
17375
- parseStreamChunk(chunk, modelId) {
18193
+ parseStreamChunk(chunk, modelId, counter) {
17376
18194
  const candidate = chunk.candidates?.[0];
17377
18195
  const parts = candidate?.content?.parts ?? [];
17378
18196
  const delta = {};
@@ -17386,9 +18204,12 @@ var VertexProvider = class extends BaseProvider {
17386
18204
  } else if (part.functionCall) {
17387
18205
  if (!delta.toolCalls) delta.toolCalls = [];
17388
18206
  delta.toolCalls.push({
17389
- id: `call_${delta.toolCalls.length}`,
18207
+ // Unique across the whole stream: the adapter merges chunks by id.
18208
+ id: `call_${counter.next}`,
18209
+ index: counter.next++,
17390
18210
  name: part.functionCall.name,
17391
- arguments: JSON.stringify(part.functionCall.args ?? {})
18211
+ arguments: JSON.stringify(part.functionCall.args ?? {}),
18212
+ ...part.thoughtSignature ? { thoughtSignature: part.thoughtSignature } : {}
17392
18213
  });
17393
18214
  }
17394
18215
  }
@@ -17410,10 +18231,21 @@ var VertexProvider = class extends BaseProvider {
17410
18231
  model: modelId,
17411
18232
  delta,
17412
18233
  usage,
17413
- finishReason: mapGeminiFinishReason(candidate?.finishReason)
18234
+ finishReason: mapGeminiFinishReason(candidate?.finishReason),
18235
+ ...typeof candidate?.finishReason === "string" ? { rawFinishReason: candidate.finishReason } : {}
17414
18236
  };
17415
18237
  }
17416
18238
  };
18239
+ var GEMINI_TASK_TYPES = {
18240
+ search_document: "RETRIEVAL_DOCUMENT",
18241
+ search_query: "RETRIEVAL_QUERY",
18242
+ classification: "CLASSIFICATION",
18243
+ clustering: "CLUSTERING",
18244
+ semantic_similarity: "SEMANTIC_SIMILARITY",
18245
+ question_answering: "QUESTION_ANSWERING",
18246
+ fact_verification: "FACT_VERIFICATION",
18247
+ code_retrieval_query: "CODE_RETRIEVAL_QUERY"
18248
+ };
17417
18249
  function mapGeminiFinishReason(reason) {
17418
18250
  switch (reason) {
17419
18251
  case "STOP":
@@ -17462,6 +18294,6 @@ function createProvider(config) {
17462
18294
  }
17463
18295
  }
17464
18296
 
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 };
18297
+ 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, supportsAdaptiveThinking, textFromContent, toMessageUsage, toStrictCompatible, toStrictToolSchema, tokenize, toolPolicy, traceSessionToOtlp, validateReasoningConfig, validateToolArgs, webhookApproval, withTools, withinDepth, writeSummaryFactsToMemory };
17466
18298
  //# sourceMappingURL=index.mjs.map
17467
18299
  //# sourceMappingURL=index.mjs.map