@cognipeer/agent-sdk 0.10.6 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -3
- package/dist/index.cjs +2187 -284
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +165 -353
- package/dist/index.d.ts +165 -353
- package/dist/index.mjs +2169 -285
- package/dist/index.mjs.map +1 -1
- package/dist/model-rules-Bg9nSqyN.d.cts +658 -0
- package/dist/model-rules-Bg9nSqyN.d.ts +658 -0
- package/dist/model-rules.cjs +763 -0
- package/dist/model-rules.cjs.map +1 -0
- package/dist/model-rules.d.cts +1 -0
- package/dist/model-rules.d.ts +1 -0
- package/dist/model-rules.json +622 -0
- package/dist/model-rules.mjs +756 -0
- package/dist/model-rules.mjs.map +1 -0
- package/package.json +46 -2
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
|
-
|
|
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
|
-
|
|
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 = {
|
|
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
|
-
|
|
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:
|
|
2943
|
-
//
|
|
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) {
|
|
@@ -5077,10 +5095,10 @@ function createToolsNode(initialTools, opts) {
|
|
|
5077
5095
|
const toolCallId = tc.id || `${tc.name}_${toolCount + 1}`;
|
|
5078
5096
|
const validatedArgs = validateToolArgs(tool, args);
|
|
5079
5097
|
if (!validatedArgs.ok && resolved.toolResponses.schemaValidation === "strict") {
|
|
5080
|
-
const
|
|
5081
|
-
push({ role: "tool", content:
|
|
5082
|
-
markToolFailure(
|
|
5083
|
-
onEvent?.({ type: "tool_call", phase: "error", name: tc.name, id: tc.id, args, error: { message:
|
|
5098
|
+
const errorMessage2 = `Tool argument validation failed for ${tc.name}: ${validatedArgs.message}`;
|
|
5099
|
+
push({ role: "tool", content: errorMessage2, tool_call_id: toolCallId, name: tc.name });
|
|
5100
|
+
markToolFailure(errorMessage2, tc.name, toolCallId);
|
|
5101
|
+
onEvent?.({ type: "tool_call", phase: "error", name: tc.name, id: tc.id, args, error: { message: errorMessage2 } });
|
|
5084
5102
|
toolCount += 1;
|
|
5085
5103
|
return { status: "error" };
|
|
5086
5104
|
}
|
|
@@ -6091,7 +6109,7 @@ var LEVEL_DEFAULTS = {
|
|
|
6091
6109
|
};
|
|
6092
6110
|
var VALID_LEVELS = ["minimal", "low", "medium", "high"];
|
|
6093
6111
|
var VALID_CADENCES = ["off", "every_turn", "after_tool", "on_branch", "initial_then_after_tool"];
|
|
6094
|
-
var VALID_EFFORTS = ["none", "minimal", "low", "medium", "high"];
|
|
6112
|
+
var VALID_EFFORTS = ["none", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
6095
6113
|
function validateReasoningConfig(input) {
|
|
6096
6114
|
if (!input) return;
|
|
6097
6115
|
if (input.level !== void 0 && !VALID_LEVELS.includes(input.level)) {
|
|
@@ -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,56 @@ 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.onModelRuleLearned = config.onModelRuleLearned;
|
|
11583
|
+
this.timeoutMs = typeof config.timeoutMs === "number" && config.timeoutMs > 0 ? config.timeoutMs : void 0;
|
|
11584
|
+
}
|
|
11585
|
+
/**
|
|
11586
|
+
* The single HTTP entry point for every provider call site. Uses the
|
|
11587
|
+
* configured `fetch` and applies `timeoutMs`: the timer covers the time until
|
|
11588
|
+
* the response HEADERS arrive and is cleared after that, so a long-running
|
|
11589
|
+
* stream is never cut by it (use the request `signal` to cancel a stream).
|
|
11590
|
+
* A timeout surfaces as a `ProviderError` with status 408. The caller's
|
|
11591
|
+
* `signal` still aborts the request as before.
|
|
11592
|
+
*/
|
|
11593
|
+
async httpFetch(url, init = {}) {
|
|
11594
|
+
const doFetch = this.fetchImpl ?? fetch;
|
|
11595
|
+
const timeoutMs = this.timeoutMs;
|
|
11596
|
+
if (!timeoutMs) return doFetch(url, init);
|
|
11597
|
+
const controller = new AbortController();
|
|
11598
|
+
const outer = init.signal ?? void 0;
|
|
11599
|
+
let timedOut = false;
|
|
11600
|
+
const onOuterAbort = () => controller.abort(outer?.reason);
|
|
11601
|
+
if (outer) {
|
|
11602
|
+
if (outer.aborted) controller.abort(outer.reason);
|
|
11603
|
+
else outer.addEventListener("abort", onOuterAbort, { once: true });
|
|
11604
|
+
}
|
|
11605
|
+
const timer = setTimeout(() => {
|
|
11606
|
+
timedOut = true;
|
|
11607
|
+
controller.abort(new Error(`timed out after ${timeoutMs}ms`));
|
|
11608
|
+
}, timeoutMs);
|
|
11609
|
+
try {
|
|
11610
|
+
const res = await doFetch(url, { ...init, signal: controller.signal });
|
|
11611
|
+
return res;
|
|
11612
|
+
} catch (err) {
|
|
11613
|
+
if (timedOut) {
|
|
11614
|
+
throw new ProviderError(`${this.providerName} request timed out after ${timeoutMs}ms`, this.providerName, 408);
|
|
11615
|
+
}
|
|
11616
|
+
throw err;
|
|
11617
|
+
} finally {
|
|
11618
|
+
clearTimeout(timer);
|
|
11619
|
+
}
|
|
11620
|
+
}
|
|
11621
|
+
/**
|
|
11622
|
+
* Embeds `request.input`. Implemented by the providers that have an
|
|
11623
|
+
* embeddings endpoint (OpenAI, Azure, openai-compatible, Bedrock, Vertex);
|
|
11624
|
+
* the others reject with a 400 ProviderError.
|
|
11625
|
+
*/
|
|
11626
|
+
async embed(_request) {
|
|
11627
|
+
throw new ProviderError(`${this.providerName} does not support embeddings`, this.providerName, 400);
|
|
11628
|
+
}
|
|
11539
11629
|
/**
|
|
11540
11630
|
* Helper concrete providers can wrap their fetch with. Retries 429/5xx
|
|
11541
11631
|
* with exponential backoff and respects Retry-After if the response
|
|
@@ -11577,34 +11667,13 @@ var BaseProvider = class {
|
|
|
11577
11667
|
}
|
|
11578
11668
|
};
|
|
11579
11669
|
|
|
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
11670
|
// src/providers/jev.ts
|
|
11603
11671
|
var JEV_DEFAULT_BASE_URL = "https://api.typesafe.ai";
|
|
11604
11672
|
var JevProvider = class extends BaseProvider {
|
|
11605
11673
|
constructor(config) {
|
|
11606
11674
|
super();
|
|
11607
11675
|
this.providerName = "jev";
|
|
11676
|
+
this.configureTransport(config);
|
|
11608
11677
|
this.apiKey = config.apiKey;
|
|
11609
11678
|
this.baseURL = (config.baseURL ?? JEV_DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
11610
11679
|
this.defaultModel = config.defaultModel;
|
|
@@ -11620,7 +11689,7 @@ var JevProvider = class extends BaseProvider {
|
|
|
11620
11689
|
questions: request.questions
|
|
11621
11690
|
};
|
|
11622
11691
|
const res = await this.doFetchWithRetry(
|
|
11623
|
-
() =>
|
|
11692
|
+
() => this.httpFetch(`${this.baseURL}/v1/systemone`, {
|
|
11624
11693
|
method: "POST",
|
|
11625
11694
|
headers: {
|
|
11626
11695
|
"Content-Type": "application/json",
|
|
@@ -13856,12 +13925,12 @@ function responseCache(config = {}) {
|
|
|
13856
13925
|
};
|
|
13857
13926
|
}
|
|
13858
13927
|
function signRequest(req) {
|
|
13859
|
-
const now = /* @__PURE__ */ new Date();
|
|
13928
|
+
const now = req.now ?? /* @__PURE__ */ new Date();
|
|
13860
13929
|
const dateStamp = toDateStamp(now);
|
|
13861
13930
|
const amzDate = toAmzDate(now);
|
|
13862
13931
|
const parsed = new URL(req.url);
|
|
13863
13932
|
const host = parsed.host;
|
|
13864
|
-
const canonicalUri = parsed.pathname || "/";
|
|
13933
|
+
const canonicalUri = (parsed.pathname || "/").split("/").map((seg) => encodeURIComponent(seg).replace(/[!'()*]/g, (c) => "%" + c.charCodeAt(0).toString(16).toUpperCase())).join("/");
|
|
13865
13934
|
const canonicalQuerystring = sortQueryParams(parsed.searchParams);
|
|
13866
13935
|
const headers = {
|
|
13867
13936
|
...req.headers,
|
|
@@ -15178,98 +15247,805 @@ function languageGuard(config) {
|
|
|
15178
15247
|
// src/index.ts
|
|
15179
15248
|
init_content();
|
|
15180
15249
|
|
|
15181
|
-
// src/
|
|
15182
|
-
|
|
15183
|
-
|
|
15184
|
-
|
|
15185
|
-
|
|
15186
|
-
|
|
15187
|
-
|
|
15188
|
-
|
|
15189
|
-
|
|
15190
|
-
|
|
15191
|
-
|
|
15192
|
-
|
|
15193
|
-
|
|
15194
|
-
|
|
15195
|
-
|
|
15196
|
-
|
|
15197
|
-
|
|
15198
|
-
|
|
15250
|
+
// src/models/model-rules.json
|
|
15251
|
+
var model_rules_default = {
|
|
15252
|
+
version: 1,
|
|
15253
|
+
effortLadder: [
|
|
15254
|
+
"none",
|
|
15255
|
+
"minimal",
|
|
15256
|
+
"low",
|
|
15257
|
+
"medium",
|
|
15258
|
+
"high",
|
|
15259
|
+
"xhigh",
|
|
15260
|
+
"max"
|
|
15261
|
+
],
|
|
15262
|
+
budgets: {
|
|
15263
|
+
minimal: 1024,
|
|
15264
|
+
low: 2048,
|
|
15265
|
+
medium: 8192,
|
|
15266
|
+
high: 16384,
|
|
15267
|
+
xhigh: 24576,
|
|
15268
|
+
max: 32768
|
|
15269
|
+
},
|
|
15270
|
+
geminiBudgets: {
|
|
15271
|
+
minimal: 512,
|
|
15272
|
+
low: 1024,
|
|
15273
|
+
medium: 4096,
|
|
15274
|
+
high: 12e3,
|
|
15275
|
+
xhigh: 24576,
|
|
15276
|
+
max: 24576
|
|
15277
|
+
},
|
|
15278
|
+
rules: [
|
|
15279
|
+
{
|
|
15280
|
+
id: "openai-chat-models",
|
|
15281
|
+
family: "openai",
|
|
15282
|
+
match: "^(?:chatgpt|gpt-[\\d.]+[a-z0-9.-]*?-chat)",
|
|
15283
|
+
reasoning: {
|
|
15284
|
+
style: "none",
|
|
15285
|
+
efforts: [],
|
|
15286
|
+
off: null
|
|
15287
|
+
},
|
|
15288
|
+
sampling: {
|
|
15289
|
+
temperature: "any",
|
|
15290
|
+
topP: true,
|
|
15291
|
+
topK: true,
|
|
15292
|
+
penalties: true,
|
|
15293
|
+
logprobs: true
|
|
15294
|
+
},
|
|
15295
|
+
maxTokensParam: "max_completion_tokens",
|
|
15296
|
+
chatTools: {
|
|
15297
|
+
reasoning: "any"
|
|
15298
|
+
},
|
|
15299
|
+
source: "docs",
|
|
15300
|
+
note: "Chat-tuned *-chat variants are not reasoning models: ordinary sampling, no reasoning field."
|
|
15301
|
+
},
|
|
15302
|
+
{
|
|
15303
|
+
id: "openai-gpt-6-plus",
|
|
15304
|
+
family: "openai",
|
|
15305
|
+
match: "^gpt-?(?:[6-9]|(?!35(?!\\d))[1-9]\\d+)(?:[.-]|$)",
|
|
15306
|
+
reasoning: {
|
|
15307
|
+
style: "effort",
|
|
15308
|
+
efforts: [
|
|
15309
|
+
"none",
|
|
15310
|
+
"low",
|
|
15311
|
+
"medium",
|
|
15312
|
+
"high",
|
|
15313
|
+
"xhigh"
|
|
15314
|
+
],
|
|
15315
|
+
off: "none",
|
|
15316
|
+
responsesEfforts: [
|
|
15317
|
+
"none",
|
|
15318
|
+
"low",
|
|
15319
|
+
"medium",
|
|
15320
|
+
"high",
|
|
15321
|
+
"xhigh",
|
|
15322
|
+
"max"
|
|
15323
|
+
]
|
|
15324
|
+
},
|
|
15325
|
+
sampling: {
|
|
15326
|
+
temperature: "default-only",
|
|
15327
|
+
topP: false,
|
|
15328
|
+
topK: false,
|
|
15329
|
+
penalties: false,
|
|
15330
|
+
logprobs: false
|
|
15331
|
+
},
|
|
15332
|
+
maxTokensParam: "max_completion_tokens",
|
|
15333
|
+
chatTools: {
|
|
15334
|
+
reasoning: "force-none"
|
|
15335
|
+
},
|
|
15336
|
+
source: "verified-2026-10-14",
|
|
15337
|
+
note: "gpt-N, N>=6. Chat Completions takes none/low/medium/high/xhigh (minimal and max are 400s); Responses also takes max. Function tools with an effort other than none are a 400 on Chat Completions and the default effort is not none, so none is sent explicitly. Rejects max_tokens, temperature != 1, top_p, penalties, logprobs."
|
|
15338
|
+
},
|
|
15339
|
+
{
|
|
15340
|
+
id: "openai-gpt-5x",
|
|
15341
|
+
family: "openai",
|
|
15342
|
+
match: "^gpt-?5\\.[1-9]",
|
|
15343
|
+
reasoning: {
|
|
15344
|
+
style: "effort",
|
|
15345
|
+
efforts: [
|
|
15346
|
+
"none",
|
|
15347
|
+
"low",
|
|
15348
|
+
"medium",
|
|
15349
|
+
"high",
|
|
15350
|
+
"xhigh"
|
|
15351
|
+
],
|
|
15352
|
+
off: "none",
|
|
15353
|
+
responsesEfforts: [
|
|
15354
|
+
"none",
|
|
15355
|
+
"low",
|
|
15356
|
+
"medium",
|
|
15357
|
+
"high",
|
|
15358
|
+
"xhigh",
|
|
15359
|
+
"max"
|
|
15360
|
+
]
|
|
15361
|
+
},
|
|
15362
|
+
sampling: {
|
|
15363
|
+
temperature: "default-only",
|
|
15364
|
+
topP: false,
|
|
15365
|
+
topK: false,
|
|
15366
|
+
penalties: false,
|
|
15367
|
+
logprobs: false
|
|
15368
|
+
},
|
|
15369
|
+
maxTokensParam: "max_completion_tokens",
|
|
15370
|
+
chatTools: {
|
|
15371
|
+
reasoning: "force-none"
|
|
15372
|
+
},
|
|
15373
|
+
source: "verified-2026-10-14",
|
|
15374
|
+
note: "gpt-5.1 and newer 5.x. Same wire rules as gpt-6: no minimal/max on Chat Completions (Responses takes max), function tools need reasoning_effort none on Chat Completions."
|
|
15375
|
+
},
|
|
15376
|
+
{
|
|
15377
|
+
id: "openai-gpt-5-base",
|
|
15378
|
+
family: "openai",
|
|
15379
|
+
match: "^gpt-?5(?![.\\d])",
|
|
15380
|
+
reasoning: {
|
|
15381
|
+
style: "effort",
|
|
15382
|
+
efforts: [
|
|
15383
|
+
"minimal",
|
|
15384
|
+
"low",
|
|
15385
|
+
"medium",
|
|
15386
|
+
"high"
|
|
15387
|
+
],
|
|
15388
|
+
off: null
|
|
15389
|
+
},
|
|
15390
|
+
sampling: {
|
|
15391
|
+
temperature: "default-only",
|
|
15392
|
+
topP: false,
|
|
15393
|
+
topK: false,
|
|
15394
|
+
penalties: false,
|
|
15395
|
+
logprobs: false
|
|
15396
|
+
},
|
|
15397
|
+
maxTokensParam: "max_completion_tokens",
|
|
15398
|
+
chatTools: {
|
|
15399
|
+
reasoning: "any"
|
|
15400
|
+
},
|
|
15401
|
+
source: "docs",
|
|
15402
|
+
note: "gpt-5, -mini, -nano, -codex: minimal/low/medium/high, reasoning cannot be turned off (none maps to minimal)."
|
|
15403
|
+
},
|
|
15404
|
+
{
|
|
15405
|
+
id: "openai-o-series",
|
|
15406
|
+
family: "openai",
|
|
15407
|
+
match: "^o[1-9]\\d?(?![a-z0-9])",
|
|
15408
|
+
reasoning: {
|
|
15409
|
+
style: "effort",
|
|
15410
|
+
efforts: [
|
|
15411
|
+
"low",
|
|
15412
|
+
"medium",
|
|
15413
|
+
"high"
|
|
15414
|
+
],
|
|
15415
|
+
off: null
|
|
15416
|
+
},
|
|
15417
|
+
sampling: {
|
|
15418
|
+
temperature: "default-only",
|
|
15419
|
+
topP: false,
|
|
15420
|
+
topK: false,
|
|
15421
|
+
penalties: false,
|
|
15422
|
+
logprobs: false
|
|
15423
|
+
},
|
|
15424
|
+
maxTokensParam: "max_completion_tokens",
|
|
15425
|
+
chatTools: {
|
|
15426
|
+
reasoning: "any"
|
|
15427
|
+
},
|
|
15428
|
+
source: "docs",
|
|
15429
|
+
note: "o1/o3/o4 family: low/medium/high, no sampling overrides."
|
|
15430
|
+
},
|
|
15431
|
+
{
|
|
15432
|
+
id: "openai-gpt-oss",
|
|
15433
|
+
family: "openai",
|
|
15434
|
+
match: "^gpt-?oss",
|
|
15435
|
+
reasoning: {
|
|
15436
|
+
style: "effort",
|
|
15437
|
+
efforts: [
|
|
15438
|
+
"low",
|
|
15439
|
+
"medium",
|
|
15440
|
+
"high"
|
|
15441
|
+
],
|
|
15442
|
+
off: null
|
|
15443
|
+
},
|
|
15444
|
+
sampling: {
|
|
15445
|
+
temperature: "any",
|
|
15446
|
+
topP: true,
|
|
15447
|
+
topK: true,
|
|
15448
|
+
penalties: true,
|
|
15449
|
+
logprobs: true
|
|
15450
|
+
},
|
|
15451
|
+
maxTokensParam: "max_tokens",
|
|
15452
|
+
chatTools: {
|
|
15453
|
+
reasoning: "any"
|
|
15454
|
+
},
|
|
15455
|
+
source: "docs",
|
|
15456
|
+
note: "Open-weight gpt-oss: low/medium/high; sampling and max_tokens behave like an ordinary chat model."
|
|
15457
|
+
},
|
|
15458
|
+
{
|
|
15459
|
+
id: "openai-legacy-gpt",
|
|
15460
|
+
family: "openai",
|
|
15461
|
+
match: "^(?:gpt-?(?:[0-4]|35)(?![0-9])|text-|davinci|babbage)",
|
|
15462
|
+
reasoning: {
|
|
15463
|
+
style: "none",
|
|
15464
|
+
efforts: [],
|
|
15465
|
+
off: null
|
|
15466
|
+
},
|
|
15467
|
+
sampling: {
|
|
15468
|
+
temperature: "any",
|
|
15469
|
+
topP: true,
|
|
15470
|
+
topK: true,
|
|
15471
|
+
penalties: true,
|
|
15472
|
+
logprobs: true
|
|
15473
|
+
},
|
|
15474
|
+
maxTokensParam: "max_tokens",
|
|
15475
|
+
chatTools: {
|
|
15476
|
+
reasoning: "any"
|
|
15477
|
+
},
|
|
15478
|
+
source: "docs",
|
|
15479
|
+
note: "gpt-4o, gpt-4.1, gpt-3.5 and older: no reasoning, ordinary sampling."
|
|
15480
|
+
},
|
|
15481
|
+
{
|
|
15482
|
+
id: "openai-compatible-toggle",
|
|
15483
|
+
family: "openai",
|
|
15484
|
+
match: "^(?:deepseek-(?:r\\d|reasoner)|qwq|qwen-?3)",
|
|
15485
|
+
reasoning: {
|
|
15486
|
+
style: "toggle",
|
|
15487
|
+
efforts: [
|
|
15488
|
+
"none",
|
|
15489
|
+
"minimal",
|
|
15490
|
+
"low",
|
|
15491
|
+
"medium",
|
|
15492
|
+
"high",
|
|
15493
|
+
"xhigh",
|
|
15494
|
+
"max"
|
|
15495
|
+
],
|
|
15496
|
+
off: "none"
|
|
15497
|
+
},
|
|
15498
|
+
sampling: {
|
|
15499
|
+
temperature: "any",
|
|
15500
|
+
topP: true,
|
|
15501
|
+
topK: true,
|
|
15502
|
+
penalties: true,
|
|
15503
|
+
logprobs: true
|
|
15504
|
+
},
|
|
15505
|
+
maxTokensParam: "max_tokens",
|
|
15506
|
+
chatTools: {
|
|
15507
|
+
reasoning: "any"
|
|
15508
|
+
},
|
|
15509
|
+
source: "docs",
|
|
15510
|
+
note: "DeepSeek R/reasoner, QwQ, Qwen3: on/off style hosts. The effort is forwarded as-is (including none, which switches thinking off on thinking-by-default models)."
|
|
15511
|
+
},
|
|
15512
|
+
{
|
|
15513
|
+
id: "openai-default",
|
|
15514
|
+
family: "openai",
|
|
15515
|
+
match: ".*",
|
|
15516
|
+
reasoning: {
|
|
15517
|
+
style: "effort",
|
|
15518
|
+
efforts: [
|
|
15519
|
+
"none",
|
|
15520
|
+
"minimal",
|
|
15521
|
+
"low",
|
|
15522
|
+
"medium",
|
|
15523
|
+
"high",
|
|
15524
|
+
"xhigh",
|
|
15525
|
+
"max"
|
|
15526
|
+
],
|
|
15527
|
+
off: "none"
|
|
15528
|
+
},
|
|
15529
|
+
sampling: {
|
|
15530
|
+
temperature: "any",
|
|
15531
|
+
topP: true,
|
|
15532
|
+
topK: true,
|
|
15533
|
+
penalties: true,
|
|
15534
|
+
logprobs: true
|
|
15535
|
+
},
|
|
15536
|
+
maxTokensParam: "max_tokens",
|
|
15537
|
+
chatTools: {
|
|
15538
|
+
reasoning: "any"
|
|
15539
|
+
},
|
|
15540
|
+
source: "docs",
|
|
15541
|
+
note: "Permissive default for unknown OpenAI-wire models: pass what the caller asked; the provider learns from 400s."
|
|
15542
|
+
},
|
|
15543
|
+
{
|
|
15544
|
+
id: "claude-haiku-5",
|
|
15545
|
+
family: "anthropic",
|
|
15546
|
+
match: "^claude-(?:haiku-5|5(?:-\\d+)?-haiku)(?!\\d)",
|
|
15547
|
+
reasoning: {
|
|
15548
|
+
style: "adaptive",
|
|
15549
|
+
efforts: [
|
|
15550
|
+
"low",
|
|
15551
|
+
"medium",
|
|
15552
|
+
"high",
|
|
15553
|
+
"xhigh",
|
|
15554
|
+
"max"
|
|
15555
|
+
],
|
|
15556
|
+
off: "disabled"
|
|
15557
|
+
},
|
|
15558
|
+
sampling: {
|
|
15559
|
+
temperature: "unsupported",
|
|
15560
|
+
topP: false,
|
|
15561
|
+
topK: false,
|
|
15562
|
+
penalties: false,
|
|
15563
|
+
logprobs: false
|
|
15564
|
+
},
|
|
15565
|
+
maxTokensParam: "max_tokens",
|
|
15566
|
+
chatTools: {
|
|
15567
|
+
reasoning: "any"
|
|
15568
|
+
},
|
|
15569
|
+
source: "verified-2026-10-14",
|
|
15570
|
+
note: "Claude Haiku 5.x: thinking:{type:adaptive} + output_config.effort; thinking:{type:enabled,budget_tokens} is rejected. Off = thinking:{type:disabled}. Sampling params are rejected."
|
|
15571
|
+
},
|
|
15572
|
+
{
|
|
15573
|
+
id: "claude-sonnet-5",
|
|
15574
|
+
family: "anthropic",
|
|
15575
|
+
match: "^claude-(?:sonnet-5|5(?:-\\d+)?-sonnet)(?!\\d)",
|
|
15576
|
+
reasoning: {
|
|
15577
|
+
style: "adaptive",
|
|
15578
|
+
efforts: [
|
|
15579
|
+
"low",
|
|
15580
|
+
"medium",
|
|
15581
|
+
"high",
|
|
15582
|
+
"xhigh",
|
|
15583
|
+
"max"
|
|
15584
|
+
],
|
|
15585
|
+
off: "between_tools"
|
|
15586
|
+
},
|
|
15587
|
+
sampling: {
|
|
15588
|
+
temperature: "unsupported",
|
|
15589
|
+
topP: false,
|
|
15590
|
+
topK: false,
|
|
15591
|
+
penalties: false,
|
|
15592
|
+
logprobs: false
|
|
15593
|
+
},
|
|
15594
|
+
maxTokensParam: "max_tokens",
|
|
15595
|
+
chatTools: {
|
|
15596
|
+
reasoning: "any"
|
|
15597
|
+
},
|
|
15598
|
+
source: "verified-2026-10-14",
|
|
15599
|
+
note: "Claude Sonnet 5.x: adaptive + output_config.effort. thinking:{type:disabled} is rejected; off = thinking:{type:between_tools}. Sampling params are rejected."
|
|
15600
|
+
},
|
|
15601
|
+
{
|
|
15602
|
+
id: "claude-opus-5",
|
|
15603
|
+
family: "anthropic",
|
|
15604
|
+
match: "^claude-(?:opus-5|5(?:-\\d+)?-opus)(?!\\d)",
|
|
15605
|
+
reasoning: {
|
|
15606
|
+
style: "adaptive",
|
|
15607
|
+
efforts: [
|
|
15608
|
+
"low",
|
|
15609
|
+
"medium",
|
|
15610
|
+
"high",
|
|
15611
|
+
"xhigh",
|
|
15612
|
+
"max"
|
|
15613
|
+
],
|
|
15614
|
+
off: null
|
|
15615
|
+
},
|
|
15616
|
+
sampling: {
|
|
15617
|
+
temperature: "unsupported",
|
|
15618
|
+
topP: false,
|
|
15619
|
+
topK: false,
|
|
15620
|
+
penalties: false,
|
|
15621
|
+
logprobs: false
|
|
15622
|
+
},
|
|
15623
|
+
maxTokensParam: "max_tokens",
|
|
15624
|
+
chatTools: {
|
|
15625
|
+
reasoning: "any"
|
|
15626
|
+
},
|
|
15627
|
+
source: "verified-2026-10-14",
|
|
15628
|
+
note: "Claude Opus 5.x: adaptive + output_config.effort; thinking cannot be turned off (none maps to the lowest effort). Sampling params are rejected."
|
|
15629
|
+
},
|
|
15630
|
+
{
|
|
15631
|
+
id: "claude-fable",
|
|
15632
|
+
family: "anthropic",
|
|
15633
|
+
match: "^claude-fable",
|
|
15634
|
+
reasoning: {
|
|
15635
|
+
style: "adaptive",
|
|
15636
|
+
efforts: [
|
|
15637
|
+
"low",
|
|
15638
|
+
"medium",
|
|
15639
|
+
"high",
|
|
15640
|
+
"xhigh",
|
|
15641
|
+
"max"
|
|
15642
|
+
],
|
|
15643
|
+
off: null
|
|
15644
|
+
},
|
|
15645
|
+
sampling: {
|
|
15646
|
+
temperature: "unsupported",
|
|
15647
|
+
topP: false,
|
|
15648
|
+
topK: false,
|
|
15649
|
+
penalties: false,
|
|
15650
|
+
logprobs: false
|
|
15651
|
+
},
|
|
15652
|
+
maxTokensParam: "max_tokens",
|
|
15653
|
+
chatTools: {
|
|
15654
|
+
reasoning: "any"
|
|
15655
|
+
},
|
|
15656
|
+
source: "docs",
|
|
15657
|
+
note: "Claude Fable line: treated like the 5.x adaptive models."
|
|
15658
|
+
},
|
|
15659
|
+
{
|
|
15660
|
+
id: "claude-4-7",
|
|
15661
|
+
family: "anthropic",
|
|
15662
|
+
match: "^claude-(?:(?:opus|sonnet|haiku)-4[-.]7|4[-.]7-(?:opus|sonnet|haiku))(?!\\d)",
|
|
15663
|
+
reasoning: {
|
|
15664
|
+
style: "adaptive",
|
|
15665
|
+
efforts: [
|
|
15666
|
+
"low",
|
|
15667
|
+
"medium",
|
|
15668
|
+
"high",
|
|
15669
|
+
"xhigh",
|
|
15670
|
+
"max"
|
|
15671
|
+
],
|
|
15672
|
+
off: "disabled"
|
|
15673
|
+
},
|
|
15674
|
+
sampling: {
|
|
15675
|
+
temperature: "thinking-requires-1",
|
|
15676
|
+
topP: true,
|
|
15677
|
+
topK: true,
|
|
15678
|
+
penalties: true,
|
|
15679
|
+
logprobs: true
|
|
15680
|
+
},
|
|
15681
|
+
maxTokensParam: "max_tokens",
|
|
15682
|
+
chatTools: {
|
|
15683
|
+
reasoning: "any"
|
|
15684
|
+
},
|
|
15685
|
+
source: "docs",
|
|
15686
|
+
note: "Claude 4.7: adaptive thinking, low/medium/high/xhigh/max."
|
|
15687
|
+
},
|
|
15688
|
+
{
|
|
15689
|
+
id: "claude-4-6",
|
|
15690
|
+
family: "anthropic",
|
|
15691
|
+
match: "^claude-(?:(?:opus|sonnet|haiku)-4[-.]6|4[-.]6-(?:opus|sonnet|haiku))(?!\\d)",
|
|
15692
|
+
reasoning: {
|
|
15693
|
+
style: "adaptive",
|
|
15694
|
+
efforts: [
|
|
15695
|
+
"low",
|
|
15696
|
+
"medium",
|
|
15697
|
+
"high",
|
|
15698
|
+
"max"
|
|
15699
|
+
],
|
|
15700
|
+
off: "disabled"
|
|
15701
|
+
},
|
|
15702
|
+
sampling: {
|
|
15703
|
+
temperature: "thinking-requires-1",
|
|
15704
|
+
topP: true,
|
|
15705
|
+
topK: true,
|
|
15706
|
+
penalties: true,
|
|
15707
|
+
logprobs: true
|
|
15708
|
+
},
|
|
15709
|
+
maxTokensParam: "max_tokens",
|
|
15710
|
+
chatTools: {
|
|
15711
|
+
reasoning: "any"
|
|
15712
|
+
},
|
|
15713
|
+
source: "docs",
|
|
15714
|
+
note: "Claude 4.6: adaptive thinking, low/medium/high/max (no xhigh)."
|
|
15715
|
+
},
|
|
15716
|
+
{
|
|
15717
|
+
id: "claude-legacy-budget",
|
|
15718
|
+
family: "anthropic",
|
|
15719
|
+
match: "^claude-(?:3|4-|(?:opus|sonnet|haiku)-4)",
|
|
15720
|
+
reasoning: {
|
|
15721
|
+
style: "budget",
|
|
15722
|
+
efforts: [
|
|
15723
|
+
"none",
|
|
15724
|
+
"minimal",
|
|
15725
|
+
"low",
|
|
15726
|
+
"medium",
|
|
15727
|
+
"high",
|
|
15728
|
+
"xhigh",
|
|
15729
|
+
"max"
|
|
15730
|
+
],
|
|
15731
|
+
off: null
|
|
15732
|
+
},
|
|
15733
|
+
sampling: {
|
|
15734
|
+
temperature: "thinking-requires-1",
|
|
15735
|
+
topP: true,
|
|
15736
|
+
topK: true,
|
|
15737
|
+
penalties: true,
|
|
15738
|
+
logprobs: true
|
|
15739
|
+
},
|
|
15740
|
+
maxTokensParam: "max_tokens",
|
|
15741
|
+
chatTools: {
|
|
15742
|
+
reasoning: "any"
|
|
15743
|
+
},
|
|
15744
|
+
source: "docs",
|
|
15745
|
+
note: "Claude 3.7 and 4.0-4.5: thinking:{type:enabled,budget_tokens}; every effort maps to a budget; sampling overrides are not allowed while thinking."
|
|
15746
|
+
},
|
|
15747
|
+
{
|
|
15748
|
+
id: "anthropic-default",
|
|
15749
|
+
family: "anthropic",
|
|
15750
|
+
match: ".*",
|
|
15751
|
+
reasoning: {
|
|
15752
|
+
style: "budget",
|
|
15753
|
+
efforts: [
|
|
15754
|
+
"none",
|
|
15755
|
+
"minimal",
|
|
15756
|
+
"low",
|
|
15757
|
+
"medium",
|
|
15758
|
+
"high",
|
|
15759
|
+
"xhigh",
|
|
15760
|
+
"max"
|
|
15761
|
+
],
|
|
15762
|
+
off: null
|
|
15763
|
+
},
|
|
15764
|
+
sampling: {
|
|
15765
|
+
temperature: "thinking-requires-1",
|
|
15766
|
+
topP: true,
|
|
15767
|
+
topK: true,
|
|
15768
|
+
penalties: true,
|
|
15769
|
+
logprobs: true
|
|
15770
|
+
},
|
|
15771
|
+
maxTokensParam: "max_tokens",
|
|
15772
|
+
chatTools: {
|
|
15773
|
+
reasoning: "any"
|
|
15774
|
+
},
|
|
15775
|
+
source: "docs",
|
|
15776
|
+
note: "Permissive default for unknown Anthropic-wire models: budget style (the long-standing form); the provider flips the thinking form when the API says so."
|
|
15777
|
+
},
|
|
15778
|
+
{
|
|
15779
|
+
id: "gemini-budget",
|
|
15780
|
+
family: "gemini",
|
|
15781
|
+
match: "^gemini",
|
|
15782
|
+
reasoning: {
|
|
15783
|
+
style: "budget",
|
|
15784
|
+
efforts: [
|
|
15785
|
+
"none",
|
|
15786
|
+
"minimal",
|
|
15787
|
+
"low",
|
|
15788
|
+
"medium",
|
|
15789
|
+
"high",
|
|
15790
|
+
"xhigh",
|
|
15791
|
+
"max"
|
|
15792
|
+
],
|
|
15793
|
+
off: "none"
|
|
15794
|
+
},
|
|
15795
|
+
sampling: {
|
|
15796
|
+
temperature: "any",
|
|
15797
|
+
topP: true,
|
|
15798
|
+
topK: true,
|
|
15799
|
+
penalties: true,
|
|
15800
|
+
logprobs: true
|
|
15801
|
+
},
|
|
15802
|
+
maxTokensParam: "max_tokens",
|
|
15803
|
+
chatTools: {
|
|
15804
|
+
reasoning: "any"
|
|
15805
|
+
},
|
|
15806
|
+
source: "docs",
|
|
15807
|
+
note: "Gemini 2.5-style thinkingBudget; effort maps to a token budget, none = budget 0."
|
|
15808
|
+
},
|
|
15809
|
+
{
|
|
15810
|
+
id: "gemini-default",
|
|
15811
|
+
family: "gemini",
|
|
15812
|
+
match: ".*",
|
|
15813
|
+
reasoning: {
|
|
15814
|
+
style: "budget",
|
|
15815
|
+
efforts: [
|
|
15816
|
+
"none",
|
|
15817
|
+
"minimal",
|
|
15818
|
+
"low",
|
|
15819
|
+
"medium",
|
|
15820
|
+
"high",
|
|
15821
|
+
"xhigh",
|
|
15822
|
+
"max"
|
|
15823
|
+
],
|
|
15824
|
+
off: "none"
|
|
15825
|
+
},
|
|
15826
|
+
sampling: {
|
|
15827
|
+
temperature: "any",
|
|
15828
|
+
topP: true,
|
|
15829
|
+
topK: true,
|
|
15830
|
+
penalties: true,
|
|
15831
|
+
logprobs: true
|
|
15832
|
+
},
|
|
15833
|
+
maxTokensParam: "max_tokens",
|
|
15834
|
+
chatTools: {
|
|
15835
|
+
reasoning: "any"
|
|
15836
|
+
},
|
|
15837
|
+
source: "docs",
|
|
15838
|
+
note: "Permissive default for unknown Gemini-wire models."
|
|
15839
|
+
},
|
|
15840
|
+
{
|
|
15841
|
+
id: "other-default",
|
|
15842
|
+
family: "other",
|
|
15843
|
+
match: ".*",
|
|
15844
|
+
reasoning: {
|
|
15845
|
+
style: "effort",
|
|
15846
|
+
efforts: [
|
|
15847
|
+
"none",
|
|
15848
|
+
"minimal",
|
|
15849
|
+
"low",
|
|
15850
|
+
"medium",
|
|
15851
|
+
"high",
|
|
15852
|
+
"xhigh",
|
|
15853
|
+
"max"
|
|
15854
|
+
],
|
|
15855
|
+
off: "none"
|
|
15856
|
+
},
|
|
15857
|
+
sampling: {
|
|
15858
|
+
temperature: "any",
|
|
15859
|
+
topP: true,
|
|
15860
|
+
topK: true,
|
|
15861
|
+
penalties: true,
|
|
15862
|
+
logprobs: true
|
|
15863
|
+
},
|
|
15864
|
+
maxTokensParam: "max_tokens",
|
|
15865
|
+
chatTools: {
|
|
15866
|
+
reasoning: "any"
|
|
15867
|
+
},
|
|
15868
|
+
source: "docs",
|
|
15869
|
+
note: "Permissive default for model families the SDK has no rules for."
|
|
15199
15870
|
}
|
|
15200
|
-
|
|
15201
|
-
|
|
15202
|
-
|
|
15871
|
+
]
|
|
15872
|
+
};
|
|
15873
|
+
|
|
15874
|
+
// src/models/rules.ts
|
|
15875
|
+
var MODEL_RULES = model_rules_default;
|
|
15876
|
+
var LADDER = MODEL_RULES.effortLadder;
|
|
15877
|
+
var compiled = /* @__PURE__ */ new Map();
|
|
15878
|
+
function regexFor(rule) {
|
|
15879
|
+
let re = compiled.get(rule.id);
|
|
15880
|
+
if (!re) {
|
|
15881
|
+
re = new RegExp(rule.match, "i");
|
|
15882
|
+
compiled.set(rule.id, re);
|
|
15883
|
+
}
|
|
15884
|
+
return re;
|
|
15885
|
+
}
|
|
15886
|
+
var GATEWAY_PREFIX = /^(?:(?:global|us|eu|apac|jp|au|ca|us-gov)\.)?(?:(?:openai|anthropic|google|meta|amazon|deepseek|qwen|mistral|cohere|ai21)\.)?/;
|
|
15887
|
+
function modelIdCandidates(model) {
|
|
15888
|
+
if (!model) return [];
|
|
15889
|
+
const lower = String(model).trim().toLowerCase();
|
|
15890
|
+
const last = lower.split("/").pop() ?? lower;
|
|
15891
|
+
const out = [];
|
|
15892
|
+
for (const id of [lower, last]) {
|
|
15893
|
+
for (const c of [id, id.replace(GATEWAY_PREFIX, "")]) {
|
|
15894
|
+
if (c && !out.includes(c)) out.push(c);
|
|
15203
15895
|
}
|
|
15204
|
-
} finally {
|
|
15205
|
-
reader.cancel().catch(() => void 0);
|
|
15206
|
-
reader.releaseLock();
|
|
15207
15896
|
}
|
|
15897
|
+
return out;
|
|
15208
15898
|
}
|
|
15209
|
-
|
|
15210
|
-
|
|
15211
|
-
|
|
15212
|
-
|
|
15213
|
-
|
|
15214
|
-
|
|
15215
|
-
|
|
15216
|
-
|
|
15217
|
-
|
|
15218
|
-
|
|
15219
|
-
|
|
15220
|
-
|
|
15221
|
-
|
|
15222
|
-
|
|
15223
|
-
|
|
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
|
-
}
|
|
15899
|
+
var OPENAI_WIRE = /* @__PURE__ */ new Set(["openai", "azure", "openai-compatible", "together", "openrouter", "groq", "fireworks", "ollama", "vllm", "litellm", "mistral", "deepseek", "xai", "jev"]);
|
|
15900
|
+
function familiesFor(provider) {
|
|
15901
|
+
const p = (provider ?? "").toLowerCase();
|
|
15902
|
+
if (OPENAI_WIRE.has(p)) return ["openai"];
|
|
15903
|
+
if (p === "anthropic") return ["anthropic"];
|
|
15904
|
+
if (p === "bedrock") return ["anthropic", "openai", "other"];
|
|
15905
|
+
if (p === "vertex" || p === "gemini" || p === "google") return ["gemini", "anthropic"];
|
|
15906
|
+
return ["openai", "anthropic", "gemini", "other"];
|
|
15907
|
+
}
|
|
15908
|
+
function matchRule(family, ids, allowDefault) {
|
|
15909
|
+
for (const rule of MODEL_RULES.rules) {
|
|
15910
|
+
if (rule.family !== family) continue;
|
|
15911
|
+
if (rule.match === ".*") {
|
|
15912
|
+
if (allowDefault) return rule;
|
|
15913
|
+
continue;
|
|
15242
15914
|
}
|
|
15915
|
+
const re = regexFor(rule);
|
|
15916
|
+
if (ids.some((id) => re.test(id))) return rule;
|
|
15243
15917
|
}
|
|
15244
|
-
|
|
15245
|
-
return { event, data: dataLines.join("\n"), id, retry };
|
|
15918
|
+
return void 0;
|
|
15246
15919
|
}
|
|
15247
|
-
|
|
15248
|
-
|
|
15249
|
-
|
|
15250
|
-
|
|
15251
|
-
|
|
15920
|
+
function mergeRulePatch(base, patch) {
|
|
15921
|
+
if (!patch) return base;
|
|
15922
|
+
const out = { ...base };
|
|
15923
|
+
if (patch.reasoning) out.reasoning = { ...base.reasoning ?? {}, ...patch.reasoning };
|
|
15924
|
+
if (patch.sampling) out.sampling = { ...base.sampling ?? {}, ...patch.sampling };
|
|
15925
|
+
if (patch.chatTools) out.chatTools = { ...base.chatTools ?? {}, ...patch.chatTools };
|
|
15926
|
+
if (patch.maxTokensParam) out.maxTokensParam = patch.maxTokensParam;
|
|
15927
|
+
if (patch.dropParams) out.dropParams = [.../* @__PURE__ */ new Set([...base.dropParams ?? [], ...patch.dropParams])];
|
|
15928
|
+
return out;
|
|
15929
|
+
}
|
|
15930
|
+
var LEARNED_MAX = 500;
|
|
15931
|
+
var learned = /* @__PURE__ */ new Map();
|
|
15932
|
+
function learnedKey(provider, model, scope) {
|
|
15933
|
+
return `${(provider ?? "").toLowerCase()}@${scope ?? ""}::${(model ?? "").trim().toLowerCase()}`;
|
|
15934
|
+
}
|
|
15935
|
+
function rememberModelRulePatch(provider, model, patch, scope) {
|
|
15936
|
+
const key = learnedKey(provider, model, scope);
|
|
15937
|
+
const merged = mergeRulePatch(learned.get(key)?.patch ?? {}, patch);
|
|
15938
|
+
learned.delete(key);
|
|
15939
|
+
learned.set(key, { provider: provider.toLowerCase(), model: model.trim().toLowerCase(), scope, patch: merged });
|
|
15940
|
+
if (learned.size > LEARNED_MAX) learned.delete(learned.keys().next().value);
|
|
15941
|
+
}
|
|
15942
|
+
function getLearnedModelRulePatch(provider, model, scope) {
|
|
15943
|
+
return learned.get(learnedKey(provider, model, scope))?.patch;
|
|
15944
|
+
}
|
|
15945
|
+
function listLearnedModelRules() {
|
|
15946
|
+
return [...learned.values()].map((e) => ({ ...e }));
|
|
15947
|
+
}
|
|
15948
|
+
function clearLearnedModelRules() {
|
|
15949
|
+
learned.clear();
|
|
15950
|
+
}
|
|
15951
|
+
function resolveModelRule(opts) {
|
|
15952
|
+
const families = familiesFor(opts.provider);
|
|
15953
|
+
const ids = modelIdCandidates(opts.model);
|
|
15954
|
+
let rule;
|
|
15955
|
+
for (const family of families) {
|
|
15956
|
+
rule = matchRule(family, ids, false);
|
|
15957
|
+
if (rule) break;
|
|
15958
|
+
}
|
|
15959
|
+
let isDefault = false;
|
|
15960
|
+
if (!rule) {
|
|
15961
|
+
isDefault = true;
|
|
15962
|
+
rule = matchRule(families[0], ids, true) ?? MODEL_RULES.rules[MODEL_RULES.rules.length - 1];
|
|
15963
|
+
}
|
|
15964
|
+
let effective = rule;
|
|
15965
|
+
const known = opts.model ? learned.get(learnedKey(opts.provider, opts.model, opts.scope))?.patch : void 0;
|
|
15966
|
+
if (known) effective = mergeRulePatch(effective, known);
|
|
15967
|
+
if (opts.patch) effective = mergeRulePatch(effective, opts.patch);
|
|
15968
|
+
return { ...effective, matchedRuleId: rule.id, isDefault, learned: !!known };
|
|
15969
|
+
}
|
|
15970
|
+
function mapReasoningEffort(rule, effort, endpoint = "chat") {
|
|
15971
|
+
const efforts = endpoint === "responses" && rule.reasoning.responsesEfforts || rule.reasoning.efforts;
|
|
15972
|
+
if (rule.reasoning.style === "none" || efforts.length === 0) return { mapped: true };
|
|
15973
|
+
const supported = LADDER.filter((e) => efforts.includes(e));
|
|
15974
|
+
if (supported.includes(effort)) return { effort, mapped: false };
|
|
15975
|
+
if (effort === "none") {
|
|
15976
|
+
const off = rule.reasoning.off;
|
|
15977
|
+
if (off && off !== "none") return { off, mapped: true };
|
|
15978
|
+
const lowest = supported.find((e) => e !== "none");
|
|
15979
|
+
return lowest ? { effort: lowest, mapped: true } : { mapped: true };
|
|
15980
|
+
}
|
|
15981
|
+
const at = LADDER.indexOf(effort);
|
|
15982
|
+
if (at < 0) return { mapped: true };
|
|
15983
|
+
for (let i = at - 1; i >= 1; i--) if (supported.includes(LADDER[i])) return { effort: LADDER[i], mapped: true };
|
|
15984
|
+
for (let i = at + 1; i < LADDER.length; i++) if (supported.includes(LADDER[i])) return { effort: LADDER[i], mapped: true };
|
|
15985
|
+
return supported.includes("none") ? { effort: "none", mapped: true } : { mapped: true };
|
|
15986
|
+
}
|
|
15987
|
+
function allowsSampling(rule, field, value, thinkingOn = false) {
|
|
15988
|
+
const s = rule.sampling;
|
|
15989
|
+
switch (field) {
|
|
15990
|
+
case "temperature":
|
|
15991
|
+
switch (s.temperature) {
|
|
15992
|
+
case "any":
|
|
15993
|
+
return true;
|
|
15994
|
+
case "unsupported":
|
|
15995
|
+
return false;
|
|
15996
|
+
// The default is what the server applies anyway, so it is never sent.
|
|
15997
|
+
case "default-only":
|
|
15998
|
+
return false;
|
|
15999
|
+
case "thinking-requires-1":
|
|
16000
|
+
return !thinkingOn || value === 1;
|
|
16001
|
+
}
|
|
16002
|
+
return true;
|
|
16003
|
+
// Anthropic's thinking restriction covers top_p / top_k as well as temperature.
|
|
16004
|
+
case "topP":
|
|
16005
|
+
return s.topP && !(thinkingOn && s.temperature === "thinking-requires-1");
|
|
16006
|
+
case "topK":
|
|
16007
|
+
return s.topK && !(thinkingOn && s.temperature === "thinking-requires-1");
|
|
16008
|
+
case "presencePenalty":
|
|
16009
|
+
case "frequencyPenalty":
|
|
16010
|
+
return s.penalties;
|
|
16011
|
+
case "logprobs":
|
|
16012
|
+
return s.logprobs;
|
|
16013
|
+
}
|
|
16014
|
+
}
|
|
16015
|
+
function applyDropParams(body, rule) {
|
|
16016
|
+
for (const p of rule.dropParams ?? []) {
|
|
16017
|
+
const dot = p.indexOf(".");
|
|
16018
|
+
if (dot < 0) delete body[p];
|
|
16019
|
+
else if (body[p.slice(0, dot)] && typeof body[p.slice(0, dot)] === "object") delete body[p.slice(0, dot)][p.slice(dot + 1)];
|
|
16020
|
+
}
|
|
16021
|
+
}
|
|
16022
|
+
function effortBudget(effort, table = "anthropic") {
|
|
16023
|
+
if (effort === "none") return 0;
|
|
16024
|
+
return (table === "gemini" ? MODEL_RULES.geminiBudgets : MODEL_RULES.budgets)[effort] ?? 0;
|
|
16025
|
+
}
|
|
16026
|
+
|
|
16027
|
+
// src/providers/utils/reasoning.ts
|
|
16028
|
+
var ANTHROPIC_EFFORT_BUDGET = {
|
|
16029
|
+
// 0 = off. `applyAnthropicReasoning` bails on a falsy budget and emits no
|
|
16030
|
+
// thinking block, which on Anthropic IS off — thinking there is opt-in.
|
|
15252
16031
|
none: 0,
|
|
15253
|
-
|
|
15254
|
-
low: 2048,
|
|
15255
|
-
medium: 8192,
|
|
15256
|
-
high: 16384
|
|
16032
|
+
...MODEL_RULES.budgets
|
|
15257
16033
|
};
|
|
15258
16034
|
var GEMINI_EFFORT_BUDGET = {
|
|
15259
16035
|
// 0 is Gemini's own documented spelling for "do not think", and unlike
|
|
15260
16036
|
// Anthropic it has to be SENT — hence `applyGeminiReasoning` testing for null
|
|
15261
16037
|
// rather than falsiness.
|
|
15262
16038
|
none: 0,
|
|
15263
|
-
|
|
15264
|
-
low: 1024,
|
|
15265
|
-
medium: 4096,
|
|
15266
|
-
high: 12e3
|
|
16039
|
+
...MODEL_RULES.geminiBudgets
|
|
15267
16040
|
};
|
|
15268
16041
|
var THINKING_OUTPUT_RESERVE = 1024;
|
|
16042
|
+
var MIN_THINKING_BUDGET = 1024;
|
|
15269
16043
|
var THINKING_MIN_MAX_TOKENS = 4096;
|
|
15270
|
-
function applyOpenAIReasoning(body, reasoning, mode = "legacy_effort") {
|
|
16044
|
+
function applyOpenAIReasoning(body, reasoning, mode = "legacy_effort", model, rule) {
|
|
15271
16045
|
if (!reasoning) return;
|
|
15272
|
-
const
|
|
16046
|
+
const requested = normalizeEffort(reasoning.effort);
|
|
16047
|
+
const r = rule ?? resolveModelRule({ provider: "openai", model: model ?? body.model });
|
|
16048
|
+
const effort = requested && mapReasoningEffort(r, requested, mode === "responses" ? "responses" : "chat").effort;
|
|
15273
16049
|
if (mode === "responses") {
|
|
15274
16050
|
const obj = {};
|
|
15275
16051
|
if (effort) obj.effort = effort;
|
|
@@ -15281,52 +16057,107 @@ function applyOpenAIReasoning(body, reasoning, mode = "legacy_effort") {
|
|
|
15281
16057
|
if (reasoning.providerExtras) Object.assign(body, reasoning.providerExtras);
|
|
15282
16058
|
}
|
|
15283
16059
|
}
|
|
15284
|
-
function
|
|
15285
|
-
if (
|
|
15286
|
-
|
|
15287
|
-
|
|
16060
|
+
function supportsAdaptiveThinking(model) {
|
|
16061
|
+
if (typeof model !== "string") return false;
|
|
16062
|
+
return resolveModelRule({ provider: "anthropic", model }).reasoning.style === "adaptive";
|
|
16063
|
+
}
|
|
16064
|
+
function resolveThinkingForm(model, mode, rule) {
|
|
16065
|
+
if (mode === "adaptive" || mode === "budget") return mode;
|
|
16066
|
+
if (rule) return rule.reasoning.style === "adaptive" ? "adaptive" : "budget";
|
|
16067
|
+
return supportsAdaptiveThinking(model) ? "adaptive" : "budget";
|
|
16068
|
+
}
|
|
16069
|
+
function enforceAnthropicSampling(target, rule, thinkingOn, bedrock = false) {
|
|
16070
|
+
const fields = bedrock ? [["temperature", "temperature"], ["topP", "topP"]] : [["temperature", "temperature"], ["top_p", "topP"], ["top_k", "topK"]];
|
|
16071
|
+
for (const [key, field] of fields) {
|
|
16072
|
+
if (key in target && !allowsSampling(rule, field, target[key], thinkingOn)) delete target[key];
|
|
16073
|
+
}
|
|
16074
|
+
}
|
|
16075
|
+
function applyAdaptiveThinking(reasoning, rule, setThinking, setOutputConfig) {
|
|
16076
|
+
let requested = normalizeEffort(reasoning.effort);
|
|
16077
|
+
if (!requested && typeof reasoning.budgetTokens === "number" && reasoning.budgetTokens > 0) {
|
|
16078
|
+
requested = reasoning.budgetTokens <= ANTHROPIC_EFFORT_BUDGET.low ? "low" : reasoning.budgetTokens <= ANTHROPIC_EFFORT_BUDGET.medium ? "medium" : "high";
|
|
16079
|
+
}
|
|
16080
|
+
if (!requested) return false;
|
|
16081
|
+
const mapped = mapReasoningEffort(rule, requested);
|
|
16082
|
+
if (mapped.off) {
|
|
16083
|
+
setThinking({ type: mapped.off });
|
|
16084
|
+
return false;
|
|
16085
|
+
}
|
|
16086
|
+
if (!mapped.effort || mapped.effort === "none") return false;
|
|
16087
|
+
const thinking = { type: "adaptive" };
|
|
16088
|
+
if (reasoning.includeThoughts !== false) thinking.display = "summarized";
|
|
16089
|
+
if (reasoning.providerExtras) Object.assign(thinking, reasoning.providerExtras);
|
|
16090
|
+
setThinking(thinking);
|
|
16091
|
+
setOutputConfig({ effort: mapped.effort });
|
|
16092
|
+
return true;
|
|
16093
|
+
}
|
|
16094
|
+
function applyAnthropicReasoning(body, reasoning, opts) {
|
|
16095
|
+
const rule = opts?.rule ?? resolveModelRule({ provider: "anthropic", model: opts?.model ?? body.model });
|
|
16096
|
+
if (!reasoning) {
|
|
16097
|
+
enforceAnthropicSampling(body, rule, false);
|
|
16098
|
+
return;
|
|
16099
|
+
}
|
|
16100
|
+
if (resolveThinkingForm(opts?.model ?? body.model, opts?.mode, rule) === "adaptive") {
|
|
16101
|
+
const on = applyAdaptiveThinking(reasoning, rule, (t) => body.thinking = t, (o) => body.output_config = { ...body.output_config ?? {}, ...o });
|
|
16102
|
+
enforceAnthropicSampling(body, rule, on);
|
|
16103
|
+
return;
|
|
16104
|
+
}
|
|
16105
|
+
let budget = resolveBudget(reasoning, ANTHROPIC_EFFORT_BUDGET, rule);
|
|
16106
|
+
if (!budget) {
|
|
16107
|
+
enforceAnthropicSampling(body, rule, false);
|
|
16108
|
+
return;
|
|
16109
|
+
}
|
|
15288
16110
|
const currentMax = typeof body.max_tokens === "number" ? body.max_tokens : 0;
|
|
15289
16111
|
const requiredMax = Math.max(THINKING_MIN_MAX_TOKENS, budget + THINKING_OUTPUT_RESERVE);
|
|
15290
16112
|
if (currentMax < requiredMax) {
|
|
15291
16113
|
body.max_tokens = requiredMax;
|
|
15292
16114
|
}
|
|
15293
|
-
budget = clampBudget(budget, body.max_tokens);
|
|
16115
|
+
budget = Math.max(MIN_THINKING_BUDGET, clampBudget(budget, body.max_tokens));
|
|
15294
16116
|
const thinking = { type: "enabled", budget_tokens: budget };
|
|
15295
16117
|
if (reasoning.providerExtras) Object.assign(thinking, reasoning.providerExtras);
|
|
15296
16118
|
body.thinking = thinking;
|
|
15297
|
-
|
|
16119
|
+
enforceAnthropicSampling(body, rule, true);
|
|
15298
16120
|
}
|
|
15299
|
-
function applyBedrockReasoning(body, reasoning) {
|
|
15300
|
-
|
|
15301
|
-
|
|
15302
|
-
|
|
16121
|
+
function applyBedrockReasoning(body, reasoning, opts) {
|
|
16122
|
+
const rule = opts?.rule ?? resolveModelRule({ provider: "bedrock", model: opts?.model ?? body.modelId });
|
|
16123
|
+
if (!reasoning) {
|
|
16124
|
+
if (body.inferenceConfig) enforceAnthropicSampling(body.inferenceConfig, rule, false, true);
|
|
16125
|
+
return;
|
|
16126
|
+
}
|
|
16127
|
+
if (resolveThinkingForm(opts?.model ?? body.modelId, opts?.mode, rule) === "adaptive") {
|
|
16128
|
+
const fields = () => body.additionalModelRequestFields ?? (body.additionalModelRequestFields = {});
|
|
16129
|
+
const on = applyAdaptiveThinking(reasoning, rule, (t) => fields().thinking = t, (o) => fields().output_config = { ...fields().output_config ?? {}, ...o });
|
|
16130
|
+
if (body.inferenceConfig) enforceAnthropicSampling(body.inferenceConfig, rule, on, true);
|
|
16131
|
+
return;
|
|
16132
|
+
}
|
|
16133
|
+
let budget = resolveBudget(reasoning, ANTHROPIC_EFFORT_BUDGET, rule);
|
|
16134
|
+
if (!budget) {
|
|
16135
|
+
if (body.inferenceConfig) enforceAnthropicSampling(body.inferenceConfig, rule, false, true);
|
|
16136
|
+
return;
|
|
16137
|
+
}
|
|
15303
16138
|
const inference = body.inferenceConfig ?? (body.inferenceConfig = {});
|
|
15304
16139
|
const currentMax = typeof inference.maxTokens === "number" ? inference.maxTokens : 0;
|
|
15305
16140
|
const requiredMax = Math.max(THINKING_MIN_MAX_TOKENS, budget + THINKING_OUTPUT_RESERVE);
|
|
15306
16141
|
if (currentMax < requiredMax) {
|
|
15307
16142
|
inference.maxTokens = requiredMax;
|
|
15308
16143
|
}
|
|
15309
|
-
budget = clampBudget(budget, inference.maxTokens);
|
|
16144
|
+
budget = Math.max(MIN_THINKING_BUDGET, clampBudget(budget, inference.maxTokens));
|
|
15310
16145
|
const extra = body.additionalModelRequestFields ?? (body.additionalModelRequestFields = {});
|
|
15311
16146
|
const thinking = { type: "enabled", budget_tokens: budget };
|
|
15312
16147
|
if (reasoning.providerExtras) Object.assign(thinking, reasoning.providerExtras);
|
|
15313
16148
|
extra.thinking = thinking;
|
|
15314
|
-
|
|
16149
|
+
enforceAnthropicSampling(inference, rule, true, true);
|
|
15315
16150
|
}
|
|
15316
16151
|
function applyGeminiReasoning(generationConfig, reasoning) {
|
|
15317
16152
|
if (!reasoning) return;
|
|
15318
16153
|
const budget = resolveBudget(reasoning, GEMINI_EFFORT_BUDGET);
|
|
15319
|
-
|
|
15320
|
-
|
|
16154
|
+
const level = typeof reasoning.thinkingLevel === "string" && reasoning.thinkingLevel ? reasoning.thinkingLevel : void 0;
|
|
16155
|
+
if (budget == null && !level) return;
|
|
16156
|
+
const thinkingConfig = level && budget !== 0 ? { thinkingLevel: level } : { thinkingBudget: budget ?? 0 };
|
|
15321
16157
|
if (reasoning.includeThoughts) thinkingConfig.includeThoughts = true;
|
|
15322
16158
|
if (reasoning.providerExtras) Object.assign(thinkingConfig, reasoning.providerExtras);
|
|
15323
16159
|
generationConfig.thinkingConfig = thinkingConfig;
|
|
15324
16160
|
}
|
|
15325
|
-
function stripSamplingParams(target, keys) {
|
|
15326
|
-
for (const k of keys) {
|
|
15327
|
-
if (k in target) delete target[k];
|
|
15328
|
-
}
|
|
15329
|
-
}
|
|
15330
16161
|
function clampBudget(budget, maxTokens) {
|
|
15331
16162
|
if (typeof maxTokens !== "number" || maxTokens <= 0) return budget;
|
|
15332
16163
|
const ceiling = maxTokens - THINKING_OUTPUT_RESERVE;
|
|
@@ -15335,19 +16166,292 @@ function clampBudget(budget, maxTokens) {
|
|
|
15335
16166
|
}
|
|
15336
16167
|
function normalizeEffort(effort) {
|
|
15337
16168
|
if (!effort) return void 0;
|
|
15338
|
-
const allowed = ["none", "minimal", "low", "medium", "high"];
|
|
16169
|
+
const allowed = ["none", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
15339
16170
|
return allowed.includes(effort) ? effort : void 0;
|
|
15340
16171
|
}
|
|
15341
|
-
function resolveBudget(reasoning,
|
|
16172
|
+
function resolveBudget(reasoning, effortBudget2, rule) {
|
|
15342
16173
|
const effort = normalizeEffort(reasoning.effort);
|
|
15343
16174
|
if (effort === "none") return 0;
|
|
15344
16175
|
if (typeof reasoning.budgetTokens === "number" && reasoning.budgetTokens > 0) {
|
|
15345
16176
|
return Math.floor(reasoning.budgetTokens);
|
|
15346
16177
|
}
|
|
15347
|
-
|
|
16178
|
+
const mapped = effort && rule ? mapReasoningEffort(rule, effort).effort : effort;
|
|
16179
|
+
if (mapped && effortBudget2[mapped]) return effortBudget2[mapped];
|
|
15348
16180
|
return void 0;
|
|
15349
16181
|
}
|
|
15350
16182
|
|
|
16183
|
+
// src/providers/utils/sse.ts
|
|
16184
|
+
async function* parseSSEStream(body, signal) {
|
|
16185
|
+
const reader = body.getReader();
|
|
16186
|
+
const decoder = new TextDecoder();
|
|
16187
|
+
let buffer = "";
|
|
16188
|
+
try {
|
|
16189
|
+
while (true) {
|
|
16190
|
+
if (signal?.aborted) throw abortReason(signal);
|
|
16191
|
+
const { done, value } = await reader.read();
|
|
16192
|
+
if (done) break;
|
|
16193
|
+
buffer += decoder.decode(value, { stream: true });
|
|
16194
|
+
const parts = buffer.split(/\r?\n\r?\n/);
|
|
16195
|
+
buffer = parts.pop() ?? "";
|
|
16196
|
+
for (const part of parts) {
|
|
16197
|
+
if (!part.trim()) continue;
|
|
16198
|
+
const event = parseSSEBlock(part);
|
|
16199
|
+
if (event) yield event;
|
|
16200
|
+
}
|
|
16201
|
+
}
|
|
16202
|
+
if (buffer.trim()) {
|
|
16203
|
+
const event = parseSSEBlock(buffer);
|
|
16204
|
+
if (event) yield event;
|
|
16205
|
+
}
|
|
16206
|
+
} finally {
|
|
16207
|
+
reader.cancel().catch(() => void 0);
|
|
16208
|
+
reader.releaseLock();
|
|
16209
|
+
}
|
|
16210
|
+
}
|
|
16211
|
+
function parseSSEBlock(block) {
|
|
16212
|
+
let event;
|
|
16213
|
+
let id;
|
|
16214
|
+
let retry;
|
|
16215
|
+
const dataLines = [];
|
|
16216
|
+
for (const line of block.split(/\r?\n/)) {
|
|
16217
|
+
if (line.startsWith(":")) continue;
|
|
16218
|
+
const colonIdx = line.indexOf(":");
|
|
16219
|
+
let field;
|
|
16220
|
+
let value;
|
|
16221
|
+
if (colonIdx === -1) {
|
|
16222
|
+
field = line;
|
|
16223
|
+
value = "";
|
|
16224
|
+
} else {
|
|
16225
|
+
field = line.slice(0, colonIdx);
|
|
16226
|
+
value = line.slice(colonIdx + 1);
|
|
16227
|
+
if (value.startsWith(" ")) value = value.slice(1);
|
|
16228
|
+
}
|
|
16229
|
+
switch (field) {
|
|
16230
|
+
case "event":
|
|
16231
|
+
event = value;
|
|
16232
|
+
break;
|
|
16233
|
+
case "data":
|
|
16234
|
+
dataLines.push(value);
|
|
16235
|
+
break;
|
|
16236
|
+
case "id":
|
|
16237
|
+
id = value;
|
|
16238
|
+
break;
|
|
16239
|
+
case "retry": {
|
|
16240
|
+
const n = parseInt(value, 10);
|
|
16241
|
+
if (!isNaN(n)) retry = n;
|
|
16242
|
+
break;
|
|
16243
|
+
}
|
|
16244
|
+
}
|
|
16245
|
+
}
|
|
16246
|
+
if (dataLines.length === 0) return null;
|
|
16247
|
+
return { event, data: dataLines.join("\n"), id, retry };
|
|
16248
|
+
}
|
|
16249
|
+
|
|
16250
|
+
// src/models/errors.ts
|
|
16251
|
+
var ModelRequestError = class extends ProviderError {
|
|
16252
|
+
constructor(init) {
|
|
16253
|
+
super(init.message, init.provider, init.status ?? 400, init.responseBody);
|
|
16254
|
+
this.status = init.status ?? 400;
|
|
16255
|
+
this.code = init.code;
|
|
16256
|
+
this.param = init.param;
|
|
16257
|
+
this.value = init.value;
|
|
16258
|
+
this.supportedValues = init.supportedValues;
|
|
16259
|
+
this.model = init.model;
|
|
16260
|
+
}
|
|
16261
|
+
};
|
|
16262
|
+
|
|
16263
|
+
// src/models/adjust.ts
|
|
16264
|
+
var MAX_ADJUSTMENTS = 3;
|
|
16265
|
+
var Q = "['\"`]";
|
|
16266
|
+
function errorMessage(text) {
|
|
16267
|
+
try {
|
|
16268
|
+
const j = JSON.parse(text);
|
|
16269
|
+
const e = j?.error ?? j;
|
|
16270
|
+
const message = typeof e?.message === "string" ? e.message : typeof j?.message === "string" ? j.message : text;
|
|
16271
|
+
return { message, param: typeof e?.param === "string" ? e.param : void 0, code: typeof e?.code === "string" ? e.code : void 0 };
|
|
16272
|
+
} catch {
|
|
16273
|
+
return { message: text };
|
|
16274
|
+
}
|
|
16275
|
+
}
|
|
16276
|
+
function quotedList(s) {
|
|
16277
|
+
const quoted = [...s.matchAll(new RegExp(`${Q}([^'"\`]+)${Q}`, "g"))].map((m) => m[1]);
|
|
16278
|
+
if (quoted.length > 0) return quoted;
|
|
16279
|
+
return s.split(/[,\s]+/).map((x) => x.replace(/[.\s]+$/, "")).filter(Boolean);
|
|
16280
|
+
}
|
|
16281
|
+
function parseModelError(text) {
|
|
16282
|
+
const { message, param: errParam } = errorMessage(String(text ?? ""));
|
|
16283
|
+
const m = message.toLowerCase();
|
|
16284
|
+
if (m.includes("function tools with reasoning_effort") && m.includes("not supported")) {
|
|
16285
|
+
return { kind: "chat_tools_effort", message };
|
|
16286
|
+
}
|
|
16287
|
+
if (m.includes("between_tools") && m.includes("thinking")) return { kind: "thinking_off_between_tools", message };
|
|
16288
|
+
if (m.includes("thinking.type.enabled") && m.includes("not supported")) return { kind: "thinking_enabled_unsupported", message };
|
|
16289
|
+
if (m.includes("thinking.type.adaptive") && m.includes("not supported")) return { kind: "thinking_adaptive_unsupported", message };
|
|
16290
|
+
if (m.includes("thinking.type.disabled") && m.includes("not supported")) return { kind: "thinking_disabled_unsupported", message };
|
|
16291
|
+
const tt = new RegExp(`${Q}?(temperature|top_p|top_k)${Q}?\\s+may only be set to 1 when thinking is enabled`, "i").exec(message);
|
|
16292
|
+
if (tt) return { kind: "temperature_thinking", param: tt[1].toLowerCase(), message };
|
|
16293
|
+
const dep = new RegExp(`${Q}([\\w.]+)${Q}\\s+is deprecated for this model`, "i").exec(message);
|
|
16294
|
+
if (dep) return { kind: "unsupported_parameter", param: dep[1], message };
|
|
16295
|
+
const rename = new RegExp(`use ${Q}(max_completion_tokens|max_tokens)${Q} instead`, "i").exec(message);
|
|
16296
|
+
if (rename) return { kind: "max_tokens_rename", renameTo: rename[1].toLowerCase(), param: rename[1].toLowerCase() === "max_tokens" ? "max_completion_tokens" : "max_tokens", message };
|
|
16297
|
+
const val = new RegExp(`unsupported value:?\\s*${Q}?([\\w.]+)${Q}?\\s+does not support\\s+(${Q}[^'"\`]*${Q}|[^\\s]+)`, "i").exec(message);
|
|
16298
|
+
if (val) {
|
|
16299
|
+
const param = val[1];
|
|
16300
|
+
const value = val[2].replace(/^['"`]|['"`]$/g, "");
|
|
16301
|
+
if (m.includes("only the default") && m.includes("value is supported")) return { kind: "default_only", param, value, message };
|
|
16302
|
+
const sup = /supported values? (?:are|is):?\s*([^\n]*)/i.exec(message);
|
|
16303
|
+
return { kind: "unsupported_value", param, value, supportedValues: sup ? quotedList(sup[1]) : void 0, message };
|
|
16304
|
+
}
|
|
16305
|
+
if (m.includes("only the default") && m.includes("value is supported")) {
|
|
16306
|
+
return { kind: "default_only", param: errParam ?? "temperature", message };
|
|
16307
|
+
}
|
|
16308
|
+
const prm = new RegExp(`unsupported parameter:?\\s*${Q}?([\\w.]+)${Q}?`, "i").exec(message);
|
|
16309
|
+
if (prm) return { kind: "unsupported_parameter", param: prm[1], message };
|
|
16310
|
+
return void 0;
|
|
16311
|
+
}
|
|
16312
|
+
var normParam = (p) => p.toLowerCase().replace(/[-\s]/g, "_");
|
|
16313
|
+
var LADDER2 = new Set(MODEL_RULES.effortLadder);
|
|
16314
|
+
function patchFromParsedError(parsed, endpoint = "chat") {
|
|
16315
|
+
const param = parsed.param ? normParam(parsed.param) : "";
|
|
16316
|
+
switch (parsed.kind) {
|
|
16317
|
+
case "chat_tools_effort":
|
|
16318
|
+
return { patch: { chatTools: { reasoning: "force-none" } }, adjustment: "chat-tools:force-effort-none" };
|
|
16319
|
+
case "max_tokens_rename":
|
|
16320
|
+
return { patch: { maxTokensParam: parsed.renameTo }, adjustment: `${parsed.param}->${parsed.renameTo}` };
|
|
16321
|
+
case "thinking_enabled_unsupported":
|
|
16322
|
+
return { patch: { reasoning: { style: "adaptive" } }, adjustment: "thinking:adaptive" };
|
|
16323
|
+
case "thinking_adaptive_unsupported":
|
|
16324
|
+
return { patch: { reasoning: { style: "budget" } }, adjustment: "thinking:budget" };
|
|
16325
|
+
case "thinking_off_between_tools":
|
|
16326
|
+
return { patch: { reasoning: { off: "between_tools" } }, adjustment: "thinking-off:between_tools" };
|
|
16327
|
+
case "thinking_disabled_unsupported":
|
|
16328
|
+
return { patch: { reasoning: { off: null } }, adjustment: "thinking-off:none" };
|
|
16329
|
+
case "temperature_thinking":
|
|
16330
|
+
return { patch: { sampling: { temperature: "unsupported" } }, adjustment: "drop:temperature" };
|
|
16331
|
+
case "default_only":
|
|
16332
|
+
if (param === "temperature") return { patch: { sampling: { temperature: "default-only" } }, adjustment: "temperature:default-only" };
|
|
16333
|
+
return { patch: { dropParams: [parsed.param ?? param] }, adjustment: `drop:${parsed.param ?? param}` };
|
|
16334
|
+
case "unsupported_value": {
|
|
16335
|
+
if (/^(reasoning_effort|reasoning\.effort|effort|output_config\.effort)$/.test(param)) {
|
|
16336
|
+
const list = (parsed.supportedValues ?? []).map((v) => v.toLowerCase()).filter((v) => LADDER2.has(v));
|
|
16337
|
+
if (list.length === 0) return void 0;
|
|
16338
|
+
const reasoning = endpoint === "responses" ? { responsesEfforts: list } : { efforts: list };
|
|
16339
|
+
return { patch: { reasoning }, adjustment: `efforts:${list.join("|")}` };
|
|
16340
|
+
}
|
|
16341
|
+
return paramDropPatch(param, parsed);
|
|
16342
|
+
}
|
|
16343
|
+
case "unsupported_parameter":
|
|
16344
|
+
return paramDropPatch(param, parsed);
|
|
16345
|
+
}
|
|
16346
|
+
}
|
|
16347
|
+
function paramDropPatch(param, parsed) {
|
|
16348
|
+
if (!param) return void 0;
|
|
16349
|
+
const label = `drop:${parsed.param ?? param}`;
|
|
16350
|
+
switch (param) {
|
|
16351
|
+
case "temperature":
|
|
16352
|
+
return { patch: { sampling: { temperature: "unsupported" } }, adjustment: label };
|
|
16353
|
+
case "top_p":
|
|
16354
|
+
return { patch: { sampling: { topP: false } }, adjustment: label };
|
|
16355
|
+
case "top_k":
|
|
16356
|
+
return { patch: { sampling: { topK: false } }, adjustment: label };
|
|
16357
|
+
case "presence_penalty":
|
|
16358
|
+
case "frequency_penalty":
|
|
16359
|
+
return { patch: { sampling: { penalties: false } }, adjustment: label };
|
|
16360
|
+
case "logprobs":
|
|
16361
|
+
case "top_logprobs":
|
|
16362
|
+
return { patch: { sampling: { logprobs: false } }, adjustment: label };
|
|
16363
|
+
case "max_tokens":
|
|
16364
|
+
return { patch: { maxTokensParam: "max_completion_tokens" }, adjustment: "max_tokens->max_completion_tokens" };
|
|
16365
|
+
case "max_completion_tokens":
|
|
16366
|
+
return { patch: { maxTokensParam: "max_tokens" }, adjustment: "max_completion_tokens->max_tokens" };
|
|
16367
|
+
case "reasoning_effort":
|
|
16368
|
+
case "reasoning.effort":
|
|
16369
|
+
case "reasoning":
|
|
16370
|
+
return { patch: { reasoning: { style: "none", efforts: [], responsesEfforts: [] }, dropParams: [param] }, adjustment: label };
|
|
16371
|
+
default:
|
|
16372
|
+
return { patch: { dropParams: [parsed.param ?? param] }, adjustment: label };
|
|
16373
|
+
}
|
|
16374
|
+
}
|
|
16375
|
+
function codeFor(parsed) {
|
|
16376
|
+
if (!parsed) return "model_request_invalid";
|
|
16377
|
+
if (parsed.kind === "unsupported_value" || parsed.kind === "default_only") return "unsupported_value";
|
|
16378
|
+
if (parsed.kind === "unsupported_parameter" || parsed.kind === "max_tokens_rename" || parsed.kind === "temperature_thinking") return "unsupported_parameter";
|
|
16379
|
+
return "model_request_invalid";
|
|
16380
|
+
}
|
|
16381
|
+
function toModelRequestError(err, parsed, provider, model) {
|
|
16382
|
+
return new ModelRequestError({
|
|
16383
|
+
status: err.statusCode ?? 400,
|
|
16384
|
+
code: codeFor(parsed),
|
|
16385
|
+
param: parsed?.param,
|
|
16386
|
+
value: parsed?.value,
|
|
16387
|
+
supportedValues: parsed?.supportedValues,
|
|
16388
|
+
provider: err.provider || provider,
|
|
16389
|
+
model,
|
|
16390
|
+
message: err.message,
|
|
16391
|
+
responseBody: err.responseBody
|
|
16392
|
+
});
|
|
16393
|
+
}
|
|
16394
|
+
var SameRequest = class extends Error {
|
|
16395
|
+
};
|
|
16396
|
+
function withoutCallerParams(step, callerParams) {
|
|
16397
|
+
const drops = step.patch.dropParams;
|
|
16398
|
+
if (!callerParams?.length || !drops) return step;
|
|
16399
|
+
const mine = (p) => callerParams.includes(p.split(".")[0]);
|
|
16400
|
+
if (!drops.some(mine)) return step;
|
|
16401
|
+
const { dropParams: _ignored, ...rest } = step.patch;
|
|
16402
|
+
const kept = drops.filter((p) => !mine(p));
|
|
16403
|
+
const patch = kept.length ? { ...rest, dropParams: kept } : rest;
|
|
16404
|
+
return Object.keys(patch).length ? { ...step, patch } : void 0;
|
|
16405
|
+
}
|
|
16406
|
+
async function runWithModelAdjustments(opts) {
|
|
16407
|
+
let overlay = {};
|
|
16408
|
+
const steps = [];
|
|
16409
|
+
let previous;
|
|
16410
|
+
let lastError;
|
|
16411
|
+
let lastParsed;
|
|
16412
|
+
for (; ; ) {
|
|
16413
|
+
const guard = (body) => {
|
|
16414
|
+
let json;
|
|
16415
|
+
try {
|
|
16416
|
+
json = JSON.stringify(body);
|
|
16417
|
+
} catch {
|
|
16418
|
+
return;
|
|
16419
|
+
}
|
|
16420
|
+
if (previous !== void 0 && json === previous) throw new SameRequest();
|
|
16421
|
+
previous = json;
|
|
16422
|
+
};
|
|
16423
|
+
try {
|
|
16424
|
+
const result = await opts.run(overlay, guard);
|
|
16425
|
+
for (const step of steps) {
|
|
16426
|
+
const s = withoutCallerParams(step, opts.callerParams);
|
|
16427
|
+
if (!s) continue;
|
|
16428
|
+
rememberModelRulePatch(opts.provider, opts.model, s.patch, opts.scope);
|
|
16429
|
+
if (opts.onLearned) {
|
|
16430
|
+
try {
|
|
16431
|
+
opts.onLearned({ provider: opts.provider, model: opts.model, adjustment: s.adjustment, patch: s.patch, reason: s.reason });
|
|
16432
|
+
} catch {
|
|
16433
|
+
}
|
|
16434
|
+
}
|
|
16435
|
+
}
|
|
16436
|
+
return result;
|
|
16437
|
+
} catch (err) {
|
|
16438
|
+
if (err instanceof SameRequest) throw toModelRequestError(lastError, lastParsed, opts.provider, opts.model);
|
|
16439
|
+
if (!(err instanceof ProviderError) || err instanceof ModelRequestError || err.statusCode !== 400) throw err;
|
|
16440
|
+
const parsed = parseModelError(String(err.responseBody ?? err.message));
|
|
16441
|
+
const fix = parsed ? patchFromParsedError(parsed, opts.endpoint) : void 0;
|
|
16442
|
+
lastError = err;
|
|
16443
|
+
lastParsed = parsed;
|
|
16444
|
+
if (!fix || steps.length >= MAX_ADJUSTMENTS) throw toModelRequestError(err, parsed, opts.provider, opts.model);
|
|
16445
|
+
overlay = mergeRulePatch(overlay, fix.patch);
|
|
16446
|
+
steps.push({ ...fix, reason: parsed.message });
|
|
16447
|
+
}
|
|
16448
|
+
}
|
|
16449
|
+
}
|
|
16450
|
+
function asModelRequestError(err, provider, model) {
|
|
16451
|
+
if (!(err instanceof ProviderError) || err instanceof ModelRequestError || err.statusCode !== 400) return err;
|
|
16452
|
+
return toModelRequestError(err, parseModelError(String(err.responseBody ?? err.message)), provider, model);
|
|
16453
|
+
}
|
|
16454
|
+
|
|
15351
16455
|
// src/providers/utils/media.ts
|
|
15352
16456
|
var EXTENSION_MIME = {
|
|
15353
16457
|
jpg: "image/jpeg",
|
|
@@ -15539,11 +16643,64 @@ function isObject2(value) {
|
|
|
15539
16643
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15540
16644
|
}
|
|
15541
16645
|
|
|
16646
|
+
// src/providers/utils/embeddings.ts
|
|
16647
|
+
function chunkArray(items, size) {
|
|
16648
|
+
const n = Math.max(1, Math.floor(size));
|
|
16649
|
+
const out = [];
|
|
16650
|
+
for (let i = 0; i < items.length; i += n) out.push(items.slice(i, i + n));
|
|
16651
|
+
return out;
|
|
16652
|
+
}
|
|
16653
|
+
async function mapWithConcurrency(items, limit, fn, signal) {
|
|
16654
|
+
const results = new Array(items.length);
|
|
16655
|
+
let next = 0;
|
|
16656
|
+
let failure;
|
|
16657
|
+
let failed = false;
|
|
16658
|
+
const worker = async () => {
|
|
16659
|
+
while (!failed) {
|
|
16660
|
+
if (signal?.aborted) throw signal.reason ?? new Error("aborted");
|
|
16661
|
+
const i = next++;
|
|
16662
|
+
if (i >= items.length) return;
|
|
16663
|
+
try {
|
|
16664
|
+
results[i] = await fn(items[i], i);
|
|
16665
|
+
} catch (err) {
|
|
16666
|
+
failed = true;
|
|
16667
|
+
failure = err;
|
|
16668
|
+
return;
|
|
16669
|
+
}
|
|
16670
|
+
}
|
|
16671
|
+
};
|
|
16672
|
+
await Promise.all(Array.from({ length: Math.min(Math.max(1, limit), items.length) }, worker));
|
|
16673
|
+
if (failed) throw failure;
|
|
16674
|
+
return results;
|
|
16675
|
+
}
|
|
16676
|
+
function decodeBase64Vector(b64) {
|
|
16677
|
+
const buf = Buffer.from(b64, "base64");
|
|
16678
|
+
const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
16679
|
+
const out = new Array(Math.floor(buf.byteLength / 4));
|
|
16680
|
+
for (let i = 0; i < out.length; i++) out[i] = view.getFloat32(i * 4, true);
|
|
16681
|
+
return out;
|
|
16682
|
+
}
|
|
16683
|
+
function assertVectorCount(provider, vectors, expected) {
|
|
16684
|
+
if (vectors.length !== expected) {
|
|
16685
|
+
throw new ProviderError(
|
|
16686
|
+
`${provider} embeddings returned ${vectors.length} vectors for ${expected} inputs`,
|
|
16687
|
+
provider,
|
|
16688
|
+
502
|
|
16689
|
+
);
|
|
16690
|
+
}
|
|
16691
|
+
}
|
|
16692
|
+
function requireEmbeddingModel(provider, model) {
|
|
16693
|
+
if (!model) throw new ProviderError(`${provider} embeddings require a model`, provider, 400);
|
|
16694
|
+
return model;
|
|
16695
|
+
}
|
|
16696
|
+
|
|
15542
16697
|
// src/providers/openai.ts
|
|
15543
|
-
var OpenAIProvider = class
|
|
16698
|
+
var OpenAIProvider = class extends BaseProvider {
|
|
15544
16699
|
constructor(config) {
|
|
15545
16700
|
super();
|
|
15546
16701
|
this.providerName = "openai";
|
|
16702
|
+
this.configureTransport(config);
|
|
16703
|
+
this.maxTokensParam = config.maxTokensParam ?? "auto";
|
|
15547
16704
|
this.apiKey = config.apiKey;
|
|
15548
16705
|
this.baseURL = (config.baseURL ?? "https://api.openai.com/v1").replace(/\/$/, "");
|
|
15549
16706
|
this.defaultModel = config.defaultModel ?? "gpt-4o";
|
|
@@ -15551,10 +16708,14 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15551
16708
|
...config.defaultHeaders,
|
|
15552
16709
|
...config.organization ? { "OpenAI-Organization": config.organization } : {}
|
|
15553
16710
|
};
|
|
15554
|
-
|
|
15555
|
-
const
|
|
15556
|
-
this.
|
|
15557
|
-
this.
|
|
16711
|
+
const legacy = config.responsesApi;
|
|
16712
|
+
const explicit = config.api === "chat" || config.api === "responses" ? config.api : void 0;
|
|
16713
|
+
this.responsesApi = explicit === "responses" ? "always" : explicit === "chat" ? "never" : legacy ?? (config._autoMeansChat ? "never" : "auto");
|
|
16714
|
+
this.apiExplicitChat = explicit === "chat" || explicit === void 0 && legacy === "never";
|
|
16715
|
+
this.apiExplicitResponses = this.responsesApi === "always";
|
|
16716
|
+
this.apiResponsesNative = explicit === "responses";
|
|
16717
|
+
this.responsesApiModels = [...config.responsesApiModels ?? []];
|
|
16718
|
+
this.responsesStreaming = config.responsesStreaming ?? this.apiResponsesNative;
|
|
15558
16719
|
if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
|
|
15559
16720
|
}
|
|
15560
16721
|
/** True when the caller listed this request's model in `responsesApiModels`. */
|
|
@@ -15580,9 +16741,10 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15580
16741
|
* A model listed in `responsesApiModels` is the caller stating the answer
|
|
15581
16742
|
* for that model alone; `never` still overrides it. */
|
|
15582
16743
|
useResponsesApi(request) {
|
|
15583
|
-
if (this.
|
|
15584
|
-
if (this.
|
|
16744
|
+
if (this.apiExplicitChat) return false;
|
|
16745
|
+
if (this.apiExplicitResponses) return true;
|
|
15585
16746
|
if (this.isResponsesApiModel(request)) return true;
|
|
16747
|
+
if (this.responsesApi !== "auto") return false;
|
|
15586
16748
|
if (!request.reasoning) return false;
|
|
15587
16749
|
return isReasoningModel(request.model || this.defaultModel);
|
|
15588
16750
|
}
|
|
@@ -15590,14 +16752,13 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15590
16752
|
if (this.useResponsesApi(request)) {
|
|
15591
16753
|
return this.completeResponses(request);
|
|
15592
16754
|
}
|
|
15593
|
-
const
|
|
15594
|
-
const res = await this.doFetch(body, request.signal);
|
|
16755
|
+
const res = await this.fetchChat(request, false);
|
|
15595
16756
|
const json = await res.json();
|
|
15596
16757
|
return this.parseResponse(json);
|
|
15597
16758
|
}
|
|
15598
16759
|
async *completeStream(request) {
|
|
15599
16760
|
if (this.useResponsesApi(request)) {
|
|
15600
|
-
if (this.responsesStreaming && this.isResponsesApiModel(request)) {
|
|
16761
|
+
if (this.responsesStreaming && (this.apiResponsesNative || this.isResponsesApiModel(request))) {
|
|
15601
16762
|
yield* this.streamResponses(request);
|
|
15602
16763
|
return;
|
|
15603
16764
|
}
|
|
@@ -15615,8 +16776,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15615
16776
|
};
|
|
15616
16777
|
return;
|
|
15617
16778
|
}
|
|
15618
|
-
const
|
|
15619
|
-
const res = await this.doFetch(body, request.signal);
|
|
16779
|
+
const res = await this.fetchChat(request, true);
|
|
15620
16780
|
if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
|
|
15621
16781
|
let id = "";
|
|
15622
16782
|
let model = "";
|
|
@@ -15647,9 +16807,14 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15647
16807
|
delta: {},
|
|
15648
16808
|
finishReason: mapFinishReason(choice.finish_reason)
|
|
15649
16809
|
};
|
|
16810
|
+
if (typeof choice.finish_reason === "string") out.rawFinishReason = choice.finish_reason;
|
|
16811
|
+
const fields = pickProviderFields(chunk, delta, choice);
|
|
16812
|
+
if (fields) out.providerFields = fields;
|
|
15650
16813
|
if (delta.content) {
|
|
15651
16814
|
out.delta.content = delta.content;
|
|
15652
16815
|
}
|
|
16816
|
+
const reasoningDelta = extractReasoningText(delta);
|
|
16817
|
+
if (reasoningDelta) out.delta.reasoning = { summary: reasoningDelta };
|
|
15653
16818
|
if (delta.tool_calls) {
|
|
15654
16819
|
const partials = [];
|
|
15655
16820
|
for (const tc of delta.tool_calls) {
|
|
@@ -15661,7 +16826,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15661
16826
|
if (tc.id) buf.id = tc.id;
|
|
15662
16827
|
if (tc.function?.name) buf.name = tc.function.name;
|
|
15663
16828
|
if (tc.function?.arguments) buf.arguments += tc.function.arguments;
|
|
15664
|
-
partials.push({ id: buf.id, name: buf.name || void 0, arguments: tc.function?.arguments });
|
|
16829
|
+
partials.push({ id: buf.id, name: buf.name || void 0, arguments: tc.function?.arguments, index: idx });
|
|
15665
16830
|
}
|
|
15666
16831
|
out.delta.toolCalls = partials;
|
|
15667
16832
|
}
|
|
@@ -15669,22 +16834,115 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15669
16834
|
yield out;
|
|
15670
16835
|
}
|
|
15671
16836
|
}
|
|
16837
|
+
// ─── Embeddings ──────────────────────────────────────────────────────────
|
|
16838
|
+
/** POST /embeddings, batched (default 2048 inputs per request, the OpenAI cap). */
|
|
16839
|
+
async embed(request) {
|
|
16840
|
+
const model = requireEmbeddingModel(this.providerName, request.model);
|
|
16841
|
+
const batches = chunkArray(request.input, request.batchSize ?? 2048);
|
|
16842
|
+
const vectors = [];
|
|
16843
|
+
const raw = [];
|
|
16844
|
+
let inputTokens = 0;
|
|
16845
|
+
let totalTokens = 0;
|
|
16846
|
+
let responseModel = model;
|
|
16847
|
+
for (const batch of batches) {
|
|
16848
|
+
const body = { model, input: batch };
|
|
16849
|
+
if (request.dimensions != null) body.dimensions = request.dimensions;
|
|
16850
|
+
if (request.encodingFormat) body.encoding_format = request.encodingFormat;
|
|
16851
|
+
if (request.extra) Object.assign(body, request.extra);
|
|
16852
|
+
const res = await this.embeddingsFetch(body, request.signal);
|
|
16853
|
+
const json = await res.json();
|
|
16854
|
+
raw.push(json);
|
|
16855
|
+
const data = Array.isArray(json.data) ? [...json.data] : [];
|
|
16856
|
+
data.sort((a, b) => (a.index ?? 0) - (b.index ?? 0));
|
|
16857
|
+
for (const d of data) {
|
|
16858
|
+
vectors.push(typeof d.embedding === "string" ? decodeBase64Vector(d.embedding) : d.embedding);
|
|
16859
|
+
}
|
|
16860
|
+
inputTokens += json.usage?.prompt_tokens ?? 0;
|
|
16861
|
+
totalTokens += json.usage?.total_tokens ?? json.usage?.prompt_tokens ?? 0;
|
|
16862
|
+
responseModel = json.model ?? responseModel;
|
|
16863
|
+
}
|
|
16864
|
+
assertVectorCount(this.providerName, vectors, request.input.length);
|
|
16865
|
+
return { model: responseModel, vectors, usage: { inputTokens, totalTokens }, raw };
|
|
16866
|
+
}
|
|
16867
|
+
async embeddingsFetch(body, signal) {
|
|
16868
|
+
const url = `${this.baseURL}/embeddings`;
|
|
16869
|
+
const headers = {
|
|
16870
|
+
"Content-Type": "application/json",
|
|
16871
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
16872
|
+
...this.defaultHeaders
|
|
16873
|
+
};
|
|
16874
|
+
const payload = JSON.stringify(body);
|
|
16875
|
+
const res = await this.doFetchWithRetry(() => this.httpFetch(url, { method: "POST", headers, body: payload, signal }), signal);
|
|
16876
|
+
if (!res.ok) {
|
|
16877
|
+
const text = await res.text().catch(() => "");
|
|
16878
|
+
throw new ProviderError(`OpenAI embeddings API error ${res.status}: ${text}`, this.providerName, res.status, text);
|
|
16879
|
+
}
|
|
16880
|
+
return res;
|
|
16881
|
+
}
|
|
15672
16882
|
// ─── Internals ───────────────────────────────────────────────────────────
|
|
15673
|
-
|
|
16883
|
+
/** Chat Completions call that corrects itself from the provider's own 400s (see models/adjust.ts). */
|
|
16884
|
+
fetchChat(request, stream) {
|
|
16885
|
+
const model = request.model || this.defaultModel;
|
|
16886
|
+
return runWithModelAdjustments({
|
|
16887
|
+
provider: this.providerName,
|
|
16888
|
+
model,
|
|
16889
|
+
endpoint: "chat",
|
|
16890
|
+
scope: this.baseURL,
|
|
16891
|
+
callerParams: request.extra ? Object.keys(request.extra) : void 0,
|
|
16892
|
+
onLearned: this.onModelRuleLearned,
|
|
16893
|
+
run: (overlay, guard) => {
|
|
16894
|
+
const body = this.buildRequestBody(request, stream, overlay);
|
|
16895
|
+
guard(body);
|
|
16896
|
+
return this.doFetch(body, request.signal);
|
|
16897
|
+
}
|
|
16898
|
+
});
|
|
16899
|
+
}
|
|
16900
|
+
/** Same for the Responses API. */
|
|
16901
|
+
fetchResponses(request, adaptExtras, stream = false) {
|
|
16902
|
+
const model = request.model || this.defaultModel;
|
|
16903
|
+
return runWithModelAdjustments({
|
|
16904
|
+
provider: this.providerName,
|
|
16905
|
+
model,
|
|
16906
|
+
endpoint: "responses",
|
|
16907
|
+
scope: this.baseURL,
|
|
16908
|
+
callerParams: request.extra ? Object.keys(request.extra) : void 0,
|
|
16909
|
+
onLearned: this.onModelRuleLearned,
|
|
16910
|
+
run: (overlay, guard) => {
|
|
16911
|
+
const body = this.buildResponsesBody(request, overlay);
|
|
16912
|
+
if (adaptExtras) adaptChatExtrasForResponses(body, request.extra);
|
|
16913
|
+
if (stream) body.stream = true;
|
|
16914
|
+
guard(body);
|
|
16915
|
+
return this.responsesFetch(body, request.signal);
|
|
16916
|
+
}
|
|
16917
|
+
});
|
|
16918
|
+
}
|
|
16919
|
+
buildRequestBody(request, stream, overlay) {
|
|
15674
16920
|
const body = {
|
|
15675
16921
|
model: request.model || this.defaultModel,
|
|
15676
16922
|
messages: request.messages.map((m) => this.toOpenAIMessage(m)),
|
|
15677
16923
|
stream
|
|
15678
16924
|
};
|
|
15679
|
-
if (stream) {
|
|
16925
|
+
if (stream && request.streamUsage !== false) {
|
|
15680
16926
|
body.stream_options = { include_usage: true };
|
|
15681
16927
|
}
|
|
15682
|
-
|
|
15683
|
-
|
|
15684
|
-
if (request.
|
|
16928
|
+
const modelId = String(body.model);
|
|
16929
|
+
const rule = resolveModelRule({ provider: this.providerName, model: modelId, patch: overlay, scope: this.baseURL });
|
|
16930
|
+
if (request.temperature != null && allowsSampling(rule, "temperature", request.temperature)) body.temperature = request.temperature;
|
|
16931
|
+
if (request.maxTokens != null) {
|
|
16932
|
+
const param = this.maxTokensParam === "auto" ? rule.maxTokensParam : this.maxTokensParam;
|
|
16933
|
+
body[param] = request.maxTokens;
|
|
16934
|
+
}
|
|
16935
|
+
if (request.topP != null && allowsSampling(rule, "topP")) body.top_p = request.topP;
|
|
15685
16936
|
if (request.stop) body.stop = request.stop;
|
|
16937
|
+
if (request.presencePenalty != null && allowsSampling(rule, "presencePenalty")) body.presence_penalty = request.presencePenalty;
|
|
16938
|
+
if (request.frequencyPenalty != null && allowsSampling(rule, "frequencyPenalty")) body.frequency_penalty = request.frequencyPenalty;
|
|
16939
|
+
if (request.seed != null) body.seed = request.seed;
|
|
16940
|
+
if (request.n != null) body.n = request.n;
|
|
16941
|
+
if (request.logprobs != null && allowsSampling(rule, "logprobs")) body.logprobs = request.logprobs;
|
|
16942
|
+
if (request.topLogprobs != null && allowsSampling(rule, "logprobs")) body.top_logprobs = request.topLogprobs;
|
|
15686
16943
|
if (request.tools?.length) {
|
|
15687
16944
|
body.tools = request.tools.map((t) => this.toOpenAITool(t));
|
|
16945
|
+
if (request.parallelToolCalls != null) body.parallel_tool_calls = request.parallelToolCalls;
|
|
15688
16946
|
}
|
|
15689
16947
|
if (request.toolChoice != null && request.tools?.length) {
|
|
15690
16948
|
if (typeof request.toolChoice === "string") {
|
|
@@ -15710,14 +16968,17 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15710
16968
|
if (request.extra) {
|
|
15711
16969
|
Object.assign(body, request.extra);
|
|
15712
16970
|
}
|
|
15713
|
-
applyOpenAIReasoning(body, request.reasoning, "legacy_effort");
|
|
16971
|
+
applyOpenAIReasoning(body, request.reasoning, "legacy_effort", modelId, rule);
|
|
16972
|
+
if (body.tools?.length && rule.chatTools.reasoning === "force-none" && rule.reasoning.style !== "none") {
|
|
16973
|
+
body.reasoning_effort = "none";
|
|
16974
|
+
}
|
|
16975
|
+
applyDropParams(body, rule);
|
|
15714
16976
|
return body;
|
|
15715
16977
|
}
|
|
15716
16978
|
// ─── Responses API (reasoning models) ──────────────────────────────────────
|
|
15717
16979
|
async completeResponses(request) {
|
|
15718
|
-
const
|
|
15719
|
-
|
|
15720
|
-
const res = await this.responsesFetch(body, request.signal);
|
|
16980
|
+
const adapt = this.apiResponsesNative || this.isResponsesApiModel(request);
|
|
16981
|
+
const res = await this.fetchResponses(request, adapt);
|
|
15721
16982
|
const json = await res.json();
|
|
15722
16983
|
return this.parseResponsesResponse(json, request.model || this.defaultModel);
|
|
15723
16984
|
}
|
|
@@ -15730,15 +16991,13 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15730
16991
|
* reads it). */
|
|
15731
16992
|
async *streamResponses(request) {
|
|
15732
16993
|
const modelId = request.model || this.defaultModel;
|
|
15733
|
-
const
|
|
15734
|
-
adaptChatExtrasForResponses(body, request.extra);
|
|
15735
|
-
body.stream = true;
|
|
15736
|
-
const res = await this.responsesFetch(body, request.signal);
|
|
16994
|
+
const res = await this.fetchResponses(request, true, true);
|
|
15737
16995
|
if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
|
|
15738
16996
|
let id = "";
|
|
15739
16997
|
let model = modelId;
|
|
15740
16998
|
const calls = /* @__PURE__ */ new Map();
|
|
15741
16999
|
let final;
|
|
17000
|
+
let streamedSummary = false;
|
|
15742
17001
|
for await (const event of parseSSEStream(res.body, request.signal)) {
|
|
15743
17002
|
if (event.data === "[DONE]") break;
|
|
15744
17003
|
let data;
|
|
@@ -15756,19 +17015,28 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15756
17015
|
case "response.output_text.delta":
|
|
15757
17016
|
if (data.delta) yield { id, model, delta: { content: data.delta } };
|
|
15758
17017
|
break;
|
|
17018
|
+
case "response.reasoning_summary_part.added":
|
|
17019
|
+
if (streamedSummary) yield { id, model, delta: { reasoning: { summary: "\n\n" } } };
|
|
17020
|
+
break;
|
|
17021
|
+
case "response.reasoning_summary_text.delta":
|
|
17022
|
+
if (typeof data.delta === "string" && data.delta) {
|
|
17023
|
+
streamedSummary = true;
|
|
17024
|
+
yield { id, model, delta: { reasoning: { summary: data.delta } } };
|
|
17025
|
+
}
|
|
17026
|
+
break;
|
|
15759
17027
|
case "response.output_item.added": {
|
|
15760
17028
|
const item = data.item;
|
|
15761
17029
|
if (item?.type !== "function_call") break;
|
|
15762
|
-
const call = { callId: item.call_id ?? item.id ?? "", name: item.name ?? "", arguments: item.arguments ?? "" };
|
|
17030
|
+
const call = { callId: item.call_id ?? item.id ?? "", name: item.name ?? "", arguments: item.arguments ?? "", index: calls.size };
|
|
15763
17031
|
calls.set(item.id ?? call.callId, call);
|
|
15764
|
-
yield { id, model, delta: { toolCalls: [{ id: call.callId, name: call.name, arguments: call.arguments }] } };
|
|
17032
|
+
yield { id, model, delta: { toolCalls: [{ id: call.callId, name: call.name, arguments: call.arguments, index: call.index }] } };
|
|
15765
17033
|
break;
|
|
15766
17034
|
}
|
|
15767
17035
|
case "response.function_call_arguments.delta": {
|
|
15768
17036
|
const call = calls.get(data.item_id);
|
|
15769
17037
|
if (!call || !data.delta) break;
|
|
15770
17038
|
call.arguments += data.delta;
|
|
15771
|
-
yield { id, model, delta: { toolCalls: [{ id: call.callId, arguments: data.delta }] } };
|
|
17039
|
+
yield { id, model, delta: { toolCalls: [{ id: call.callId, arguments: data.delta, index: call.index }] } };
|
|
15772
17040
|
break;
|
|
15773
17041
|
}
|
|
15774
17042
|
case "response.output_item.done": {
|
|
@@ -15777,13 +17045,13 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15777
17045
|
const full = typeof item.arguments === "string" ? item.arguments : "";
|
|
15778
17046
|
const call = calls.get(item.id ?? item.call_id);
|
|
15779
17047
|
if (!call) {
|
|
15780
|
-
const added = { callId: item.call_id ?? item.id ?? "", name: item.name ?? "", arguments: full };
|
|
17048
|
+
const added = { callId: item.call_id ?? item.id ?? "", name: item.name ?? "", arguments: full, index: calls.size };
|
|
15781
17049
|
calls.set(item.id ?? added.callId, added);
|
|
15782
|
-
yield { id, model, delta: { toolCalls: [{ id: added.callId, name: added.name, arguments: full }] } };
|
|
17050
|
+
yield { id, model, delta: { toolCalls: [{ id: added.callId, name: added.name, arguments: full, index: added.index }] } };
|
|
15783
17051
|
} else if (full.length > call.arguments.length && full.startsWith(call.arguments)) {
|
|
15784
17052
|
const rest = full.slice(call.arguments.length);
|
|
15785
17053
|
call.arguments = full;
|
|
15786
|
-
yield { id, model, delta: { toolCalls: [{ id: call.callId, arguments: rest }] } };
|
|
17054
|
+
yield { id, model, delta: { toolCalls: [{ id: call.callId, arguments: rest, index: call.index }] } };
|
|
15787
17055
|
}
|
|
15788
17056
|
break;
|
|
15789
17057
|
}
|
|
@@ -15806,18 +17074,20 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15806
17074
|
yield {
|
|
15807
17075
|
id: final?.id || id,
|
|
15808
17076
|
model: final?.model || model,
|
|
15809
|
-
|
|
17077
|
+
// Summary text already went out as deltas; do not repeat it.
|
|
17078
|
+
delta: final?.reasoning && !streamedSummary ? { reasoning: final.reasoning } : {},
|
|
15810
17079
|
usage: final?.usage,
|
|
15811
17080
|
finishReason: final?.finishReason ?? (calls.size > 0 ? "tool_calls" : "stop")
|
|
15812
17081
|
};
|
|
15813
17082
|
}
|
|
15814
|
-
buildResponsesBody(request) {
|
|
17083
|
+
buildResponsesBody(request, overlay) {
|
|
15815
17084
|
const body = {
|
|
15816
17085
|
model: request.model || this.defaultModel,
|
|
15817
17086
|
input: request.messages.map((m) => this.toResponsesInput(m))
|
|
15818
17087
|
};
|
|
15819
17088
|
if (request.maxTokens != null) body.max_output_tokens = request.maxTokens;
|
|
15820
|
-
|
|
17089
|
+
const rule = resolveModelRule({ provider: this.providerName, model: String(body.model), patch: overlay, scope: this.baseURL });
|
|
17090
|
+
if (request.topP != null && allowsSampling(rule, "topP")) body.top_p = request.topP;
|
|
15821
17091
|
if (request.tools?.length) {
|
|
15822
17092
|
body.tools = request.tools.map((t) => ({
|
|
15823
17093
|
type: "function",
|
|
@@ -15849,7 +17119,8 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15849
17119
|
}
|
|
15850
17120
|
}
|
|
15851
17121
|
if (request.extra) Object.assign(body, request.extra);
|
|
15852
|
-
applyOpenAIReasoning(body, request.reasoning, "responses");
|
|
17122
|
+
applyOpenAIReasoning(body, request.reasoning, "responses", String(body.model), rule);
|
|
17123
|
+
applyDropParams(body, rule);
|
|
15853
17124
|
return body;
|
|
15854
17125
|
}
|
|
15855
17126
|
/** Maps a unified message to a Responses API `input` item. */
|
|
@@ -15916,7 +17187,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15916
17187
|
...this.defaultHeaders
|
|
15917
17188
|
};
|
|
15918
17189
|
const payload = JSON.stringify(body);
|
|
15919
|
-
const res = await this.doFetchWithRetry(() =>
|
|
17190
|
+
const res = await this.doFetchWithRetry(() => this.httpFetch(url, { method: "POST", headers, body: payload, signal }), signal);
|
|
15920
17191
|
if (!res.ok) {
|
|
15921
17192
|
const text = await res.text().catch(() => "");
|
|
15922
17193
|
throw new ProviderError(
|
|
@@ -16045,7 +17316,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
16045
17316
|
...this.defaultHeaders
|
|
16046
17317
|
};
|
|
16047
17318
|
const payload = JSON.stringify(body);
|
|
16048
|
-
const res = await this.doFetchWithRetry(() =>
|
|
17319
|
+
const res = await this.doFetchWithRetry(() => this.httpFetch(url, { method: "POST", headers, body: payload, signal }), signal);
|
|
16049
17320
|
if (!res.ok) {
|
|
16050
17321
|
const text = await res.text().catch(() => "");
|
|
16051
17322
|
throw new ProviderError(
|
|
@@ -16065,6 +17336,8 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
16065
17336
|
name: tc.function?.name ?? "",
|
|
16066
17337
|
arguments: tc.function?.arguments ?? "{}"
|
|
16067
17338
|
}));
|
|
17339
|
+
const reasoningText = extractReasoningText(message);
|
|
17340
|
+
const providerFields = pickProviderFields(json, message, choice);
|
|
16068
17341
|
return {
|
|
16069
17342
|
id: json.id ?? "",
|
|
16070
17343
|
model: json.model ?? "",
|
|
@@ -16072,6 +17345,9 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
16072
17345
|
toolCalls,
|
|
16073
17346
|
usage: this.extractUsage(json.usage),
|
|
16074
17347
|
finishReason: mapFinishReason(choice?.finish_reason),
|
|
17348
|
+
...typeof choice?.finish_reason === "string" ? { rawFinishReason: choice.finish_reason } : {},
|
|
17349
|
+
...providerFields ? { providerFields } : {},
|
|
17350
|
+
...reasoningText ? { reasoning: { summary: reasoningText } } : {},
|
|
16075
17351
|
raw: json
|
|
16076
17352
|
};
|
|
16077
17353
|
}
|
|
@@ -16090,10 +17366,27 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
16090
17366
|
};
|
|
16091
17367
|
}
|
|
16092
17368
|
};
|
|
17369
|
+
function extractReasoningText(src) {
|
|
17370
|
+
if (!src || typeof src !== "object") return void 0;
|
|
17371
|
+
for (const key of ["reasoning_content", "reasoning"]) {
|
|
17372
|
+
const v = src[key];
|
|
17373
|
+
if (typeof v === "string" && v.length > 0) return v;
|
|
17374
|
+
}
|
|
17375
|
+
return void 0;
|
|
17376
|
+
}
|
|
17377
|
+
function pickProviderFields(top, message, choice) {
|
|
17378
|
+
const out = {};
|
|
17379
|
+
if (top?.system_fingerprint != null) out.system_fingerprint = top.system_fingerprint;
|
|
17380
|
+
if (top?.service_tier != null) out.service_tier = top.service_tier;
|
|
17381
|
+
if (message?.annotations != null) out.annotations = message.annotations;
|
|
17382
|
+
if (message?.refusal != null) out.refusal = message.refusal;
|
|
17383
|
+
if (choice?.logprobs != null) out.logprobs = choice.logprobs;
|
|
17384
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
17385
|
+
}
|
|
16093
17386
|
function isReasoningModel(model) {
|
|
16094
17387
|
if (!model) return false;
|
|
16095
|
-
const
|
|
16096
|
-
return
|
|
17388
|
+
const rule = resolveModelRule({ provider: "openai", model });
|
|
17389
|
+
return !rule.isDefault && rule.reasoning.style === "effort" && rule.sampling.temperature !== "any";
|
|
16097
17390
|
}
|
|
16098
17391
|
function adaptChatExtrasForResponses(body, extra) {
|
|
16099
17392
|
const native = extra ?? {};
|
|
@@ -16166,36 +17459,80 @@ function mapFinishReason(reason) {
|
|
|
16166
17459
|
}
|
|
16167
17460
|
}
|
|
16168
17461
|
|
|
17462
|
+
// src/providers/utils/toolChoice.ts
|
|
17463
|
+
function supportsForcedToolChoice(model) {
|
|
17464
|
+
if (typeof model !== "string") return true;
|
|
17465
|
+
const id = model.toLowerCase();
|
|
17466
|
+
const at = id.indexOf("claude-");
|
|
17467
|
+
if (at < 0) return true;
|
|
17468
|
+
const toks = id.slice(at + 7).split("-");
|
|
17469
|
+
let family = false;
|
|
17470
|
+
for (const tok of toks) {
|
|
17471
|
+
if (tok === "sonnet" || tok === "opus") {
|
|
17472
|
+
family = true;
|
|
17473
|
+
continue;
|
|
17474
|
+
}
|
|
17475
|
+
const m = /^(\d+)(?:@|:|$)/.exec(tok);
|
|
17476
|
+
if (m) {
|
|
17477
|
+
if (m[1].length > 2) continue;
|
|
17478
|
+
if (Number(m[1]) < 5) return true;
|
|
17479
|
+
if (family) return false;
|
|
17480
|
+
return !toks.some((t) => t === "sonnet" || t === "opus");
|
|
17481
|
+
}
|
|
17482
|
+
}
|
|
17483
|
+
return true;
|
|
17484
|
+
}
|
|
17485
|
+
function forcedToolChoiceRejected(text) {
|
|
17486
|
+
const t = text.toLowerCase();
|
|
17487
|
+
return t.indexOf("tool_choice") >= 0 && t.indexOf("not supported for this model") >= 0;
|
|
17488
|
+
}
|
|
17489
|
+
|
|
16169
17490
|
// src/providers/anthropic.ts
|
|
17491
|
+
var DEFAULT_MAX_TOKENS = 4096;
|
|
17492
|
+
function normalizeExplicitThinking(body) {
|
|
17493
|
+
const t = body.thinking;
|
|
17494
|
+
if (t == null) {
|
|
17495
|
+
delete body.thinking;
|
|
17496
|
+
return;
|
|
17497
|
+
}
|
|
17498
|
+
if (t.type !== "enabled") return;
|
|
17499
|
+
const budget = typeof t.budget_tokens === "number" ? t.budget_tokens : 0;
|
|
17500
|
+
if (budget > 0 && (typeof body.max_tokens !== "number" || body.max_tokens <= budget)) {
|
|
17501
|
+
body.max_tokens = budget + 1024;
|
|
17502
|
+
}
|
|
17503
|
+
for (const k of ["temperature", "top_p", "top_k"]) delete body[k];
|
|
17504
|
+
}
|
|
16170
17505
|
var AnthropicProvider = class extends BaseProvider {
|
|
16171
17506
|
constructor(config) {
|
|
16172
17507
|
super();
|
|
16173
17508
|
this.providerName = "anthropic";
|
|
17509
|
+
this.configureTransport(config);
|
|
16174
17510
|
this.apiKey = config.apiKey;
|
|
16175
17511
|
this.baseURL = (config.baseURL ?? "https://api.anthropic.com").replace(/\/$/, "");
|
|
16176
17512
|
this.defaultModel = config.defaultModel ?? "claude-sonnet-4-20250514";
|
|
16177
17513
|
this.defaultHeaders = config.defaultHeaders ?? {};
|
|
16178
17514
|
this.anthropicVersion = config.anthropicVersion ?? "2023-06-01";
|
|
17515
|
+
this.thinkingMode = config.thinkingMode ?? "auto";
|
|
16179
17516
|
this.promptCachingEnabled = config.prompt_caching?.enabled === true;
|
|
16180
17517
|
if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
|
|
16181
17518
|
}
|
|
16182
17519
|
async complete(request) {
|
|
16183
|
-
const
|
|
16184
|
-
const res = await this.doFetch(body, request.signal);
|
|
17520
|
+
const res = await this.send(request, false);
|
|
16185
17521
|
const json = await res.json();
|
|
16186
17522
|
return this.parseResponse(json);
|
|
16187
17523
|
}
|
|
16188
17524
|
async *completeStream(request) {
|
|
16189
|
-
const
|
|
16190
|
-
const res = await this.doFetch(body, request.signal);
|
|
17525
|
+
const res = await this.send(request, true);
|
|
16191
17526
|
if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
|
|
16192
17527
|
let id = "";
|
|
16193
17528
|
let model = "";
|
|
16194
17529
|
let inputTokens = 0;
|
|
16195
17530
|
let outputTokens = 0;
|
|
17531
|
+
let thinkingTokens = 0;
|
|
16196
17532
|
let cacheReadInputTokens = 0;
|
|
16197
17533
|
let cacheCreationInputTokens = 0;
|
|
16198
17534
|
const currentToolCalls = /* @__PURE__ */ new Map();
|
|
17535
|
+
let toolOrdinal = 0;
|
|
16199
17536
|
const reasoningBlocks = /* @__PURE__ */ new Map();
|
|
16200
17537
|
for await (const event of parseSSEStream(res.body, request.signal)) {
|
|
16201
17538
|
let data;
|
|
@@ -16224,8 +17561,11 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16224
17561
|
currentToolCalls.set(idx, {
|
|
16225
17562
|
id: block.id ?? "",
|
|
16226
17563
|
name: block.name ?? "",
|
|
16227
|
-
arguments: ""
|
|
17564
|
+
arguments: "",
|
|
17565
|
+
ordinal: toolOrdinal++
|
|
16228
17566
|
});
|
|
17567
|
+
const opened = currentToolCalls.get(idx);
|
|
17568
|
+
yield { id, model, delta: { toolCalls: [{ id: opened.id, name: opened.name, arguments: "", index: opened.ordinal }] } };
|
|
16229
17569
|
} else if (block?.type === "thinking") {
|
|
16230
17570
|
reasoningBlocks.set(idx, { type: "thinking", text: block.thinking ?? "", signature: block.signature });
|
|
16231
17571
|
} else if (block?.type === "redacted_thinking") {
|
|
@@ -16263,7 +17603,7 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16263
17603
|
id,
|
|
16264
17604
|
model,
|
|
16265
17605
|
delta: {
|
|
16266
|
-
toolCalls: [{ id: tc.id, name: tc.name, arguments: delta.partial_json }]
|
|
17606
|
+
toolCalls: [{ id: tc.id, name: tc.name, arguments: delta.partial_json, index: tc.ordinal }]
|
|
16267
17607
|
}
|
|
16268
17608
|
};
|
|
16269
17609
|
}
|
|
@@ -16276,8 +17616,10 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16276
17616
|
const delta = data.delta;
|
|
16277
17617
|
if (data.usage) {
|
|
16278
17618
|
outputTokens = data.usage.output_tokens ?? outputTokens;
|
|
17619
|
+
thinkingTokens = data.usage.output_tokens_details?.thinking_tokens ?? thinkingTokens;
|
|
16279
17620
|
}
|
|
16280
17621
|
const finishReason = mapAnthropicStopReason(delta?.stop_reason);
|
|
17622
|
+
const rawFinishReason = typeof delta?.stop_reason === "string" ? delta.stop_reason : void 0;
|
|
16281
17623
|
const usage = {
|
|
16282
17624
|
inputTokens,
|
|
16283
17625
|
outputTokens,
|
|
@@ -16285,7 +17627,7 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16285
17627
|
cachedInputTokens: cacheReadInputTokens,
|
|
16286
17628
|
cachedWriteTokens: cacheCreationInputTokens,
|
|
16287
17629
|
cachedOutputTokens: 0,
|
|
16288
|
-
reasoningTokens:
|
|
17630
|
+
reasoningTokens: thinkingTokens
|
|
16289
17631
|
};
|
|
16290
17632
|
const blocks = [...reasoningBlocks.values()].filter(
|
|
16291
17633
|
(b) => b.type === "thinking" && b.signature || b.type === "redacted_thinking" && b.data
|
|
@@ -16295,6 +17637,7 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16295
17637
|
model,
|
|
16296
17638
|
delta: blocks.length > 0 ? { reasoning: { blocks } } : {},
|
|
16297
17639
|
finishReason,
|
|
17640
|
+
...rawFinishReason ? { rawFinishReason } : {},
|
|
16298
17641
|
usage
|
|
16299
17642
|
};
|
|
16300
17643
|
break;
|
|
@@ -16309,12 +17652,12 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16309
17652
|
}
|
|
16310
17653
|
}
|
|
16311
17654
|
// ─── Internals ───────────────────────────────────────────────────────────
|
|
16312
|
-
buildRequestBody(request, stream) {
|
|
17655
|
+
buildRequestBody(request, stream, overlay, downgradeToolChoice = false) {
|
|
16313
17656
|
const { system, messages } = this.splitSystemMessages(request.messages);
|
|
16314
17657
|
const body = {
|
|
16315
17658
|
model: request.model || this.defaultModel,
|
|
16316
17659
|
messages: this.toAnthropicMessages(messages),
|
|
16317
|
-
max_tokens: request.maxTokens ??
|
|
17660
|
+
max_tokens: request.maxTokens ?? DEFAULT_MAX_TOKENS,
|
|
16318
17661
|
stream
|
|
16319
17662
|
};
|
|
16320
17663
|
if (system) {
|
|
@@ -16324,6 +17667,7 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16324
17667
|
body.system = system;
|
|
16325
17668
|
}
|
|
16326
17669
|
}
|
|
17670
|
+
const rule = resolveModelRule({ provider: this.providerName, model: String(body.model), patch: overlay });
|
|
16327
17671
|
if (request.temperature != null) body.temperature = request.temperature;
|
|
16328
17672
|
if (request.topP != null) body.top_p = request.topP;
|
|
16329
17673
|
if (request.stop) body.stop_sequences = request.stop;
|
|
@@ -16335,18 +17679,29 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16335
17679
|
body.tools = tools;
|
|
16336
17680
|
}
|
|
16337
17681
|
if (request.toolChoice != null) {
|
|
17682
|
+
const forceOk = !downgradeToolChoice && supportsForcedToolChoice(body.model);
|
|
16338
17683
|
if (request.toolChoice === "auto") {
|
|
16339
17684
|
body.tool_choice = { type: "auto" };
|
|
16340
17685
|
} else if (request.toolChoice === "required") {
|
|
16341
|
-
body.tool_choice = { type: "any" };
|
|
17686
|
+
body.tool_choice = forceOk ? { type: "any" } : { type: "auto" };
|
|
16342
17687
|
} else if (request.toolChoice === "none") ; else {
|
|
16343
|
-
body.tool_choice = { type: "tool", name: request.toolChoice.name };
|
|
17688
|
+
body.tool_choice = forceOk ? { type: "tool", name: request.toolChoice.name } : { type: "auto" };
|
|
16344
17689
|
}
|
|
16345
17690
|
}
|
|
16346
17691
|
if (request.extra) {
|
|
16347
17692
|
Object.assign(body, request.extra);
|
|
16348
17693
|
}
|
|
16349
|
-
|
|
17694
|
+
const explicitThinking = request.extra && typeof request.extra === "object" && "thinking" in request.extra;
|
|
17695
|
+
if (explicitThinking) {
|
|
17696
|
+
normalizeExplicitThinking(body);
|
|
17697
|
+
enforceAnthropicSampling(body, rule, body.thinking?.type === "enabled" || body.thinking?.type === "adaptive");
|
|
17698
|
+
} else {
|
|
17699
|
+
applyAnthropicReasoning(body, request.reasoning, { model: body.model, mode: this.thinkingMode, rule });
|
|
17700
|
+
}
|
|
17701
|
+
applyDropParams(body, rule);
|
|
17702
|
+
if (typeof body.max_tokens !== "number" || !(body.max_tokens > 0)) {
|
|
17703
|
+
body.max_tokens = DEFAULT_MAX_TOKENS;
|
|
17704
|
+
}
|
|
16350
17705
|
return body;
|
|
16351
17706
|
}
|
|
16352
17707
|
splitSystemMessages(messages) {
|
|
@@ -16477,6 +17832,31 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16477
17832
|
input_schema: t.parameters
|
|
16478
17833
|
};
|
|
16479
17834
|
}
|
|
17835
|
+
/** Builds and sends the request; retries once with the other thinking form
|
|
17836
|
+
* when the upstream rejects the one we picked. */
|
|
17837
|
+
send(request, stream) {
|
|
17838
|
+
let downgrade = false;
|
|
17839
|
+
return runWithModelAdjustments({
|
|
17840
|
+
provider: this.providerName,
|
|
17841
|
+
model: request.model || this.defaultModel,
|
|
17842
|
+
endpoint: "messages",
|
|
17843
|
+
callerParams: request.extra ? Object.keys(request.extra) : void 0,
|
|
17844
|
+
onLearned: this.onModelRuleLearned,
|
|
17845
|
+
run: async (overlay, guard) => {
|
|
17846
|
+
for (; ; ) {
|
|
17847
|
+
const body = this.buildRequestBody(request, stream, overlay, downgrade);
|
|
17848
|
+
guard(body);
|
|
17849
|
+
try {
|
|
17850
|
+
return await this.doFetch(body, request.signal);
|
|
17851
|
+
} catch (err) {
|
|
17852
|
+
const rejected = err instanceof ProviderError && err.statusCode === 400 && !downgrade && body.tool_choice && body.tool_choice.type !== "auto" && forcedToolChoiceRejected(String(err.responseBody ?? err.message));
|
|
17853
|
+
if (!rejected) throw err;
|
|
17854
|
+
downgrade = true;
|
|
17855
|
+
}
|
|
17856
|
+
}
|
|
17857
|
+
}
|
|
17858
|
+
});
|
|
17859
|
+
}
|
|
16480
17860
|
async doFetch(body, signal) {
|
|
16481
17861
|
const url = `${this.baseURL}/v1/messages`;
|
|
16482
17862
|
const headers = {
|
|
@@ -16486,7 +17866,7 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16486
17866
|
...this.defaultHeaders
|
|
16487
17867
|
};
|
|
16488
17868
|
const payload = JSON.stringify(body);
|
|
16489
|
-
const res = await this.doFetchWithRetry(() =>
|
|
17869
|
+
const res = await this.doFetchWithRetry(() => this.httpFetch(url, { method: "POST", headers, body: payload, signal }), signal);
|
|
16490
17870
|
if (!res.ok) {
|
|
16491
17871
|
const text = await res.text().catch(() => "");
|
|
16492
17872
|
throw new ProviderError(
|
|
@@ -16531,10 +17911,9 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16531
17911
|
cachedInputTokens: usage.cache_read_input_tokens ?? 0,
|
|
16532
17912
|
cachedWriteTokens: usage.cache_creation_input_tokens ?? 0,
|
|
16533
17913
|
cachedOutputTokens: 0,
|
|
16534
|
-
//
|
|
16535
|
-
//
|
|
16536
|
-
|
|
16537
|
-
reasoningTokens: 0
|
|
17914
|
+
// Thinking tokens are billed inside `output_tokens`; newer models also
|
|
17915
|
+
// report the split as `output_tokens_details.thinking_tokens`.
|
|
17916
|
+
reasoningTokens: usage.output_tokens_details?.thinking_tokens ?? 0
|
|
16538
17917
|
};
|
|
16539
17918
|
return {
|
|
16540
17919
|
id: json.id ?? "",
|
|
@@ -16543,6 +17922,7 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16543
17922
|
toolCalls,
|
|
16544
17923
|
usage: tokenUsage,
|
|
16545
17924
|
finishReason: mapAnthropicStopReason(json.stop_reason),
|
|
17925
|
+
...typeof json.stop_reason === "string" ? { rawFinishReason: json.stop_reason } : {},
|
|
16546
17926
|
reasoning: reasoningBlocks.length > 0 ? { blocks: reasoningBlocks, summary: summaryParts.join("\n").trim() || void 0 } : void 0,
|
|
16547
17927
|
raw: json
|
|
16548
17928
|
};
|
|
@@ -16588,7 +17968,16 @@ var AzureProvider = class extends OpenAIProvider {
|
|
|
16588
17968
|
provider: "openai",
|
|
16589
17969
|
apiKey: config.apiKey,
|
|
16590
17970
|
defaultModel: config.defaultModel ?? config.deploymentName ?? "gpt-4o",
|
|
16591
|
-
defaultHeaders: config.defaultHeaders
|
|
17971
|
+
defaultHeaders: config.defaultHeaders,
|
|
17972
|
+
retry: config.retry,
|
|
17973
|
+
fetch: config.fetch,
|
|
17974
|
+
timeoutMs: config.timeoutMs,
|
|
17975
|
+
onModelRuleLearned: config.onModelRuleLearned,
|
|
17976
|
+
maxTokensParam: config.maxTokensParam,
|
|
17977
|
+
api: config.api,
|
|
17978
|
+
responsesApi: config.responsesApi,
|
|
17979
|
+
responsesApiModels: config.responsesApiModels,
|
|
17980
|
+
responsesStreaming: config.responsesStreaming
|
|
16592
17981
|
});
|
|
16593
17982
|
this.providerName = "azure";
|
|
16594
17983
|
this.endpoint = config.endpoint.replace(/\/$/, "");
|
|
@@ -16603,16 +17992,17 @@ var AzureProvider = class extends OpenAIProvider {
|
|
|
16603
17992
|
}
|
|
16604
17993
|
const url = `${this.endpoint}/openai/deployments/${deployment}/chat/completions?api-version=${this.apiVersion}`;
|
|
16605
17994
|
const { model: _model, ...bodyWithoutModel } = body;
|
|
16606
|
-
const
|
|
17995
|
+
const payload = JSON.stringify(bodyWithoutModel);
|
|
17996
|
+
const res = await this.doFetchWithRetry(() => this.httpFetch(url, {
|
|
16607
17997
|
method: "POST",
|
|
16608
17998
|
headers: {
|
|
16609
17999
|
"Content-Type": "application/json",
|
|
16610
18000
|
"api-key": this.azureApiKey,
|
|
16611
18001
|
...this.defaultHeaders
|
|
16612
18002
|
},
|
|
16613
|
-
body:
|
|
18003
|
+
body: payload,
|
|
16614
18004
|
signal
|
|
16615
|
-
});
|
|
18005
|
+
}), signal);
|
|
16616
18006
|
if (!res.ok) {
|
|
16617
18007
|
const text = await res.text().catch(() => "");
|
|
16618
18008
|
throw new ProviderError(
|
|
@@ -16624,6 +18014,32 @@ var AzureProvider = class extends OpenAIProvider {
|
|
|
16624
18014
|
}
|
|
16625
18015
|
return res;
|
|
16626
18016
|
}
|
|
18017
|
+
/** Azure embeddings: the deployment named by the request's model (falling back
|
|
18018
|
+
* to the configured deployment) in the path, api-key auth. */
|
|
18019
|
+
async embeddingsFetch(body, signal) {
|
|
18020
|
+
const deployment = body.model || this.deploymentName;
|
|
18021
|
+
if (!deployment) {
|
|
18022
|
+
throw new ProviderError("Azure embeddings require a deployment name or model", this.providerName, 400);
|
|
18023
|
+
}
|
|
18024
|
+
const url = `${this.endpoint}/openai/deployments/${deployment}/embeddings?api-version=${this.apiVersion}`;
|
|
18025
|
+
const { model: _model, ...bodyWithoutModel } = body;
|
|
18026
|
+
const payload = JSON.stringify(bodyWithoutModel);
|
|
18027
|
+
const res = await this.doFetchWithRetry(() => this.httpFetch(url, {
|
|
18028
|
+
method: "POST",
|
|
18029
|
+
headers: {
|
|
18030
|
+
"Content-Type": "application/json",
|
|
18031
|
+
"api-key": this.azureApiKey,
|
|
18032
|
+
...this.defaultHeaders
|
|
18033
|
+
},
|
|
18034
|
+
body: payload,
|
|
18035
|
+
signal
|
|
18036
|
+
}), signal);
|
|
18037
|
+
if (!res.ok) {
|
|
18038
|
+
const text = await res.text().catch(() => "");
|
|
18039
|
+
throw new ProviderError(`Azure OpenAI embeddings API error ${res.status}: ${text}`, this.providerName, res.status, text);
|
|
18040
|
+
}
|
|
18041
|
+
return res;
|
|
18042
|
+
}
|
|
16627
18043
|
/** Azure exposes the Responses API at /openai/responses with api-key auth.
|
|
16628
18044
|
* Reasoning summaries require a preview api-version; callers can override via
|
|
16629
18045
|
* the `apiVersion` config. */
|
|
@@ -16635,7 +18051,7 @@ var AzureProvider = class extends OpenAIProvider {
|
|
|
16635
18051
|
}
|
|
16636
18052
|
const url = `${this.endpoint}/openai/responses?api-version=${this.apiVersion}`;
|
|
16637
18053
|
const payload = JSON.stringify({ ...body, model: deployment });
|
|
16638
|
-
const res = await
|
|
18054
|
+
const res = await this.doFetchWithRetry(() => this.httpFetch(url, {
|
|
16639
18055
|
method: "POST",
|
|
16640
18056
|
headers: {
|
|
16641
18057
|
"Content-Type": "application/json",
|
|
@@ -16644,7 +18060,7 @@ var AzureProvider = class extends OpenAIProvider {
|
|
|
16644
18060
|
},
|
|
16645
18061
|
body: payload,
|
|
16646
18062
|
signal
|
|
16647
|
-
});
|
|
18063
|
+
}), signal);
|
|
16648
18064
|
if (!res.ok) {
|
|
16649
18065
|
const text = await res.text().catch(() => "");
|
|
16650
18066
|
throw new ProviderError(
|
|
@@ -16680,20 +18096,156 @@ var OpenAICompatibleProvider = class extends OpenAIProvider {
|
|
|
16680
18096
|
apiKey: config.apiKey,
|
|
16681
18097
|
baseURL: config.baseURL,
|
|
16682
18098
|
defaultModel: config.defaultModel,
|
|
16683
|
-
defaultHeaders: config.defaultHeaders
|
|
18099
|
+
defaultHeaders: config.defaultHeaders,
|
|
18100
|
+
organization: config.organization,
|
|
18101
|
+
retry: config.retry,
|
|
18102
|
+
fetch: config.fetch,
|
|
18103
|
+
timeoutMs: config.timeoutMs,
|
|
18104
|
+
onModelRuleLearned: config.onModelRuleLearned,
|
|
18105
|
+
maxTokensParam: config.maxTokensParam,
|
|
18106
|
+
api: config.api,
|
|
18107
|
+
// Unlike OpenAI / Azure, "auto" on a compatible server means Chat
|
|
18108
|
+
// Completions (the 0.11 default): the model name is the operator's.
|
|
18109
|
+
// `responsesApiModels` still applies; `responsesApi: "auto"` opts in.
|
|
18110
|
+
_autoMeansChat: true,
|
|
18111
|
+
responsesApi: config.responsesApi,
|
|
18112
|
+
responsesApiModels: config.responsesApiModels,
|
|
18113
|
+
responsesStreaming: config.responsesStreaming
|
|
16684
18114
|
});
|
|
16685
18115
|
this.providerName = "openai-compatible";
|
|
16686
18116
|
}
|
|
16687
18117
|
};
|
|
16688
18118
|
|
|
18119
|
+
// src/providers/utils/eventStream.ts
|
|
18120
|
+
var EventStreamError = class extends Error {
|
|
18121
|
+
constructor(message) {
|
|
18122
|
+
super(message);
|
|
18123
|
+
this.name = "EventStreamError";
|
|
18124
|
+
}
|
|
18125
|
+
};
|
|
18126
|
+
var CRC_TABLE = (() => {
|
|
18127
|
+
const table = new Uint32Array(256);
|
|
18128
|
+
for (let n = 0; n < 256; n++) {
|
|
18129
|
+
let c = n;
|
|
18130
|
+
for (let k = 0; k < 8; k++) c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
|
|
18131
|
+
table[n] = c >>> 0;
|
|
18132
|
+
}
|
|
18133
|
+
return table;
|
|
18134
|
+
})();
|
|
18135
|
+
function crc32(bytes, start = 0, end = bytes.length) {
|
|
18136
|
+
let c = 4294967295;
|
|
18137
|
+
for (let i = start; i < end; i++) c = CRC_TABLE[(c ^ bytes[i]) & 255] ^ c >>> 8;
|
|
18138
|
+
return (c ^ 4294967295) >>> 0;
|
|
18139
|
+
}
|
|
18140
|
+
function decodeFrame(frame) {
|
|
18141
|
+
const view = new DataView(frame.buffer, frame.byteOffset, frame.byteLength);
|
|
18142
|
+
const total = view.getUint32(0);
|
|
18143
|
+
const headersLen = view.getUint32(4);
|
|
18144
|
+
if (total !== frame.byteLength) throw new EventStreamError("event-stream frame length mismatch");
|
|
18145
|
+
if (crc32(frame, 0, 8) !== view.getUint32(8)) throw new EventStreamError("event-stream prelude CRC mismatch");
|
|
18146
|
+
if (crc32(frame, 0, total - 4) !== view.getUint32(total - 4)) throw new EventStreamError("event-stream message CRC mismatch");
|
|
18147
|
+
if (12 + headersLen > total - 4) throw new EventStreamError("event-stream headers overflow frame");
|
|
18148
|
+
const headers = {};
|
|
18149
|
+
const td = new TextDecoder();
|
|
18150
|
+
let o = 12;
|
|
18151
|
+
const headersEnd = 12 + headersLen;
|
|
18152
|
+
while (o < headersEnd) {
|
|
18153
|
+
const nameLen = frame[o++];
|
|
18154
|
+
const name = td.decode(frame.subarray(o, o + nameLen));
|
|
18155
|
+
o += nameLen;
|
|
18156
|
+
const type = frame[o++];
|
|
18157
|
+
switch (type) {
|
|
18158
|
+
case 0:
|
|
18159
|
+
headers[name] = true;
|
|
18160
|
+
break;
|
|
18161
|
+
case 1:
|
|
18162
|
+
headers[name] = false;
|
|
18163
|
+
break;
|
|
18164
|
+
case 2:
|
|
18165
|
+
headers[name] = view.getInt8(o);
|
|
18166
|
+
o += 1;
|
|
18167
|
+
break;
|
|
18168
|
+
case 3:
|
|
18169
|
+
headers[name] = view.getInt16(o);
|
|
18170
|
+
o += 2;
|
|
18171
|
+
break;
|
|
18172
|
+
case 4:
|
|
18173
|
+
headers[name] = view.getInt32(o);
|
|
18174
|
+
o += 4;
|
|
18175
|
+
break;
|
|
18176
|
+
case 5:
|
|
18177
|
+
headers[name] = view.getBigInt64(o);
|
|
18178
|
+
o += 8;
|
|
18179
|
+
break;
|
|
18180
|
+
case 6: {
|
|
18181
|
+
const len = view.getUint16(o);
|
|
18182
|
+
o += 2;
|
|
18183
|
+
headers[name] = frame.slice(o, o + len);
|
|
18184
|
+
o += len;
|
|
18185
|
+
break;
|
|
18186
|
+
}
|
|
18187
|
+
case 7: {
|
|
18188
|
+
const len = view.getUint16(o);
|
|
18189
|
+
o += 2;
|
|
18190
|
+
headers[name] = td.decode(frame.subarray(o, o + len));
|
|
18191
|
+
o += len;
|
|
18192
|
+
break;
|
|
18193
|
+
}
|
|
18194
|
+
case 8:
|
|
18195
|
+
headers[name] = view.getBigInt64(o);
|
|
18196
|
+
o += 8;
|
|
18197
|
+
break;
|
|
18198
|
+
case 9:
|
|
18199
|
+
headers[name] = frame.slice(o, o + 16);
|
|
18200
|
+
o += 16;
|
|
18201
|
+
break;
|
|
18202
|
+
default:
|
|
18203
|
+
throw new EventStreamError(`unknown event-stream header type ${type}`);
|
|
18204
|
+
}
|
|
18205
|
+
}
|
|
18206
|
+
return { headers, payload: frame.slice(headersEnd, total - 4) };
|
|
18207
|
+
}
|
|
18208
|
+
async function* parseEventStream(body, signal) {
|
|
18209
|
+
const reader = body.getReader();
|
|
18210
|
+
let buf = new Uint8Array(0);
|
|
18211
|
+
try {
|
|
18212
|
+
while (true) {
|
|
18213
|
+
if (signal?.aborted) throw abortReason(signal);
|
|
18214
|
+
const { done, value } = await reader.read();
|
|
18215
|
+
if (done) break;
|
|
18216
|
+
if (!value?.length) continue;
|
|
18217
|
+
const merged = new Uint8Array(buf.length + value.length);
|
|
18218
|
+
merged.set(buf, 0);
|
|
18219
|
+
merged.set(value, buf.length);
|
|
18220
|
+
buf = merged;
|
|
18221
|
+
while (buf.length >= 12) {
|
|
18222
|
+
const total = new DataView(buf.buffer, buf.byteOffset, buf.byteLength).getUint32(0);
|
|
18223
|
+
if (total < 16) throw new EventStreamError("invalid event-stream frame length");
|
|
18224
|
+
if (buf.length < total) break;
|
|
18225
|
+
yield decodeFrame(buf.subarray(0, total));
|
|
18226
|
+
buf = buf.subarray(total);
|
|
18227
|
+
}
|
|
18228
|
+
}
|
|
18229
|
+
if (buf.length > 0) throw new EventStreamError("event-stream ended inside a frame");
|
|
18230
|
+
} finally {
|
|
18231
|
+
reader.cancel().catch(() => void 0);
|
|
18232
|
+
try {
|
|
18233
|
+
reader.releaseLock();
|
|
18234
|
+
} catch {
|
|
18235
|
+
}
|
|
18236
|
+
}
|
|
18237
|
+
}
|
|
18238
|
+
|
|
16689
18239
|
// src/providers/bedrock.ts
|
|
16690
18240
|
var BedrockProvider = class extends BaseProvider {
|
|
16691
18241
|
constructor(config) {
|
|
16692
18242
|
super();
|
|
16693
18243
|
this.providerName = "bedrock";
|
|
18244
|
+
this.configureTransport(config);
|
|
16694
18245
|
this.region = config.region;
|
|
16695
18246
|
this.defaultModel = config.defaultModel ?? "anthropic.claude-sonnet-4-20250514-v1:0";
|
|
16696
18247
|
this.defaultHeaders = config.defaultHeaders ?? {};
|
|
18248
|
+
this.thinkingMode = config.thinkingMode ?? "auto";
|
|
16697
18249
|
this.promptCachingEnabled = config.prompt_caching?.enabled === true;
|
|
16698
18250
|
if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
|
|
16699
18251
|
this.credentials = {
|
|
@@ -16710,25 +18262,202 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16710
18262
|
}
|
|
16711
18263
|
async complete(request) {
|
|
16712
18264
|
const modelId = request.model || this.defaultModel;
|
|
16713
|
-
const
|
|
16714
|
-
|
|
16715
|
-
return this.parseResponse(json, modelId);
|
|
18265
|
+
const res = await this.converseFetch(modelId, request, false);
|
|
18266
|
+
return this.parseResponse(await res.json(), modelId);
|
|
16716
18267
|
}
|
|
18268
|
+
/**
|
|
18269
|
+
* Real streaming over ConverseStream. The response is an AWS event-stream
|
|
18270
|
+
* (binary frames); each frame carries one JSON event: messageStart,
|
|
18271
|
+
* contentBlockStart/Delta/Stop (text, toolUse, reasoningContent),
|
|
18272
|
+
* messageStop and, last, metadata (usage). Text, tool-call argument and
|
|
18273
|
+
* reasoning deltas are yielded as they arrive; one closing chunk carries the
|
|
18274
|
+
* finish reason, usage and the signed reasoning blocks.
|
|
18275
|
+
*/
|
|
16717
18276
|
async *completeStream(request) {
|
|
16718
|
-
const
|
|
18277
|
+
const modelId = request.model || this.defaultModel;
|
|
18278
|
+
const res = await this.converseFetch(modelId, request, true);
|
|
18279
|
+
if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
|
|
18280
|
+
const id = res.headers.get("x-amzn-requestid") ?? "";
|
|
18281
|
+
const toolsByIndex = /* @__PURE__ */ new Map();
|
|
18282
|
+
const reasoningByIndex = /* @__PURE__ */ new Map();
|
|
18283
|
+
let finishReason;
|
|
18284
|
+
let rawFinishReason;
|
|
18285
|
+
let toolOrdinal = 0;
|
|
18286
|
+
let usage;
|
|
18287
|
+
for await (const msg of parseEventStream(res.body, request.signal)) {
|
|
18288
|
+
const messageType = String(msg.headers[":message-type"] ?? "event");
|
|
18289
|
+
const eventType = String(msg.headers[":event-type"] ?? msg.headers[":exception-type"] ?? "");
|
|
18290
|
+
let data = {};
|
|
18291
|
+
const text = new TextDecoder().decode(msg.payload);
|
|
18292
|
+
if (text) {
|
|
18293
|
+
try {
|
|
18294
|
+
data = JSON.parse(text);
|
|
18295
|
+
} catch {
|
|
18296
|
+
data = { message: text };
|
|
18297
|
+
}
|
|
18298
|
+
}
|
|
18299
|
+
if (messageType === "exception" || messageType === "error") {
|
|
18300
|
+
const code = String(msg.headers[":exception-type"] ?? msg.headers[":error-code"] ?? eventType);
|
|
18301
|
+
throw new ProviderError(
|
|
18302
|
+
`Bedrock stream error ${code}: ${data.message ?? text}`,
|
|
18303
|
+
this.providerName,
|
|
18304
|
+
bedrockExceptionStatus(code),
|
|
18305
|
+
data
|
|
18306
|
+
);
|
|
18307
|
+
}
|
|
18308
|
+
switch (eventType) {
|
|
18309
|
+
case "contentBlockStart": {
|
|
18310
|
+
const idx = data.contentBlockIndex ?? 0;
|
|
18311
|
+
const tu = data.start?.toolUse;
|
|
18312
|
+
if (tu) {
|
|
18313
|
+
const ordinal = toolOrdinal++;
|
|
18314
|
+
toolsByIndex.set(idx, { id: tu.toolUseId ?? "", name: tu.name ?? "", ordinal });
|
|
18315
|
+
yield { id, model: modelId, delta: { toolCalls: [{ id: tu.toolUseId, name: tu.name, arguments: "", index: ordinal }] } };
|
|
18316
|
+
}
|
|
18317
|
+
break;
|
|
18318
|
+
}
|
|
18319
|
+
case "contentBlockDelta": {
|
|
18320
|
+
const idx = data.contentBlockIndex ?? 0;
|
|
18321
|
+
const d = data.delta ?? {};
|
|
18322
|
+
if (typeof d.text === "string" && d.text) {
|
|
18323
|
+
yield { id, model: modelId, delta: { content: d.text } };
|
|
18324
|
+
} else if (d.toolUse) {
|
|
18325
|
+
const tc = toolsByIndex.get(idx);
|
|
18326
|
+
if (tc && typeof d.toolUse.input === "string" && d.toolUse.input) {
|
|
18327
|
+
yield { id, model: modelId, delta: { toolCalls: [{ id: tc.id, name: tc.name, arguments: d.toolUse.input, index: tc.ordinal }] } };
|
|
18328
|
+
}
|
|
18329
|
+
} else if (d.reasoningContent) {
|
|
18330
|
+
const rc = d.reasoningContent;
|
|
18331
|
+
const blk = reasoningByIndex.get(idx) ?? { type: "thinking", text: "" };
|
|
18332
|
+
if (typeof rc.text === "string" && rc.text) {
|
|
18333
|
+
blk.text = (blk.text ?? "") + rc.text;
|
|
18334
|
+
reasoningByIndex.set(idx, blk);
|
|
18335
|
+
yield { id, model: modelId, delta: { reasoning: { summary: rc.text } } };
|
|
18336
|
+
}
|
|
18337
|
+
if (typeof rc.signature === "string" && rc.signature) {
|
|
18338
|
+
blk.signature = (blk.signature ?? "") + rc.signature;
|
|
18339
|
+
reasoningByIndex.set(idx, blk);
|
|
18340
|
+
}
|
|
18341
|
+
if (rc.redactedContent) {
|
|
18342
|
+
reasoningByIndex.set(idx, { type: "redacted_thinking", data: rc.redactedContent });
|
|
18343
|
+
}
|
|
18344
|
+
}
|
|
18345
|
+
break;
|
|
18346
|
+
}
|
|
18347
|
+
case "messageStop":
|
|
18348
|
+
finishReason = mapBedrockStopReason(data.stopReason);
|
|
18349
|
+
if (typeof data.stopReason === "string") rawFinishReason = data.stopReason;
|
|
18350
|
+
break;
|
|
18351
|
+
case "metadata": {
|
|
18352
|
+
const u = data.usage ?? {};
|
|
18353
|
+
usage = {
|
|
18354
|
+
inputTokens: u.inputTokens ?? 0,
|
|
18355
|
+
outputTokens: u.outputTokens ?? 0,
|
|
18356
|
+
totalTokens: u.totalTokens ?? (u.inputTokens ?? 0) + (u.outputTokens ?? 0),
|
|
18357
|
+
cachedInputTokens: u.cacheReadInputTokens ?? u.cacheReadInputTokenCount ?? 0,
|
|
18358
|
+
cachedWriteTokens: u.cacheWriteInputTokens ?? u.cacheWriteInputTokenCount ?? 0,
|
|
18359
|
+
cachedOutputTokens: 0,
|
|
18360
|
+
reasoningTokens: 0
|
|
18361
|
+
};
|
|
18362
|
+
break;
|
|
18363
|
+
}
|
|
18364
|
+
}
|
|
18365
|
+
}
|
|
18366
|
+
const blocks = [...reasoningByIndex.values()].filter(
|
|
18367
|
+
(b) => b.type === "thinking" && b.signature || b.type === "redacted_thinking" && b.data
|
|
18368
|
+
);
|
|
16719
18369
|
yield {
|
|
16720
|
-
id
|
|
16721
|
-
model:
|
|
16722
|
-
delta: {
|
|
16723
|
-
|
|
16724
|
-
|
|
16725
|
-
|
|
16726
|
-
usage: response.usage,
|
|
16727
|
-
finishReason: response.finishReason
|
|
18370
|
+
id,
|
|
18371
|
+
model: modelId,
|
|
18372
|
+
delta: blocks.length > 0 ? { reasoning: { blocks } } : {},
|
|
18373
|
+
finishReason: finishReason ?? "stop",
|
|
18374
|
+
...rawFinishReason ? { rawFinishReason } : {},
|
|
18375
|
+
usage
|
|
16728
18376
|
};
|
|
16729
18377
|
}
|
|
18378
|
+
// ─── Embeddings ──────────────────────────────────────────────────────────
|
|
18379
|
+
/**
|
|
18380
|
+
* InvokeModel embeddings. Supported families (by model id, inference-profile
|
|
18381
|
+
* prefixes such as `us.` allowed):
|
|
18382
|
+
* - Amazon Titan Text Embeddings (v1, v2): one text per call, `dimensions`
|
|
18383
|
+
* (v2: 256/512/1024) and `normalize` via `extra`.
|
|
18384
|
+
* - Cohere Embed (v3, v4): a batch of texts per call (default 96), `inputType`
|
|
18385
|
+
* maps to `input_type`, `dimensions` to `output_dimension` (v4).
|
|
18386
|
+
*/
|
|
18387
|
+
async embed(request) {
|
|
18388
|
+
const model = requireEmbeddingModel(this.providerName, request.model);
|
|
18389
|
+
const id = model.toLowerCase();
|
|
18390
|
+
const raw = [];
|
|
18391
|
+
let inputTokens = 0;
|
|
18392
|
+
let vectors = [];
|
|
18393
|
+
if (id.includes("titan-embed")) {
|
|
18394
|
+
const results = await mapWithConcurrency(request.input, 4, async (text) => {
|
|
18395
|
+
const body = { inputText: text };
|
|
18396
|
+
if (request.dimensions != null && !id.includes("titan-embed-text-v1")) body.dimensions = request.dimensions;
|
|
18397
|
+
if (request.extra) Object.assign(body, request.extra);
|
|
18398
|
+
const res = await this.invokeModel(model, body, request.signal);
|
|
18399
|
+
const json = await res.json();
|
|
18400
|
+
return { json, tokens: json.inputTextTokenCount ?? Number(res.headers.get("x-amzn-bedrock-input-token-count") ?? 0) };
|
|
18401
|
+
}, request.signal);
|
|
18402
|
+
for (const r of results) {
|
|
18403
|
+
raw.push(r.json);
|
|
18404
|
+
inputTokens += r.tokens || 0;
|
|
18405
|
+
vectors.push(r.json.embedding ?? r.json.embeddingsByType?.float);
|
|
18406
|
+
}
|
|
18407
|
+
} else if (id.includes("cohere.embed")) {
|
|
18408
|
+
for (const batch of chunkArray(request.input, request.batchSize ?? 96)) {
|
|
18409
|
+
const body = {
|
|
18410
|
+
texts: batch,
|
|
18411
|
+
input_type: request.inputType ?? "search_document",
|
|
18412
|
+
embedding_types: ["float"]
|
|
18413
|
+
};
|
|
18414
|
+
if (request.dimensions != null) body.output_dimension = request.dimensions;
|
|
18415
|
+
if (request.extra) Object.assign(body, request.extra);
|
|
18416
|
+
const res = await this.invokeModel(model, body, request.signal);
|
|
18417
|
+
const json = await res.json();
|
|
18418
|
+
raw.push(json);
|
|
18419
|
+
const emb = Array.isArray(json.embeddings) ? json.embeddings : json.embeddings?.float;
|
|
18420
|
+
vectors.push(...emb ?? []);
|
|
18421
|
+
inputTokens += Number(res.headers.get("x-amzn-bedrock-input-token-count") ?? 0) || 0;
|
|
18422
|
+
}
|
|
18423
|
+
} else {
|
|
18424
|
+
throw new ProviderError(
|
|
18425
|
+
`Bedrock embeddings are supported for Amazon Titan and Cohere Embed models, not "${model}"`,
|
|
18426
|
+
this.providerName,
|
|
18427
|
+
400
|
|
18428
|
+
);
|
|
18429
|
+
}
|
|
18430
|
+
assertVectorCount(this.providerName, vectors, request.input.length);
|
|
18431
|
+
return { model, vectors, usage: { inputTokens, totalTokens: inputTokens }, raw };
|
|
18432
|
+
}
|
|
18433
|
+
async invokeModel(modelId, body, signal) {
|
|
18434
|
+
const host = `bedrock-runtime.${this.region}.amazonaws.com`;
|
|
18435
|
+
const url = `https://${host}/model/${encodeURIComponent(modelId)}/invoke`;
|
|
18436
|
+
const bodyStr = JSON.stringify(body);
|
|
18437
|
+
const res = await this.doFetchWithRetry(() => {
|
|
18438
|
+
const headers = signRequest({
|
|
18439
|
+
method: "POST",
|
|
18440
|
+
url,
|
|
18441
|
+
headers: {
|
|
18442
|
+
"Content-Type": "application/json",
|
|
18443
|
+
Accept: "application/json",
|
|
18444
|
+
...this.defaultHeaders
|
|
18445
|
+
},
|
|
18446
|
+
body: bodyStr,
|
|
18447
|
+
region: this.region,
|
|
18448
|
+
service: "bedrock",
|
|
18449
|
+
credentials: this.credentials
|
|
18450
|
+
});
|
|
18451
|
+
return this.httpFetch(url, { method: "POST", headers, body: bodyStr, signal });
|
|
18452
|
+
}, signal);
|
|
18453
|
+
if (!res.ok) {
|
|
18454
|
+
const text = await res.text().catch(() => "");
|
|
18455
|
+
throw new ProviderError(`Bedrock API error ${res.status}: ${text}`, this.providerName, res.status, text);
|
|
18456
|
+
}
|
|
18457
|
+
return res;
|
|
18458
|
+
}
|
|
16730
18459
|
// ─── Internals ───────────────────────────────────────────────────────────
|
|
16731
|
-
buildConverseBody(request) {
|
|
18460
|
+
buildConverseBody(request, downgradeToolChoice = false, overlay) {
|
|
16732
18461
|
const { system, messages } = this.splitSystemMessages(request.messages);
|
|
16733
18462
|
const body = {
|
|
16734
18463
|
messages: this.toBedrockMessages(messages)
|
|
@@ -16752,8 +18481,9 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16752
18481
|
body.toolConfig = {
|
|
16753
18482
|
tools
|
|
16754
18483
|
};
|
|
18484
|
+
const forceOk = !downgradeToolChoice && supportsForcedToolChoice(request.model || this.defaultModel);
|
|
16755
18485
|
if (request.toolChoice != null) {
|
|
16756
|
-
if (request.toolChoice === "auto") {
|
|
18486
|
+
if (request.toolChoice === "auto" || !forceOk && request.toolChoice !== "none") {
|
|
16757
18487
|
body.toolConfig.toolChoice = { auto: {} };
|
|
16758
18488
|
} else if (request.toolChoice === "required") {
|
|
16759
18489
|
body.toolConfig.toolChoice = { any: {} };
|
|
@@ -16763,9 +18493,22 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16763
18493
|
}
|
|
16764
18494
|
}
|
|
16765
18495
|
if (request.extra) {
|
|
16766
|
-
|
|
16767
|
-
|
|
16768
|
-
|
|
18496
|
+
const fields = { ...request.extra.additionalModelRequestFields ?? {} };
|
|
18497
|
+
const topLevel = { ...request.extra.__top ?? {} };
|
|
18498
|
+
for (const [key, value] of Object.entries(request.extra)) {
|
|
18499
|
+
if (key === "additionalModelRequestFields" || key === "__top") continue;
|
|
18500
|
+
if (CONVERSE_TOP_LEVEL_FIELDS.has(key)) body[key] = value;
|
|
18501
|
+
else fields[key] = value;
|
|
18502
|
+
}
|
|
18503
|
+
Object.assign(body, topLevel);
|
|
18504
|
+
if (Object.keys(fields).length > 0) body.additionalModelRequestFields = fields;
|
|
18505
|
+
}
|
|
18506
|
+
const rule = resolveModelRule({ provider: this.providerName, model: request.model || this.defaultModel, patch: overlay });
|
|
18507
|
+
applyBedrockReasoning(body, request.reasoning, { model: request.model || this.defaultModel, mode: this.thinkingMode, rule });
|
|
18508
|
+
if (body.inferenceConfig && rule.dropParams?.length) {
|
|
18509
|
+
for (const p of rule.dropParams) delete body.inferenceConfig[p === "top_p" ? "topP" : p === "max_tokens" ? "maxTokens" : p];
|
|
18510
|
+
}
|
|
18511
|
+
applyDropParams(body, rule);
|
|
16769
18512
|
return body;
|
|
16770
18513
|
}
|
|
16771
18514
|
splitSystemMessages(messages) {
|
|
@@ -16888,9 +18631,35 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16888
18631
|
}
|
|
16889
18632
|
};
|
|
16890
18633
|
}
|
|
16891
|
-
|
|
18634
|
+
/** Sends the Converse call; retries once with toolChoice auto when the
|
|
18635
|
+
* model rejects forced tool use. */
|
|
18636
|
+
converseFetch(modelId, request, stream) {
|
|
18637
|
+
let downgrade = false;
|
|
18638
|
+
return runWithModelAdjustments({
|
|
18639
|
+
provider: this.providerName,
|
|
18640
|
+
model: modelId,
|
|
18641
|
+
endpoint: "converse",
|
|
18642
|
+
callerParams: request.extra ? Object.keys(request.extra) : void 0,
|
|
18643
|
+
onLearned: this.onModelRuleLearned,
|
|
18644
|
+
run: async (overlay, guard) => {
|
|
18645
|
+
for (; ; ) {
|
|
18646
|
+
const body = this.buildConverseBody(request, downgrade, overlay);
|
|
18647
|
+
guard(body);
|
|
18648
|
+
try {
|
|
18649
|
+
return await this.doFetch(modelId, body, request.signal, stream);
|
|
18650
|
+
} catch (err) {
|
|
18651
|
+
const tc = body.toolConfig?.toolChoice;
|
|
18652
|
+
const rejected = err instanceof ProviderError && err.statusCode === 400 && !downgrade && !!tc && !tc.auto && forcedToolChoiceRejected(String(err.responseBody ?? err.message));
|
|
18653
|
+
if (!rejected) throw err;
|
|
18654
|
+
downgrade = true;
|
|
18655
|
+
}
|
|
18656
|
+
}
|
|
18657
|
+
}
|
|
18658
|
+
});
|
|
18659
|
+
}
|
|
18660
|
+
async doFetch(modelId, body, signal, stream) {
|
|
16892
18661
|
const host = `bedrock-runtime.${this.region}.amazonaws.com`;
|
|
16893
|
-
const url = `https://${host}/model/${encodeURIComponent(modelId)}
|
|
18662
|
+
const url = `https://${host}/model/${encodeURIComponent(modelId)}/${stream ? "converse-stream" : "converse"}`;
|
|
16894
18663
|
const bodyStr = JSON.stringify(body);
|
|
16895
18664
|
const res = await this.doFetchWithRetry(() => {
|
|
16896
18665
|
const headers = signRequest({
|
|
@@ -16898,7 +18667,7 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16898
18667
|
url,
|
|
16899
18668
|
headers: {
|
|
16900
18669
|
"Content-Type": "application/json",
|
|
16901
|
-
Accept: "application/json",
|
|
18670
|
+
Accept: stream ? "application/vnd.amazon.eventstream" : "application/json",
|
|
16902
18671
|
...this.defaultHeaders
|
|
16903
18672
|
},
|
|
16904
18673
|
body: bodyStr,
|
|
@@ -16906,7 +18675,7 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16906
18675
|
service: "bedrock",
|
|
16907
18676
|
credentials: this.credentials
|
|
16908
18677
|
});
|
|
16909
|
-
return
|
|
18678
|
+
return this.httpFetch(url, { method: "POST", headers, body: bodyStr, signal });
|
|
16910
18679
|
}, signal);
|
|
16911
18680
|
if (!res.ok) {
|
|
16912
18681
|
const text = await res.text().catch(() => "");
|
|
@@ -16917,7 +18686,7 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16917
18686
|
text
|
|
16918
18687
|
);
|
|
16919
18688
|
}
|
|
16920
|
-
return res
|
|
18689
|
+
return res;
|
|
16921
18690
|
}
|
|
16922
18691
|
parseResponse(json, modelId) {
|
|
16923
18692
|
const output = json.output?.message;
|
|
@@ -16953,8 +18722,8 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16953
18722
|
inputTokens: usage.inputTokens ?? 0,
|
|
16954
18723
|
outputTokens: usage.outputTokens ?? 0,
|
|
16955
18724
|
totalTokens: usage.totalTokens ?? (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0),
|
|
16956
|
-
cachedInputTokens: usage.cacheReadInputTokenCount ?? 0,
|
|
16957
|
-
cachedWriteTokens: usage.cacheWriteInputTokenCount ?? 0,
|
|
18725
|
+
cachedInputTokens: usage.cacheReadInputTokens ?? usage.cacheReadInputTokenCount ?? 0,
|
|
18726
|
+
cachedWriteTokens: usage.cacheWriteInputTokens ?? usage.cacheWriteInputTokenCount ?? 0,
|
|
16958
18727
|
cachedOutputTokens: 0,
|
|
16959
18728
|
// Bedrock bills thinking tokens inside outputTokens; no separate count.
|
|
16960
18729
|
reasoningTokens: 0
|
|
@@ -16966,11 +18735,26 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16966
18735
|
toolCalls,
|
|
16967
18736
|
usage: tokenUsage,
|
|
16968
18737
|
finishReason: mapBedrockStopReason(json.stopReason),
|
|
18738
|
+
...typeof json.stopReason === "string" ? { rawFinishReason: json.stopReason } : {},
|
|
16969
18739
|
reasoning: reasoningBlocks.length > 0 ? { blocks: reasoningBlocks, summary: summaryParts.join("\n").trim() || void 0 } : void 0,
|
|
16970
18740
|
raw: json
|
|
16971
18741
|
};
|
|
16972
18742
|
}
|
|
16973
18743
|
};
|
|
18744
|
+
var CONVERSE_TOP_LEVEL_FIELDS = /* @__PURE__ */ new Set([
|
|
18745
|
+
"messages",
|
|
18746
|
+
"system",
|
|
18747
|
+
"inferenceConfig",
|
|
18748
|
+
"toolConfig",
|
|
18749
|
+
"guardrailConfig",
|
|
18750
|
+
"additionalModelRequestFields",
|
|
18751
|
+
"additionalModelResponseFieldPaths",
|
|
18752
|
+
"promptVariables",
|
|
18753
|
+
"requestMetadata",
|
|
18754
|
+
"performanceConfig",
|
|
18755
|
+
"serviceTier",
|
|
18756
|
+
"outputConfig"
|
|
18757
|
+
]);
|
|
16974
18758
|
function appendBedrockReasoning(content, blocks) {
|
|
16975
18759
|
if (!blocks?.length) return;
|
|
16976
18760
|
for (const b of blocks) {
|
|
@@ -16985,6 +18769,23 @@ function appendBedrockReasoning(content, blocks) {
|
|
|
16985
18769
|
}
|
|
16986
18770
|
}
|
|
16987
18771
|
}
|
|
18772
|
+
function bedrockExceptionStatus(code) {
|
|
18773
|
+
switch (code) {
|
|
18774
|
+
case "throttlingException":
|
|
18775
|
+
return 429;
|
|
18776
|
+
case "validationException":
|
|
18777
|
+
return 400;
|
|
18778
|
+
case "modelTimeoutException":
|
|
18779
|
+
return 408;
|
|
18780
|
+
case "serviceUnavailableException":
|
|
18781
|
+
return 503;
|
|
18782
|
+
case "internalServerException":
|
|
18783
|
+
case "modelStreamErrorException":
|
|
18784
|
+
return 500;
|
|
18785
|
+
default:
|
|
18786
|
+
return void 0;
|
|
18787
|
+
}
|
|
18788
|
+
}
|
|
16988
18789
|
function mapBedrockStopReason(reason) {
|
|
16989
18790
|
switch (reason) {
|
|
16990
18791
|
case "end_turn":
|
|
@@ -16993,8 +18794,10 @@ function mapBedrockStopReason(reason) {
|
|
|
16993
18794
|
case "tool_use":
|
|
16994
18795
|
return "tool_calls";
|
|
16995
18796
|
case "max_tokens":
|
|
18797
|
+
case "model_context_window_exceeded":
|
|
16996
18798
|
return "length";
|
|
16997
18799
|
case "content_filtered":
|
|
18800
|
+
case "guardrail_intervened":
|
|
16998
18801
|
case "guardrail":
|
|
16999
18802
|
return "content_filter";
|
|
17000
18803
|
default:
|
|
@@ -17024,10 +18827,12 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17024
18827
|
super();
|
|
17025
18828
|
this.providerName = "vertex";
|
|
17026
18829
|
this.tokenExpiry = 0;
|
|
18830
|
+
this.configureTransport(config);
|
|
17027
18831
|
this.projectId = config.projectId;
|
|
17028
18832
|
this.location = config.location ?? "us-central1";
|
|
17029
18833
|
this.defaultModel = config.defaultModel ?? "gemini-2.0-flash";
|
|
17030
18834
|
this.defaultHeaders = config.defaultHeaders ?? {};
|
|
18835
|
+
if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
|
|
17031
18836
|
if (config.accessToken) {
|
|
17032
18837
|
this.accessToken = config.accessToken;
|
|
17033
18838
|
this.tokenExpiry = Date.now() + 36e5;
|
|
@@ -17040,7 +18845,7 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17040
18845
|
const modelId = request.model || this.defaultModel;
|
|
17041
18846
|
const body = this.buildGeminiBody(request);
|
|
17042
18847
|
const url = this.buildUrl(modelId, false);
|
|
17043
|
-
const res = await this.doFetch(url, body, request.signal);
|
|
18848
|
+
const res = await this.doFetch(url, body, request.signal, modelId);
|
|
17044
18849
|
const json = await res.json();
|
|
17045
18850
|
return this.parseResponse(json, modelId);
|
|
17046
18851
|
}
|
|
@@ -17048,8 +18853,9 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17048
18853
|
const modelId = request.model || this.defaultModel;
|
|
17049
18854
|
const body = this.buildGeminiBody(request);
|
|
17050
18855
|
const url = this.buildUrl(modelId, true);
|
|
17051
|
-
const res = await this.doFetch(url, body, request.signal);
|
|
18856
|
+
const res = await this.doFetch(url, body, request.signal, modelId);
|
|
17052
18857
|
if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
|
|
18858
|
+
const counter = { next: 0 };
|
|
17053
18859
|
const contentType = res.headers.get("content-type") ?? "";
|
|
17054
18860
|
if (contentType.includes("text/event-stream")) {
|
|
17055
18861
|
for await (const event of parseSSEStream(res.body, request.signal)) {
|
|
@@ -17060,7 +18866,7 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17060
18866
|
} catch {
|
|
17061
18867
|
continue;
|
|
17062
18868
|
}
|
|
17063
|
-
yield this.parseStreamChunk(chunk, modelId);
|
|
18869
|
+
yield this.parseStreamChunk(chunk, modelId, counter);
|
|
17064
18870
|
}
|
|
17065
18871
|
} else {
|
|
17066
18872
|
const reader = res.body.getReader();
|
|
@@ -17078,7 +18884,7 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17078
18884
|
if (!trimmed || trimmed === "[" || trimmed === "]") continue;
|
|
17079
18885
|
try {
|
|
17080
18886
|
const chunk = JSON.parse(trimmed);
|
|
17081
|
-
yield this.parseStreamChunk(chunk, modelId);
|
|
18887
|
+
yield this.parseStreamChunk(chunk, modelId, counter);
|
|
17082
18888
|
} catch {
|
|
17083
18889
|
buffer = line + "\n" + buffer;
|
|
17084
18890
|
break;
|
|
@@ -17089,7 +18895,7 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17089
18895
|
if (remaining && remaining !== "[" && remaining !== "]") {
|
|
17090
18896
|
try {
|
|
17091
18897
|
const chunk = JSON.parse(remaining);
|
|
17092
|
-
yield this.parseStreamChunk(chunk, modelId);
|
|
18898
|
+
yield this.parseStreamChunk(chunk, modelId, counter);
|
|
17093
18899
|
} catch {
|
|
17094
18900
|
}
|
|
17095
18901
|
}
|
|
@@ -17100,6 +18906,48 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17100
18906
|
}
|
|
17101
18907
|
}
|
|
17102
18908
|
// ─── Internals ───────────────────────────────────────────────────────────
|
|
18909
|
+
/**
|
|
18910
|
+
* Vertex `:predict` embeddings (text-embedding-00x, text-multilingual-embedding,
|
|
18911
|
+
* gemini-embedding-001). `inputType` maps to the task type; `dimensions` to
|
|
18912
|
+
* `outputDimensionality`. gemini-embedding takes one instance per request, the
|
|
18913
|
+
* text-embedding models up to `batchSize` (default 100).
|
|
18914
|
+
*/
|
|
18915
|
+
async embed(request) {
|
|
18916
|
+
const model = requireEmbeddingModel(this.providerName, request.model);
|
|
18917
|
+
const perRequest = request.batchSize ?? (/gemini-embedding/i.test(model) ? 1 : 100);
|
|
18918
|
+
const url = `https://${this.location}-aiplatform.googleapis.com/v1/projects/${this.projectId}/locations/${this.location}/publishers/google/models/${model}:predict`;
|
|
18919
|
+
const taskType = request.inputType ? Object.prototype.hasOwnProperty.call(GEMINI_TASK_TYPES, request.inputType) ? GEMINI_TASK_TYPES[request.inputType] : request.inputType.toUpperCase() : void 0;
|
|
18920
|
+
const vectors = [];
|
|
18921
|
+
const raw = [];
|
|
18922
|
+
let inputTokens = 0;
|
|
18923
|
+
for (const batch of chunkArray(request.input, perRequest)) {
|
|
18924
|
+
const body = {
|
|
18925
|
+
instances: batch.map((content) => ({ content, ...taskType ? { task_type: taskType } : {} }))
|
|
18926
|
+
};
|
|
18927
|
+
const { parameters: extraParameters, ...extraRest } = request.extra ?? {};
|
|
18928
|
+
const parameters = {
|
|
18929
|
+
...request.dimensions != null ? { outputDimensionality: request.dimensions } : {},
|
|
18930
|
+
// Caller-supplied parameters are merged in, not replacing the above (an
|
|
18931
|
+
// explicit extra.parameters.outputDimensionality still wins).
|
|
18932
|
+
...extraParameters && typeof extraParameters === "object" ? extraParameters : {}
|
|
18933
|
+
};
|
|
18934
|
+
if (Object.keys(parameters).length > 0) body.parameters = parameters;
|
|
18935
|
+
Object.assign(body, extraRest);
|
|
18936
|
+
const res = await this.doFetch(url, body, request.signal, model);
|
|
18937
|
+
const json = await res.json();
|
|
18938
|
+
raw.push(json);
|
|
18939
|
+
for (const p of json.predictions ?? []) {
|
|
18940
|
+
const values = p.embeddings?.values;
|
|
18941
|
+
if (!Array.isArray(values)) {
|
|
18942
|
+
throw new ProviderError("Vertex embeddings response has a prediction without an embeddings.values array", this.providerName, void 0, json);
|
|
18943
|
+
}
|
|
18944
|
+
vectors.push(values);
|
|
18945
|
+
inputTokens += p.embeddings?.statistics?.token_count ?? 0;
|
|
18946
|
+
}
|
|
18947
|
+
}
|
|
18948
|
+
assertVectorCount(this.providerName, vectors, request.input.length);
|
|
18949
|
+
return { model, vectors, usage: { inputTokens, totalTokens: inputTokens }, raw };
|
|
18950
|
+
}
|
|
17103
18951
|
buildUrl(modelId, stream) {
|
|
17104
18952
|
const base = `https://${this.location}-aiplatform.googleapis.com/v1`;
|
|
17105
18953
|
const path2 = `projects/${this.projectId}/locations/${this.location}/publishers/google/models/${modelId}`;
|
|
@@ -17197,7 +19045,9 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17197
19045
|
functionCall: {
|
|
17198
19046
|
name: tc.name,
|
|
17199
19047
|
args: safeJsonParse3(tc.arguments)
|
|
17200
|
-
}
|
|
19048
|
+
},
|
|
19049
|
+
// Gemini 3 requires the signature of each functionCall echoed back.
|
|
19050
|
+
...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {}
|
|
17201
19051
|
});
|
|
17202
19052
|
}
|
|
17203
19053
|
return { role: "model", parts: parts2 };
|
|
@@ -17294,7 +19144,7 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17294
19144
|
sign.update(signingInput);
|
|
17295
19145
|
const signature = sign.sign(sa.private_key, "base64url");
|
|
17296
19146
|
const jwt = `${signingInput}.${signature}`;
|
|
17297
|
-
const tokenRes = await
|
|
19147
|
+
const tokenRes = await this.httpFetch("https://oauth2.googleapis.com/token", {
|
|
17298
19148
|
method: "POST",
|
|
17299
19149
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
17300
19150
|
body: `grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=${jwt}`
|
|
@@ -17306,20 +19156,38 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17306
19156
|
const tokenJson = await tokenRes.json();
|
|
17307
19157
|
return tokenJson.access_token;
|
|
17308
19158
|
}
|
|
17309
|
-
async doFetch(url, body, signal) {
|
|
19159
|
+
async doFetch(url, body, signal, model = "") {
|
|
17310
19160
|
const token = await this.getAccessToken();
|
|
17311
|
-
const
|
|
17312
|
-
|
|
17313
|
-
|
|
17314
|
-
|
|
17315
|
-
|
|
17316
|
-
|
|
17317
|
-
|
|
17318
|
-
|
|
19161
|
+
const bodyStr = JSON.stringify(body);
|
|
19162
|
+
const res = await this.doFetchWithRetry(
|
|
19163
|
+
() => this.httpFetch(url, {
|
|
19164
|
+
method: "POST",
|
|
19165
|
+
headers: {
|
|
19166
|
+
"Content-Type": "application/json",
|
|
19167
|
+
Authorization: `Bearer ${token}`,
|
|
19168
|
+
...this.defaultHeaders
|
|
19169
|
+
},
|
|
19170
|
+
body: bodyStr,
|
|
19171
|
+
signal
|
|
19172
|
+
}),
|
|
17319
19173
|
signal
|
|
17320
|
-
|
|
19174
|
+
);
|
|
17321
19175
|
if (!res.ok) {
|
|
17322
19176
|
const text = await res.text().catch(() => "");
|
|
19177
|
+
if (res.status === 400) {
|
|
19178
|
+
const parsed = parseModelError(text);
|
|
19179
|
+
throw new ModelRequestError({
|
|
19180
|
+
status: 400,
|
|
19181
|
+
code: parsed?.kind === "unsupported_value" ? "unsupported_value" : parsed?.kind === "unsupported_parameter" ? "unsupported_parameter" : "model_request_invalid",
|
|
19182
|
+
param: parsed?.param,
|
|
19183
|
+
value: parsed?.value,
|
|
19184
|
+
supportedValues: parsed?.supportedValues,
|
|
19185
|
+
provider: this.providerName,
|
|
19186
|
+
model,
|
|
19187
|
+
message: `Vertex AI API error ${res.status}: ${text}`,
|
|
19188
|
+
responseBody: text
|
|
19189
|
+
});
|
|
19190
|
+
}
|
|
17323
19191
|
throw new ProviderError(
|
|
17324
19192
|
`Vertex AI API error ${res.status}: ${text}`,
|
|
17325
19193
|
this.providerName,
|
|
@@ -17347,7 +19215,8 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17347
19215
|
toolCalls.push({
|
|
17348
19216
|
id: `call_${toolCallIdx++}`,
|
|
17349
19217
|
name: part.functionCall.name,
|
|
17350
|
-
arguments: JSON.stringify(part.functionCall.args ?? {})
|
|
19218
|
+
arguments: JSON.stringify(part.functionCall.args ?? {}),
|
|
19219
|
+
...part.thoughtSignature ? { thoughtSignature: part.thoughtSignature } : {}
|
|
17351
19220
|
});
|
|
17352
19221
|
}
|
|
17353
19222
|
}
|
|
@@ -17368,11 +19237,12 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17368
19237
|
toolCalls,
|
|
17369
19238
|
usage: tokenUsage,
|
|
17370
19239
|
finishReason: mapGeminiFinishReason(candidate?.finishReason),
|
|
19240
|
+
...typeof candidate?.finishReason === "string" ? { rawFinishReason: candidate.finishReason } : {},
|
|
17371
19241
|
reasoning: thoughtParts.length > 0 ? { summary: thoughtParts.join("\n").trim() || void 0 } : void 0,
|
|
17372
19242
|
raw: json
|
|
17373
19243
|
};
|
|
17374
19244
|
}
|
|
17375
|
-
parseStreamChunk(chunk, modelId) {
|
|
19245
|
+
parseStreamChunk(chunk, modelId, counter) {
|
|
17376
19246
|
const candidate = chunk.candidates?.[0];
|
|
17377
19247
|
const parts = candidate?.content?.parts ?? [];
|
|
17378
19248
|
const delta = {};
|
|
@@ -17386,9 +19256,12 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17386
19256
|
} else if (part.functionCall) {
|
|
17387
19257
|
if (!delta.toolCalls) delta.toolCalls = [];
|
|
17388
19258
|
delta.toolCalls.push({
|
|
17389
|
-
|
|
19259
|
+
// Unique across the whole stream: the adapter merges chunks by id.
|
|
19260
|
+
id: `call_${counter.next}`,
|
|
19261
|
+
index: counter.next++,
|
|
17390
19262
|
name: part.functionCall.name,
|
|
17391
|
-
arguments: JSON.stringify(part.functionCall.args ?? {})
|
|
19263
|
+
arguments: JSON.stringify(part.functionCall.args ?? {}),
|
|
19264
|
+
...part.thoughtSignature ? { thoughtSignature: part.thoughtSignature } : {}
|
|
17392
19265
|
});
|
|
17393
19266
|
}
|
|
17394
19267
|
}
|
|
@@ -17410,10 +19283,21 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17410
19283
|
model: modelId,
|
|
17411
19284
|
delta,
|
|
17412
19285
|
usage,
|
|
17413
|
-
finishReason: mapGeminiFinishReason(candidate?.finishReason)
|
|
19286
|
+
finishReason: mapGeminiFinishReason(candidate?.finishReason),
|
|
19287
|
+
...typeof candidate?.finishReason === "string" ? { rawFinishReason: candidate.finishReason } : {}
|
|
17414
19288
|
};
|
|
17415
19289
|
}
|
|
17416
19290
|
};
|
|
19291
|
+
var GEMINI_TASK_TYPES = {
|
|
19292
|
+
search_document: "RETRIEVAL_DOCUMENT",
|
|
19293
|
+
search_query: "RETRIEVAL_QUERY",
|
|
19294
|
+
classification: "CLASSIFICATION",
|
|
19295
|
+
clustering: "CLUSTERING",
|
|
19296
|
+
semantic_similarity: "SEMANTIC_SIMILARITY",
|
|
19297
|
+
question_answering: "QUESTION_ANSWERING",
|
|
19298
|
+
fact_verification: "FACT_VERIFICATION",
|
|
19299
|
+
code_retrieval_query: "CODE_RETRIEVAL_QUERY"
|
|
19300
|
+
};
|
|
17417
19301
|
function mapGeminiFinishReason(reason) {
|
|
17418
19302
|
switch (reason) {
|
|
17419
19303
|
case "STOP":
|
|
@@ -17462,6 +19346,6 @@ function createProvider(config) {
|
|
|
17462
19346
|
}
|
|
17463
19347
|
}
|
|
17464
19348
|
|
|
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 };
|
|
19349
|
+
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, MAX_ADJUSTMENTS, MODEL_RULES, ModelRequestError, NativeJsonSchemaStrategy, OpenAICompatibleProvider, OpenAIProvider, PREOPEN_TOOL_CALL_PREFIX, ProviderError, SMALL_TIER_SKILL_POLICY, StructuredOutputManager, TOOL_INPUT_DIGEST_KEY, ToolBasedStrategy, VertexProvider, agentVerdictRule, allowsSampling, appendBoundTools, applyDropParams, asModelRequestError, auditLog, azureContentSafety, bedrockGuardrail, budgetGuard, buildHandoffTools, buildResponseFormatSection, buildSkillHeaderBlock, buildSubagentCatalogBlock, buildSystemPrompt, buildToolDefinitionsSection, canOpenSkill, canSpawn, captureSnapshot, checkpointing, clearLearnedModelRules, 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, effortBudget, emptyUsage, evaluateGuardrails, extractLatestUserQuery, extractMessageText, fileCheckpointStore, fileSink, findSubagent, formatZodError, fromLangchainModel, fromLangchainTools, fromNativeProvider, generateSpanId, generateTraceId, getLearnedModelRulePatch, getModelCapabilities, getNestedValue, getResolvedSmartConfig, getTokenCounter, hasMediaPart, hasToolResponseRecoveryReference, httpGuardrail, httpSink, inMemoryCheckpointStore, inMemoryConversationStore, isHookImplemented, isOpenAIHostedEndpoint, isSmartModel, isValidIban, isValidLuhn, isValidTckn, jsonSchemaRule, defaultBuildPayload as langfuseDefaultPayload, langfuseTracing, languageGuard, listLearnedModelRules, loadSkillsFromDisk, mapConsoleHookVerdict, mapReasoningEffort, mapTextParts, mcp, mediaKindOf, mediaPolicy, mergeRulePatch, modelIdCandidates, normalizeSmartAgentOptions, normalizeVerdicts, openAIModeration, otelTracing, otlpSink, outputGuard, parseApprovalDecision, parseModelError, parseSkillFrontmatter, pathSandbox, piiRedaction, pluginCapabilities, portkeyGateway, portkeyGuardrail, preopenSkills, preopenToolCallId, prepareStrictToolMenu, promptInjectionGuard, rateLimit, readMemoryFacts, redactText, regexGuardrail, regexRule, rememberModelRulePatch, replaceTextContent, resolveAvailableSkills, resolveAvailableSubagents, resolveInputRetention, resolveMemoryStore, resolveModelRule, resolveReasoning, resolveStrategy, resolveSubagentTools, resolveSummarizationRetention, resolveToolApprovalState, resolveUserQuestionState, responseCache, restoreSnapshot, restoreToolCalls, runSmartAgentEvalHarness, runWithModelAdjustments, scoreItemsByRelevance, searchSkills, seedChildMessages, selectTopIndicesInOrder, sessionMetrics, setTokenCounter, startStreamingSession, summarizeObject, supportsAdaptiveThinking, textFromContent, toMessageUsage, toStrictCompatible, toStrictToolSchema, tokenize, toolPolicy, traceSessionToOtlp, validateReasoningConfig, validateToolArgs, webhookApproval, withTools, withinDepth, writeSummaryFactsToMemory };
|
|
17466
19350
|
//# sourceMappingURL=index.mjs.map
|
|
17467
19351
|
//# sourceMappingURL=index.mjs.map
|