@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.cjs
CHANGED
|
@@ -2441,6 +2441,15 @@ function estimatePayloadBytes(value) {
|
|
|
2441
2441
|
}
|
|
2442
2442
|
}
|
|
2443
2443
|
}
|
|
2444
|
+
function toMessageUsage(u) {
|
|
2445
|
+
return {
|
|
2446
|
+
prompt_tokens: u.inputTokens,
|
|
2447
|
+
completion_tokens: u.outputTokens,
|
|
2448
|
+
total_tokens: u.totalTokens,
|
|
2449
|
+
prompt_tokens_details: { cached_tokens: u.cachedInputTokens, cache_write_tokens: u.cachedWriteTokens },
|
|
2450
|
+
completion_tokens_details: { reasoning_tokens: u.reasoningTokens }
|
|
2451
|
+
};
|
|
2452
|
+
}
|
|
2444
2453
|
function fromNativeProvider(provider, options) {
|
|
2445
2454
|
let boundTools = options?.__tools;
|
|
2446
2455
|
const modelName = options?.model ?? provider.defaultModel ?? provider.providerName;
|
|
@@ -2450,8 +2459,9 @@ function fromNativeProvider(provider, options) {
|
|
|
2450
2459
|
invoke: async (messages, _invokeOptions) => {
|
|
2451
2460
|
const link = linkAbortSignal(_invokeOptions);
|
|
2452
2461
|
try {
|
|
2453
|
-
|
|
2462
|
+
let request = buildRequest(messages, boundTools, options, _invokeOptions);
|
|
2454
2463
|
if (link.signal) request.signal = link.signal;
|
|
2464
|
+
request = await applyTransform(request);
|
|
2455
2465
|
const response = await provider.complete(request);
|
|
2456
2466
|
return toBaseChatMessage(response);
|
|
2457
2467
|
} finally {
|
|
@@ -2461,33 +2471,46 @@ function fromNativeProvider(provider, options) {
|
|
|
2461
2471
|
stream: async function* (messages, _invokeOptions) {
|
|
2462
2472
|
const link = linkAbortSignal(_invokeOptions);
|
|
2463
2473
|
try {
|
|
2464
|
-
|
|
2474
|
+
let request = buildRequest(messages, boundTools, options, _invokeOptions);
|
|
2465
2475
|
request.stream = true;
|
|
2466
2476
|
if (link.signal) request.signal = link.signal;
|
|
2477
|
+
request = await applyTransform(request);
|
|
2467
2478
|
let fullContent = "";
|
|
2468
2479
|
let allToolCalls = [];
|
|
2469
2480
|
let lastUsage;
|
|
2470
2481
|
let reasoningBlocks;
|
|
2482
|
+
let reasoningText = "";
|
|
2483
|
+
let finishReason;
|
|
2484
|
+
let responseModel;
|
|
2471
2485
|
const toolCallBuffers = /* @__PURE__ */ new Map();
|
|
2472
2486
|
for await (const chunk of provider.completeStream(request)) {
|
|
2473
2487
|
if (chunk.delta.content) {
|
|
2474
2488
|
fullContent += chunk.delta.content;
|
|
2475
2489
|
yield chunk.delta.content;
|
|
2476
2490
|
}
|
|
2491
|
+
if (chunk.model) responseModel = chunk.model;
|
|
2492
|
+
if (chunk.finishReason) finishReason = chunk.finishReason;
|
|
2477
2493
|
if (chunk.delta.reasoning?.blocks?.length) {
|
|
2478
2494
|
reasoningBlocks = chunk.delta.reasoning.blocks;
|
|
2479
2495
|
}
|
|
2496
|
+
const reasoningDelta = chunk.delta.reasoning?.summary;
|
|
2497
|
+
if (reasoningDelta) {
|
|
2498
|
+
reasoningText += reasoningDelta;
|
|
2499
|
+
yield { type: "reasoning", reasoning_content: reasoningDelta };
|
|
2500
|
+
}
|
|
2480
2501
|
if (chunk.delta.toolCalls) {
|
|
2481
2502
|
for (const tc of chunk.delta.toolCalls) {
|
|
2482
2503
|
if (tc.id) {
|
|
2483
2504
|
const existing = toolCallBuffers.get(tc.id);
|
|
2484
2505
|
if (existing) {
|
|
2485
2506
|
if (tc.arguments) existing.arguments += tc.arguments;
|
|
2507
|
+
if (tc.thoughtSignature) existing.thoughtSignature = tc.thoughtSignature;
|
|
2486
2508
|
} else {
|
|
2487
2509
|
toolCallBuffers.set(tc.id, {
|
|
2488
2510
|
id: tc.id,
|
|
2489
2511
|
name: tc.name ?? "",
|
|
2490
|
-
arguments: tc.arguments ?? ""
|
|
2512
|
+
arguments: tc.arguments ?? "",
|
|
2513
|
+
...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {}
|
|
2491
2514
|
});
|
|
2492
2515
|
}
|
|
2493
2516
|
}
|
|
@@ -2498,8 +2521,18 @@ function fromNativeProvider(provider, options) {
|
|
|
2498
2521
|
if (link.signal?.aborted) return;
|
|
2499
2522
|
allToolCalls = [...toolCallBuffers.values()];
|
|
2500
2523
|
const finalMessage = assembleMessage(fullContent, allToolCalls, lastUsage);
|
|
2501
|
-
if (reasoningBlocks?.length) {
|
|
2502
|
-
finalMessage.reasoning = {
|
|
2524
|
+
if (reasoningBlocks?.length || reasoningText) {
|
|
2525
|
+
finalMessage.reasoning = {
|
|
2526
|
+
...reasoningBlocks?.length ? { blocks: reasoningBlocks } : {},
|
|
2527
|
+
...reasoningText ? { summary: reasoningText } : {}
|
|
2528
|
+
};
|
|
2529
|
+
}
|
|
2530
|
+
if (finishReason || responseModel) {
|
|
2531
|
+
finalMessage.response_metadata = {
|
|
2532
|
+
...finalMessage.response_metadata ?? {},
|
|
2533
|
+
...finishReason ? { finish_reason: finishReason } : {},
|
|
2534
|
+
...responseModel ? { model_name: responseModel } : {}
|
|
2535
|
+
};
|
|
2503
2536
|
}
|
|
2504
2537
|
yield finalMessage;
|
|
2505
2538
|
} finally {
|
|
@@ -2513,6 +2546,11 @@ function fromNativeProvider(provider, options) {
|
|
|
2513
2546
|
}
|
|
2514
2547
|
};
|
|
2515
2548
|
return adapted;
|
|
2549
|
+
async function applyTransform(req) {
|
|
2550
|
+
if (!options?.transformRequest) return req;
|
|
2551
|
+
const out = await options.transformRequest(req);
|
|
2552
|
+
return out ?? req;
|
|
2553
|
+
}
|
|
2516
2554
|
function buildRequest(messages, tools, opts, invokeOptions) {
|
|
2517
2555
|
const req = {
|
|
2518
2556
|
model: opts?.model ?? modelName,
|
|
@@ -2520,6 +2558,10 @@ function fromNativeProvider(provider, options) {
|
|
|
2520
2558
|
};
|
|
2521
2559
|
if (opts?.temperature != null) req.temperature = opts.temperature;
|
|
2522
2560
|
if (opts?.maxTokens != null) req.maxTokens = opts.maxTokens;
|
|
2561
|
+
if (opts?.topP != null) req.topP = opts.topP;
|
|
2562
|
+
if (opts?.stop?.length) req.stop = opts.stop;
|
|
2563
|
+
if (opts?.presencePenalty != null) req.presencePenalty = opts.presencePenalty;
|
|
2564
|
+
if (opts?.frequencyPenalty != null) req.frequencyPenalty = opts.frequencyPenalty;
|
|
2523
2565
|
if (tools?.length) req.tools = tools;
|
|
2524
2566
|
if (opts?.extra) req.extra = opts.extra;
|
|
2525
2567
|
const reasoningOverride = invokeOptions?.reasoning;
|
|
@@ -2572,7 +2614,8 @@ function toUnifiedMessage(msg) {
|
|
|
2572
2614
|
unified.toolCalls = msg.tool_calls.map((tc) => ({
|
|
2573
2615
|
id: tc.id,
|
|
2574
2616
|
name: tc.function?.name ?? tc.name ?? "",
|
|
2575
|
-
arguments: tc.function?.arguments ?? tc.arguments ?? "{}"
|
|
2617
|
+
arguments: tc.function?.arguments ?? tc.arguments ?? "{}",
|
|
2618
|
+
...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {}
|
|
2576
2619
|
}));
|
|
2577
2620
|
}
|
|
2578
2621
|
const reasoning = msg.reasoning;
|
|
@@ -2846,29 +2889,16 @@ function toToolDefinition(tool, strict) {
|
|
|
2846
2889
|
}
|
|
2847
2890
|
return { name, description, parameters, ...useStrict ? { strict: true } : {} };
|
|
2848
2891
|
}
|
|
2892
|
+
function legacyTokenUsage(u) {
|
|
2893
|
+
return { ...toMessageUsage(u), cached_tokens: u.cachedInputTokens, cache_write_tokens: u.cachedWriteTokens };
|
|
2894
|
+
}
|
|
2849
2895
|
function toBaseChatMessage(response) {
|
|
2850
2896
|
const msg = {
|
|
2851
2897
|
role: "assistant",
|
|
2852
2898
|
content: response.content ?? "",
|
|
2853
|
-
usage:
|
|
2854
|
-
prompt_tokens: response.usage.inputTokens,
|
|
2855
|
-
completion_tokens: response.usage.outputTokens,
|
|
2856
|
-
total_tokens: response.usage.totalTokens,
|
|
2857
|
-
prompt_tokens_details: {
|
|
2858
|
-
cached_tokens: response.usage.cachedInputTokens
|
|
2859
|
-
},
|
|
2860
|
-
completion_tokens_details: {
|
|
2861
|
-
reasoning_tokens: response.usage.reasoningTokens
|
|
2862
|
-
}
|
|
2863
|
-
},
|
|
2899
|
+
usage: toMessageUsage(response.usage),
|
|
2864
2900
|
response_metadata: {
|
|
2865
|
-
token_usage:
|
|
2866
|
-
prompt_tokens: response.usage.inputTokens,
|
|
2867
|
-
completion_tokens: response.usage.outputTokens,
|
|
2868
|
-
total_tokens: response.usage.totalTokens,
|
|
2869
|
-
cached_tokens: response.usage.cachedInputTokens,
|
|
2870
|
-
cache_write_tokens: response.usage.cachedWriteTokens
|
|
2871
|
-
},
|
|
2901
|
+
token_usage: legacyTokenUsage(response.usage),
|
|
2872
2902
|
finish_reason: response.finishReason,
|
|
2873
2903
|
model_name: response.model
|
|
2874
2904
|
}
|
|
@@ -2877,7 +2907,8 @@ function toBaseChatMessage(response) {
|
|
|
2877
2907
|
msg.tool_calls = response.toolCalls.map((tc) => ({
|
|
2878
2908
|
id: tc.id,
|
|
2879
2909
|
type: "function",
|
|
2880
|
-
function: { name: tc.name, arguments: tc.arguments }
|
|
2910
|
+
function: { name: tc.name, arguments: tc.arguments },
|
|
2911
|
+
...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {}
|
|
2881
2912
|
}));
|
|
2882
2913
|
}
|
|
2883
2914
|
if (response.reasoning && (response.reasoning.blocks?.length || response.reasoning.summary)) {
|
|
@@ -2891,32 +2922,15 @@ function assembleMessage(content, toolCalls, usage) {
|
|
|
2891
2922
|
content
|
|
2892
2923
|
};
|
|
2893
2924
|
if (usage) {
|
|
2894
|
-
msg.usage =
|
|
2895
|
-
|
|
2896
|
-
completion_tokens: usage.outputTokens,
|
|
2897
|
-
total_tokens: usage.totalTokens,
|
|
2898
|
-
prompt_tokens_details: {
|
|
2899
|
-
cached_tokens: usage.cachedInputTokens
|
|
2900
|
-
},
|
|
2901
|
-
completion_tokens_details: {
|
|
2902
|
-
reasoning_tokens: usage.reasoningTokens
|
|
2903
|
-
}
|
|
2904
|
-
};
|
|
2905
|
-
msg.response_metadata = {
|
|
2906
|
-
token_usage: {
|
|
2907
|
-
prompt_tokens: usage.inputTokens,
|
|
2908
|
-
completion_tokens: usage.outputTokens,
|
|
2909
|
-
total_tokens: usage.totalTokens,
|
|
2910
|
-
cached_tokens: usage.cachedInputTokens,
|
|
2911
|
-
cache_write_tokens: usage.cachedWriteTokens
|
|
2912
|
-
}
|
|
2913
|
-
};
|
|
2925
|
+
msg.usage = toMessageUsage(usage);
|
|
2926
|
+
msg.response_metadata = { token_usage: legacyTokenUsage(usage) };
|
|
2914
2927
|
}
|
|
2915
2928
|
if (toolCalls.length > 0) {
|
|
2916
2929
|
msg.tool_calls = toolCalls.map((tc) => ({
|
|
2917
2930
|
id: tc.id,
|
|
2918
2931
|
type: "function",
|
|
2919
|
-
function: { name: tc.name, arguments: tc.arguments }
|
|
2932
|
+
function: { name: tc.name, arguments: tc.arguments },
|
|
2933
|
+
...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {}
|
|
2920
2934
|
}));
|
|
2921
2935
|
}
|
|
2922
2936
|
return msg;
|
|
@@ -2949,8 +2963,8 @@ function resolveCapabilities(provider) {
|
|
|
2949
2963
|
return {
|
|
2950
2964
|
structuredOutput: "tool_based",
|
|
2951
2965
|
strictToolCalling: false,
|
|
2952
|
-
streaming:
|
|
2953
|
-
//
|
|
2966
|
+
streaming: true,
|
|
2967
|
+
// ConverseStream (AWS event-stream frames)
|
|
2954
2968
|
provider: "bedrock"
|
|
2955
2969
|
};
|
|
2956
2970
|
case "vertex":
|
|
@@ -4656,6 +4670,10 @@ ${append}`;
|
|
|
4656
4670
|
if (chunk && typeof chunk === "object" && chunk.role) {
|
|
4657
4671
|
streamedMessage = chunk;
|
|
4658
4672
|
}
|
|
4673
|
+
if (chunk && typeof chunk === "object" && chunk.type === "reasoning" && typeof chunk.reasoning_content === "string") {
|
|
4674
|
+
onEvent?.({ type: "reasoning", text: chunk.reasoning_content });
|
|
4675
|
+
continue;
|
|
4676
|
+
}
|
|
4659
4677
|
const text = extractText2(chunk);
|
|
4660
4678
|
const isAssembledMessage = Boolean(chunk && typeof chunk === "object" && chunk.role) && text.length > 0 && text === streamedText;
|
|
4661
4679
|
if (text && !isAssembledMessage) {
|
|
@@ -5087,10 +5105,10 @@ function createToolsNode(initialTools, opts) {
|
|
|
5087
5105
|
const toolCallId = tc.id || `${tc.name}_${toolCount + 1}`;
|
|
5088
5106
|
const validatedArgs = validateToolArgs(tool, args);
|
|
5089
5107
|
if (!validatedArgs.ok && resolved.toolResponses.schemaValidation === "strict") {
|
|
5090
|
-
const
|
|
5091
|
-
push({ role: "tool", content:
|
|
5092
|
-
markToolFailure(
|
|
5093
|
-
onEvent?.({ type: "tool_call", phase: "error", name: tc.name, id: tc.id, args, error: { message:
|
|
5108
|
+
const errorMessage2 = `Tool argument validation failed for ${tc.name}: ${validatedArgs.message}`;
|
|
5109
|
+
push({ role: "tool", content: errorMessage2, tool_call_id: toolCallId, name: tc.name });
|
|
5110
|
+
markToolFailure(errorMessage2, tc.name, toolCallId);
|
|
5111
|
+
onEvent?.({ type: "tool_call", phase: "error", name: tc.name, id: tc.id, args, error: { message: errorMessage2 } });
|
|
5094
5112
|
toolCount += 1;
|
|
5095
5113
|
return { status: "error" };
|
|
5096
5114
|
}
|
|
@@ -6101,7 +6119,7 @@ var LEVEL_DEFAULTS = {
|
|
|
6101
6119
|
};
|
|
6102
6120
|
var VALID_LEVELS = ["minimal", "low", "medium", "high"];
|
|
6103
6121
|
var VALID_CADENCES = ["off", "every_turn", "after_tool", "on_branch", "initial_then_after_tool"];
|
|
6104
|
-
var VALID_EFFORTS = ["none", "minimal", "low", "medium", "high"];
|
|
6122
|
+
var VALID_EFFORTS = ["none", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
6105
6123
|
function validateReasoningConfig(input) {
|
|
6106
6124
|
if (!input) return;
|
|
6107
6125
|
if (input.level !== void 0 && !VALID_LEVELS.includes(input.level)) {
|
|
@@ -11536,6 +11554,28 @@ async function runSmartAgentEvalHarness(params) {
|
|
|
11536
11554
|
return results;
|
|
11537
11555
|
}
|
|
11538
11556
|
|
|
11557
|
+
// src/providers/types.ts
|
|
11558
|
+
function emptyUsage() {
|
|
11559
|
+
return {
|
|
11560
|
+
inputTokens: 0,
|
|
11561
|
+
outputTokens: 0,
|
|
11562
|
+
totalTokens: 0,
|
|
11563
|
+
cachedInputTokens: 0,
|
|
11564
|
+
cachedWriteTokens: 0,
|
|
11565
|
+
cachedOutputTokens: 0,
|
|
11566
|
+
reasoningTokens: 0
|
|
11567
|
+
};
|
|
11568
|
+
}
|
|
11569
|
+
var ProviderError = class extends Error {
|
|
11570
|
+
constructor(message, provider, statusCode, responseBody) {
|
|
11571
|
+
super(message);
|
|
11572
|
+
this.provider = provider;
|
|
11573
|
+
this.statusCode = statusCode;
|
|
11574
|
+
this.responseBody = responseBody;
|
|
11575
|
+
this.name = "ProviderError";
|
|
11576
|
+
}
|
|
11577
|
+
};
|
|
11578
|
+
|
|
11539
11579
|
// src/providers/base.ts
|
|
11540
11580
|
var DEFAULT_RETRY = {
|
|
11541
11581
|
maxRetries: 3,
|
|
@@ -11546,6 +11586,56 @@ var BaseProvider = class {
|
|
|
11546
11586
|
constructor() {
|
|
11547
11587
|
this.retryPolicy = DEFAULT_RETRY;
|
|
11548
11588
|
}
|
|
11589
|
+
/** Applies the transport options shared by every provider config. */
|
|
11590
|
+
configureTransport(config) {
|
|
11591
|
+
this.fetchImpl = config.fetch;
|
|
11592
|
+
this.onModelRuleLearned = config.onModelRuleLearned;
|
|
11593
|
+
this.timeoutMs = typeof config.timeoutMs === "number" && config.timeoutMs > 0 ? config.timeoutMs : void 0;
|
|
11594
|
+
}
|
|
11595
|
+
/**
|
|
11596
|
+
* The single HTTP entry point for every provider call site. Uses the
|
|
11597
|
+
* configured `fetch` and applies `timeoutMs`: the timer covers the time until
|
|
11598
|
+
* the response HEADERS arrive and is cleared after that, so a long-running
|
|
11599
|
+
* stream is never cut by it (use the request `signal` to cancel a stream).
|
|
11600
|
+
* A timeout surfaces as a `ProviderError` with status 408. The caller's
|
|
11601
|
+
* `signal` still aborts the request as before.
|
|
11602
|
+
*/
|
|
11603
|
+
async httpFetch(url, init = {}) {
|
|
11604
|
+
const doFetch = this.fetchImpl ?? fetch;
|
|
11605
|
+
const timeoutMs = this.timeoutMs;
|
|
11606
|
+
if (!timeoutMs) return doFetch(url, init);
|
|
11607
|
+
const controller = new AbortController();
|
|
11608
|
+
const outer = init.signal ?? void 0;
|
|
11609
|
+
let timedOut = false;
|
|
11610
|
+
const onOuterAbort = () => controller.abort(outer?.reason);
|
|
11611
|
+
if (outer) {
|
|
11612
|
+
if (outer.aborted) controller.abort(outer.reason);
|
|
11613
|
+
else outer.addEventListener("abort", onOuterAbort, { once: true });
|
|
11614
|
+
}
|
|
11615
|
+
const timer = setTimeout(() => {
|
|
11616
|
+
timedOut = true;
|
|
11617
|
+
controller.abort(new Error(`timed out after ${timeoutMs}ms`));
|
|
11618
|
+
}, timeoutMs);
|
|
11619
|
+
try {
|
|
11620
|
+
const res = await doFetch(url, { ...init, signal: controller.signal });
|
|
11621
|
+
return res;
|
|
11622
|
+
} catch (err) {
|
|
11623
|
+
if (timedOut) {
|
|
11624
|
+
throw new ProviderError(`${this.providerName} request timed out after ${timeoutMs}ms`, this.providerName, 408);
|
|
11625
|
+
}
|
|
11626
|
+
throw err;
|
|
11627
|
+
} finally {
|
|
11628
|
+
clearTimeout(timer);
|
|
11629
|
+
}
|
|
11630
|
+
}
|
|
11631
|
+
/**
|
|
11632
|
+
* Embeds `request.input`. Implemented by the providers that have an
|
|
11633
|
+
* embeddings endpoint (OpenAI, Azure, openai-compatible, Bedrock, Vertex);
|
|
11634
|
+
* the others reject with a 400 ProviderError.
|
|
11635
|
+
*/
|
|
11636
|
+
async embed(_request) {
|
|
11637
|
+
throw new ProviderError(`${this.providerName} does not support embeddings`, this.providerName, 400);
|
|
11638
|
+
}
|
|
11549
11639
|
/**
|
|
11550
11640
|
* Helper concrete providers can wrap their fetch with. Retries 429/5xx
|
|
11551
11641
|
* with exponential backoff and respects Retry-After if the response
|
|
@@ -11587,34 +11677,13 @@ var BaseProvider = class {
|
|
|
11587
11677
|
}
|
|
11588
11678
|
};
|
|
11589
11679
|
|
|
11590
|
-
// src/providers/types.ts
|
|
11591
|
-
function emptyUsage() {
|
|
11592
|
-
return {
|
|
11593
|
-
inputTokens: 0,
|
|
11594
|
-
outputTokens: 0,
|
|
11595
|
-
totalTokens: 0,
|
|
11596
|
-
cachedInputTokens: 0,
|
|
11597
|
-
cachedWriteTokens: 0,
|
|
11598
|
-
cachedOutputTokens: 0,
|
|
11599
|
-
reasoningTokens: 0
|
|
11600
|
-
};
|
|
11601
|
-
}
|
|
11602
|
-
var ProviderError = class extends Error {
|
|
11603
|
-
constructor(message, provider, statusCode, responseBody) {
|
|
11604
|
-
super(message);
|
|
11605
|
-
this.provider = provider;
|
|
11606
|
-
this.statusCode = statusCode;
|
|
11607
|
-
this.responseBody = responseBody;
|
|
11608
|
-
this.name = "ProviderError";
|
|
11609
|
-
}
|
|
11610
|
-
};
|
|
11611
|
-
|
|
11612
11680
|
// src/providers/jev.ts
|
|
11613
11681
|
var JEV_DEFAULT_BASE_URL = "https://api.typesafe.ai";
|
|
11614
11682
|
var JevProvider = class extends BaseProvider {
|
|
11615
11683
|
constructor(config) {
|
|
11616
11684
|
super();
|
|
11617
11685
|
this.providerName = "jev";
|
|
11686
|
+
this.configureTransport(config);
|
|
11618
11687
|
this.apiKey = config.apiKey;
|
|
11619
11688
|
this.baseURL = (config.baseURL ?? JEV_DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
11620
11689
|
this.defaultModel = config.defaultModel;
|
|
@@ -11630,7 +11699,7 @@ var JevProvider = class extends BaseProvider {
|
|
|
11630
11699
|
questions: request.questions
|
|
11631
11700
|
};
|
|
11632
11701
|
const res = await this.doFetchWithRetry(
|
|
11633
|
-
() =>
|
|
11702
|
+
() => this.httpFetch(`${this.baseURL}/v1/systemone`, {
|
|
11634
11703
|
method: "POST",
|
|
11635
11704
|
headers: {
|
|
11636
11705
|
"Content-Type": "application/json",
|
|
@@ -13866,12 +13935,12 @@ function responseCache(config = {}) {
|
|
|
13866
13935
|
};
|
|
13867
13936
|
}
|
|
13868
13937
|
function signRequest(req) {
|
|
13869
|
-
const now = /* @__PURE__ */ new Date();
|
|
13938
|
+
const now = req.now ?? /* @__PURE__ */ new Date();
|
|
13870
13939
|
const dateStamp = toDateStamp(now);
|
|
13871
13940
|
const amzDate = toAmzDate(now);
|
|
13872
13941
|
const parsed = new URL(req.url);
|
|
13873
13942
|
const host = parsed.host;
|
|
13874
|
-
const canonicalUri = parsed.pathname || "/";
|
|
13943
|
+
const canonicalUri = (parsed.pathname || "/").split("/").map((seg) => encodeURIComponent(seg).replace(/[!'()*]/g, (c) => "%" + c.charCodeAt(0).toString(16).toUpperCase())).join("/");
|
|
13875
13944
|
const canonicalQuerystring = sortQueryParams(parsed.searchParams);
|
|
13876
13945
|
const headers = {
|
|
13877
13946
|
...req.headers,
|
|
@@ -15188,98 +15257,805 @@ function languageGuard(config) {
|
|
|
15188
15257
|
// src/index.ts
|
|
15189
15258
|
init_content();
|
|
15190
15259
|
|
|
15191
|
-
// src/
|
|
15192
|
-
|
|
15193
|
-
|
|
15194
|
-
|
|
15195
|
-
|
|
15196
|
-
|
|
15197
|
-
|
|
15198
|
-
|
|
15199
|
-
|
|
15200
|
-
|
|
15201
|
-
|
|
15202
|
-
|
|
15203
|
-
|
|
15204
|
-
|
|
15205
|
-
|
|
15206
|
-
|
|
15207
|
-
|
|
15208
|
-
|
|
15260
|
+
// src/models/model-rules.json
|
|
15261
|
+
var model_rules_default = {
|
|
15262
|
+
version: 1,
|
|
15263
|
+
effortLadder: [
|
|
15264
|
+
"none",
|
|
15265
|
+
"minimal",
|
|
15266
|
+
"low",
|
|
15267
|
+
"medium",
|
|
15268
|
+
"high",
|
|
15269
|
+
"xhigh",
|
|
15270
|
+
"max"
|
|
15271
|
+
],
|
|
15272
|
+
budgets: {
|
|
15273
|
+
minimal: 1024,
|
|
15274
|
+
low: 2048,
|
|
15275
|
+
medium: 8192,
|
|
15276
|
+
high: 16384,
|
|
15277
|
+
xhigh: 24576,
|
|
15278
|
+
max: 32768
|
|
15279
|
+
},
|
|
15280
|
+
geminiBudgets: {
|
|
15281
|
+
minimal: 512,
|
|
15282
|
+
low: 1024,
|
|
15283
|
+
medium: 4096,
|
|
15284
|
+
high: 12e3,
|
|
15285
|
+
xhigh: 24576,
|
|
15286
|
+
max: 24576
|
|
15287
|
+
},
|
|
15288
|
+
rules: [
|
|
15289
|
+
{
|
|
15290
|
+
id: "openai-chat-models",
|
|
15291
|
+
family: "openai",
|
|
15292
|
+
match: "^(?:chatgpt|gpt-[\\d.]+[a-z0-9.-]*?-chat)",
|
|
15293
|
+
reasoning: {
|
|
15294
|
+
style: "none",
|
|
15295
|
+
efforts: [],
|
|
15296
|
+
off: null
|
|
15297
|
+
},
|
|
15298
|
+
sampling: {
|
|
15299
|
+
temperature: "any",
|
|
15300
|
+
topP: true,
|
|
15301
|
+
topK: true,
|
|
15302
|
+
penalties: true,
|
|
15303
|
+
logprobs: true
|
|
15304
|
+
},
|
|
15305
|
+
maxTokensParam: "max_completion_tokens",
|
|
15306
|
+
chatTools: {
|
|
15307
|
+
reasoning: "any"
|
|
15308
|
+
},
|
|
15309
|
+
source: "docs",
|
|
15310
|
+
note: "Chat-tuned *-chat variants are not reasoning models: ordinary sampling, no reasoning field."
|
|
15311
|
+
},
|
|
15312
|
+
{
|
|
15313
|
+
id: "openai-gpt-6-plus",
|
|
15314
|
+
family: "openai",
|
|
15315
|
+
match: "^gpt-?(?:[6-9]|(?!35(?!\\d))[1-9]\\d+)(?:[.-]|$)",
|
|
15316
|
+
reasoning: {
|
|
15317
|
+
style: "effort",
|
|
15318
|
+
efforts: [
|
|
15319
|
+
"none",
|
|
15320
|
+
"low",
|
|
15321
|
+
"medium",
|
|
15322
|
+
"high",
|
|
15323
|
+
"xhigh"
|
|
15324
|
+
],
|
|
15325
|
+
off: "none",
|
|
15326
|
+
responsesEfforts: [
|
|
15327
|
+
"none",
|
|
15328
|
+
"low",
|
|
15329
|
+
"medium",
|
|
15330
|
+
"high",
|
|
15331
|
+
"xhigh",
|
|
15332
|
+
"max"
|
|
15333
|
+
]
|
|
15334
|
+
},
|
|
15335
|
+
sampling: {
|
|
15336
|
+
temperature: "default-only",
|
|
15337
|
+
topP: false,
|
|
15338
|
+
topK: false,
|
|
15339
|
+
penalties: false,
|
|
15340
|
+
logprobs: false
|
|
15341
|
+
},
|
|
15342
|
+
maxTokensParam: "max_completion_tokens",
|
|
15343
|
+
chatTools: {
|
|
15344
|
+
reasoning: "force-none"
|
|
15345
|
+
},
|
|
15346
|
+
source: "verified-2026-10-14",
|
|
15347
|
+
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."
|
|
15348
|
+
},
|
|
15349
|
+
{
|
|
15350
|
+
id: "openai-gpt-5x",
|
|
15351
|
+
family: "openai",
|
|
15352
|
+
match: "^gpt-?5\\.[1-9]",
|
|
15353
|
+
reasoning: {
|
|
15354
|
+
style: "effort",
|
|
15355
|
+
efforts: [
|
|
15356
|
+
"none",
|
|
15357
|
+
"low",
|
|
15358
|
+
"medium",
|
|
15359
|
+
"high",
|
|
15360
|
+
"xhigh"
|
|
15361
|
+
],
|
|
15362
|
+
off: "none",
|
|
15363
|
+
responsesEfforts: [
|
|
15364
|
+
"none",
|
|
15365
|
+
"low",
|
|
15366
|
+
"medium",
|
|
15367
|
+
"high",
|
|
15368
|
+
"xhigh",
|
|
15369
|
+
"max"
|
|
15370
|
+
]
|
|
15371
|
+
},
|
|
15372
|
+
sampling: {
|
|
15373
|
+
temperature: "default-only",
|
|
15374
|
+
topP: false,
|
|
15375
|
+
topK: false,
|
|
15376
|
+
penalties: false,
|
|
15377
|
+
logprobs: false
|
|
15378
|
+
},
|
|
15379
|
+
maxTokensParam: "max_completion_tokens",
|
|
15380
|
+
chatTools: {
|
|
15381
|
+
reasoning: "force-none"
|
|
15382
|
+
},
|
|
15383
|
+
source: "verified-2026-10-14",
|
|
15384
|
+
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."
|
|
15385
|
+
},
|
|
15386
|
+
{
|
|
15387
|
+
id: "openai-gpt-5-base",
|
|
15388
|
+
family: "openai",
|
|
15389
|
+
match: "^gpt-?5(?![.\\d])",
|
|
15390
|
+
reasoning: {
|
|
15391
|
+
style: "effort",
|
|
15392
|
+
efforts: [
|
|
15393
|
+
"minimal",
|
|
15394
|
+
"low",
|
|
15395
|
+
"medium",
|
|
15396
|
+
"high"
|
|
15397
|
+
],
|
|
15398
|
+
off: null
|
|
15399
|
+
},
|
|
15400
|
+
sampling: {
|
|
15401
|
+
temperature: "default-only",
|
|
15402
|
+
topP: false,
|
|
15403
|
+
topK: false,
|
|
15404
|
+
penalties: false,
|
|
15405
|
+
logprobs: false
|
|
15406
|
+
},
|
|
15407
|
+
maxTokensParam: "max_completion_tokens",
|
|
15408
|
+
chatTools: {
|
|
15409
|
+
reasoning: "any"
|
|
15410
|
+
},
|
|
15411
|
+
source: "docs",
|
|
15412
|
+
note: "gpt-5, -mini, -nano, -codex: minimal/low/medium/high, reasoning cannot be turned off (none maps to minimal)."
|
|
15413
|
+
},
|
|
15414
|
+
{
|
|
15415
|
+
id: "openai-o-series",
|
|
15416
|
+
family: "openai",
|
|
15417
|
+
match: "^o[1-9]\\d?(?![a-z0-9])",
|
|
15418
|
+
reasoning: {
|
|
15419
|
+
style: "effort",
|
|
15420
|
+
efforts: [
|
|
15421
|
+
"low",
|
|
15422
|
+
"medium",
|
|
15423
|
+
"high"
|
|
15424
|
+
],
|
|
15425
|
+
off: null
|
|
15426
|
+
},
|
|
15427
|
+
sampling: {
|
|
15428
|
+
temperature: "default-only",
|
|
15429
|
+
topP: false,
|
|
15430
|
+
topK: false,
|
|
15431
|
+
penalties: false,
|
|
15432
|
+
logprobs: false
|
|
15433
|
+
},
|
|
15434
|
+
maxTokensParam: "max_completion_tokens",
|
|
15435
|
+
chatTools: {
|
|
15436
|
+
reasoning: "any"
|
|
15437
|
+
},
|
|
15438
|
+
source: "docs",
|
|
15439
|
+
note: "o1/o3/o4 family: low/medium/high, no sampling overrides."
|
|
15440
|
+
},
|
|
15441
|
+
{
|
|
15442
|
+
id: "openai-gpt-oss",
|
|
15443
|
+
family: "openai",
|
|
15444
|
+
match: "^gpt-?oss",
|
|
15445
|
+
reasoning: {
|
|
15446
|
+
style: "effort",
|
|
15447
|
+
efforts: [
|
|
15448
|
+
"low",
|
|
15449
|
+
"medium",
|
|
15450
|
+
"high"
|
|
15451
|
+
],
|
|
15452
|
+
off: null
|
|
15453
|
+
},
|
|
15454
|
+
sampling: {
|
|
15455
|
+
temperature: "any",
|
|
15456
|
+
topP: true,
|
|
15457
|
+
topK: true,
|
|
15458
|
+
penalties: true,
|
|
15459
|
+
logprobs: true
|
|
15460
|
+
},
|
|
15461
|
+
maxTokensParam: "max_tokens",
|
|
15462
|
+
chatTools: {
|
|
15463
|
+
reasoning: "any"
|
|
15464
|
+
},
|
|
15465
|
+
source: "docs",
|
|
15466
|
+
note: "Open-weight gpt-oss: low/medium/high; sampling and max_tokens behave like an ordinary chat model."
|
|
15467
|
+
},
|
|
15468
|
+
{
|
|
15469
|
+
id: "openai-legacy-gpt",
|
|
15470
|
+
family: "openai",
|
|
15471
|
+
match: "^(?:gpt-?(?:[0-4]|35)(?![0-9])|text-|davinci|babbage)",
|
|
15472
|
+
reasoning: {
|
|
15473
|
+
style: "none",
|
|
15474
|
+
efforts: [],
|
|
15475
|
+
off: null
|
|
15476
|
+
},
|
|
15477
|
+
sampling: {
|
|
15478
|
+
temperature: "any",
|
|
15479
|
+
topP: true,
|
|
15480
|
+
topK: true,
|
|
15481
|
+
penalties: true,
|
|
15482
|
+
logprobs: true
|
|
15483
|
+
},
|
|
15484
|
+
maxTokensParam: "max_tokens",
|
|
15485
|
+
chatTools: {
|
|
15486
|
+
reasoning: "any"
|
|
15487
|
+
},
|
|
15488
|
+
source: "docs",
|
|
15489
|
+
note: "gpt-4o, gpt-4.1, gpt-3.5 and older: no reasoning, ordinary sampling."
|
|
15490
|
+
},
|
|
15491
|
+
{
|
|
15492
|
+
id: "openai-compatible-toggle",
|
|
15493
|
+
family: "openai",
|
|
15494
|
+
match: "^(?:deepseek-(?:r\\d|reasoner)|qwq|qwen-?3)",
|
|
15495
|
+
reasoning: {
|
|
15496
|
+
style: "toggle",
|
|
15497
|
+
efforts: [
|
|
15498
|
+
"none",
|
|
15499
|
+
"minimal",
|
|
15500
|
+
"low",
|
|
15501
|
+
"medium",
|
|
15502
|
+
"high",
|
|
15503
|
+
"xhigh",
|
|
15504
|
+
"max"
|
|
15505
|
+
],
|
|
15506
|
+
off: "none"
|
|
15507
|
+
},
|
|
15508
|
+
sampling: {
|
|
15509
|
+
temperature: "any",
|
|
15510
|
+
topP: true,
|
|
15511
|
+
topK: true,
|
|
15512
|
+
penalties: true,
|
|
15513
|
+
logprobs: true
|
|
15514
|
+
},
|
|
15515
|
+
maxTokensParam: "max_tokens",
|
|
15516
|
+
chatTools: {
|
|
15517
|
+
reasoning: "any"
|
|
15518
|
+
},
|
|
15519
|
+
source: "docs",
|
|
15520
|
+
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)."
|
|
15521
|
+
},
|
|
15522
|
+
{
|
|
15523
|
+
id: "openai-default",
|
|
15524
|
+
family: "openai",
|
|
15525
|
+
match: ".*",
|
|
15526
|
+
reasoning: {
|
|
15527
|
+
style: "effort",
|
|
15528
|
+
efforts: [
|
|
15529
|
+
"none",
|
|
15530
|
+
"minimal",
|
|
15531
|
+
"low",
|
|
15532
|
+
"medium",
|
|
15533
|
+
"high",
|
|
15534
|
+
"xhigh",
|
|
15535
|
+
"max"
|
|
15536
|
+
],
|
|
15537
|
+
off: "none"
|
|
15538
|
+
},
|
|
15539
|
+
sampling: {
|
|
15540
|
+
temperature: "any",
|
|
15541
|
+
topP: true,
|
|
15542
|
+
topK: true,
|
|
15543
|
+
penalties: true,
|
|
15544
|
+
logprobs: true
|
|
15545
|
+
},
|
|
15546
|
+
maxTokensParam: "max_tokens",
|
|
15547
|
+
chatTools: {
|
|
15548
|
+
reasoning: "any"
|
|
15549
|
+
},
|
|
15550
|
+
source: "docs",
|
|
15551
|
+
note: "Permissive default for unknown OpenAI-wire models: pass what the caller asked; the provider learns from 400s."
|
|
15552
|
+
},
|
|
15553
|
+
{
|
|
15554
|
+
id: "claude-haiku-5",
|
|
15555
|
+
family: "anthropic",
|
|
15556
|
+
match: "^claude-(?:haiku-5|5(?:-\\d+)?-haiku)(?!\\d)",
|
|
15557
|
+
reasoning: {
|
|
15558
|
+
style: "adaptive",
|
|
15559
|
+
efforts: [
|
|
15560
|
+
"low",
|
|
15561
|
+
"medium",
|
|
15562
|
+
"high",
|
|
15563
|
+
"xhigh",
|
|
15564
|
+
"max"
|
|
15565
|
+
],
|
|
15566
|
+
off: "disabled"
|
|
15567
|
+
},
|
|
15568
|
+
sampling: {
|
|
15569
|
+
temperature: "unsupported",
|
|
15570
|
+
topP: false,
|
|
15571
|
+
topK: false,
|
|
15572
|
+
penalties: false,
|
|
15573
|
+
logprobs: false
|
|
15574
|
+
},
|
|
15575
|
+
maxTokensParam: "max_tokens",
|
|
15576
|
+
chatTools: {
|
|
15577
|
+
reasoning: "any"
|
|
15578
|
+
},
|
|
15579
|
+
source: "verified-2026-10-14",
|
|
15580
|
+
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."
|
|
15581
|
+
},
|
|
15582
|
+
{
|
|
15583
|
+
id: "claude-sonnet-5",
|
|
15584
|
+
family: "anthropic",
|
|
15585
|
+
match: "^claude-(?:sonnet-5|5(?:-\\d+)?-sonnet)(?!\\d)",
|
|
15586
|
+
reasoning: {
|
|
15587
|
+
style: "adaptive",
|
|
15588
|
+
efforts: [
|
|
15589
|
+
"low",
|
|
15590
|
+
"medium",
|
|
15591
|
+
"high",
|
|
15592
|
+
"xhigh",
|
|
15593
|
+
"max"
|
|
15594
|
+
],
|
|
15595
|
+
off: "between_tools"
|
|
15596
|
+
},
|
|
15597
|
+
sampling: {
|
|
15598
|
+
temperature: "unsupported",
|
|
15599
|
+
topP: false,
|
|
15600
|
+
topK: false,
|
|
15601
|
+
penalties: false,
|
|
15602
|
+
logprobs: false
|
|
15603
|
+
},
|
|
15604
|
+
maxTokensParam: "max_tokens",
|
|
15605
|
+
chatTools: {
|
|
15606
|
+
reasoning: "any"
|
|
15607
|
+
},
|
|
15608
|
+
source: "verified-2026-10-14",
|
|
15609
|
+
note: "Claude Sonnet 5.x: adaptive + output_config.effort. thinking:{type:disabled} is rejected; off = thinking:{type:between_tools}. Sampling params are rejected."
|
|
15610
|
+
},
|
|
15611
|
+
{
|
|
15612
|
+
id: "claude-opus-5",
|
|
15613
|
+
family: "anthropic",
|
|
15614
|
+
match: "^claude-(?:opus-5|5(?:-\\d+)?-opus)(?!\\d)",
|
|
15615
|
+
reasoning: {
|
|
15616
|
+
style: "adaptive",
|
|
15617
|
+
efforts: [
|
|
15618
|
+
"low",
|
|
15619
|
+
"medium",
|
|
15620
|
+
"high",
|
|
15621
|
+
"xhigh",
|
|
15622
|
+
"max"
|
|
15623
|
+
],
|
|
15624
|
+
off: null
|
|
15625
|
+
},
|
|
15626
|
+
sampling: {
|
|
15627
|
+
temperature: "unsupported",
|
|
15628
|
+
topP: false,
|
|
15629
|
+
topK: false,
|
|
15630
|
+
penalties: false,
|
|
15631
|
+
logprobs: false
|
|
15632
|
+
},
|
|
15633
|
+
maxTokensParam: "max_tokens",
|
|
15634
|
+
chatTools: {
|
|
15635
|
+
reasoning: "any"
|
|
15636
|
+
},
|
|
15637
|
+
source: "verified-2026-10-14",
|
|
15638
|
+
note: "Claude Opus 5.x: adaptive + output_config.effort; thinking cannot be turned off (none maps to the lowest effort). Sampling params are rejected."
|
|
15639
|
+
},
|
|
15640
|
+
{
|
|
15641
|
+
id: "claude-fable",
|
|
15642
|
+
family: "anthropic",
|
|
15643
|
+
match: "^claude-fable",
|
|
15644
|
+
reasoning: {
|
|
15645
|
+
style: "adaptive",
|
|
15646
|
+
efforts: [
|
|
15647
|
+
"low",
|
|
15648
|
+
"medium",
|
|
15649
|
+
"high",
|
|
15650
|
+
"xhigh",
|
|
15651
|
+
"max"
|
|
15652
|
+
],
|
|
15653
|
+
off: null
|
|
15654
|
+
},
|
|
15655
|
+
sampling: {
|
|
15656
|
+
temperature: "unsupported",
|
|
15657
|
+
topP: false,
|
|
15658
|
+
topK: false,
|
|
15659
|
+
penalties: false,
|
|
15660
|
+
logprobs: false
|
|
15661
|
+
},
|
|
15662
|
+
maxTokensParam: "max_tokens",
|
|
15663
|
+
chatTools: {
|
|
15664
|
+
reasoning: "any"
|
|
15665
|
+
},
|
|
15666
|
+
source: "docs",
|
|
15667
|
+
note: "Claude Fable line: treated like the 5.x adaptive models."
|
|
15668
|
+
},
|
|
15669
|
+
{
|
|
15670
|
+
id: "claude-4-7",
|
|
15671
|
+
family: "anthropic",
|
|
15672
|
+
match: "^claude-(?:(?:opus|sonnet|haiku)-4[-.]7|4[-.]7-(?:opus|sonnet|haiku))(?!\\d)",
|
|
15673
|
+
reasoning: {
|
|
15674
|
+
style: "adaptive",
|
|
15675
|
+
efforts: [
|
|
15676
|
+
"low",
|
|
15677
|
+
"medium",
|
|
15678
|
+
"high",
|
|
15679
|
+
"xhigh",
|
|
15680
|
+
"max"
|
|
15681
|
+
],
|
|
15682
|
+
off: "disabled"
|
|
15683
|
+
},
|
|
15684
|
+
sampling: {
|
|
15685
|
+
temperature: "thinking-requires-1",
|
|
15686
|
+
topP: true,
|
|
15687
|
+
topK: true,
|
|
15688
|
+
penalties: true,
|
|
15689
|
+
logprobs: true
|
|
15690
|
+
},
|
|
15691
|
+
maxTokensParam: "max_tokens",
|
|
15692
|
+
chatTools: {
|
|
15693
|
+
reasoning: "any"
|
|
15694
|
+
},
|
|
15695
|
+
source: "docs",
|
|
15696
|
+
note: "Claude 4.7: adaptive thinking, low/medium/high/xhigh/max."
|
|
15697
|
+
},
|
|
15698
|
+
{
|
|
15699
|
+
id: "claude-4-6",
|
|
15700
|
+
family: "anthropic",
|
|
15701
|
+
match: "^claude-(?:(?:opus|sonnet|haiku)-4[-.]6|4[-.]6-(?:opus|sonnet|haiku))(?!\\d)",
|
|
15702
|
+
reasoning: {
|
|
15703
|
+
style: "adaptive",
|
|
15704
|
+
efforts: [
|
|
15705
|
+
"low",
|
|
15706
|
+
"medium",
|
|
15707
|
+
"high",
|
|
15708
|
+
"max"
|
|
15709
|
+
],
|
|
15710
|
+
off: "disabled"
|
|
15711
|
+
},
|
|
15712
|
+
sampling: {
|
|
15713
|
+
temperature: "thinking-requires-1",
|
|
15714
|
+
topP: true,
|
|
15715
|
+
topK: true,
|
|
15716
|
+
penalties: true,
|
|
15717
|
+
logprobs: true
|
|
15718
|
+
},
|
|
15719
|
+
maxTokensParam: "max_tokens",
|
|
15720
|
+
chatTools: {
|
|
15721
|
+
reasoning: "any"
|
|
15722
|
+
},
|
|
15723
|
+
source: "docs",
|
|
15724
|
+
note: "Claude 4.6: adaptive thinking, low/medium/high/max (no xhigh)."
|
|
15725
|
+
},
|
|
15726
|
+
{
|
|
15727
|
+
id: "claude-legacy-budget",
|
|
15728
|
+
family: "anthropic",
|
|
15729
|
+
match: "^claude-(?:3|4-|(?:opus|sonnet|haiku)-4)",
|
|
15730
|
+
reasoning: {
|
|
15731
|
+
style: "budget",
|
|
15732
|
+
efforts: [
|
|
15733
|
+
"none",
|
|
15734
|
+
"minimal",
|
|
15735
|
+
"low",
|
|
15736
|
+
"medium",
|
|
15737
|
+
"high",
|
|
15738
|
+
"xhigh",
|
|
15739
|
+
"max"
|
|
15740
|
+
],
|
|
15741
|
+
off: null
|
|
15742
|
+
},
|
|
15743
|
+
sampling: {
|
|
15744
|
+
temperature: "thinking-requires-1",
|
|
15745
|
+
topP: true,
|
|
15746
|
+
topK: true,
|
|
15747
|
+
penalties: true,
|
|
15748
|
+
logprobs: true
|
|
15749
|
+
},
|
|
15750
|
+
maxTokensParam: "max_tokens",
|
|
15751
|
+
chatTools: {
|
|
15752
|
+
reasoning: "any"
|
|
15753
|
+
},
|
|
15754
|
+
source: "docs",
|
|
15755
|
+
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."
|
|
15756
|
+
},
|
|
15757
|
+
{
|
|
15758
|
+
id: "anthropic-default",
|
|
15759
|
+
family: "anthropic",
|
|
15760
|
+
match: ".*",
|
|
15761
|
+
reasoning: {
|
|
15762
|
+
style: "budget",
|
|
15763
|
+
efforts: [
|
|
15764
|
+
"none",
|
|
15765
|
+
"minimal",
|
|
15766
|
+
"low",
|
|
15767
|
+
"medium",
|
|
15768
|
+
"high",
|
|
15769
|
+
"xhigh",
|
|
15770
|
+
"max"
|
|
15771
|
+
],
|
|
15772
|
+
off: null
|
|
15773
|
+
},
|
|
15774
|
+
sampling: {
|
|
15775
|
+
temperature: "thinking-requires-1",
|
|
15776
|
+
topP: true,
|
|
15777
|
+
topK: true,
|
|
15778
|
+
penalties: true,
|
|
15779
|
+
logprobs: true
|
|
15780
|
+
},
|
|
15781
|
+
maxTokensParam: "max_tokens",
|
|
15782
|
+
chatTools: {
|
|
15783
|
+
reasoning: "any"
|
|
15784
|
+
},
|
|
15785
|
+
source: "docs",
|
|
15786
|
+
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."
|
|
15787
|
+
},
|
|
15788
|
+
{
|
|
15789
|
+
id: "gemini-budget",
|
|
15790
|
+
family: "gemini",
|
|
15791
|
+
match: "^gemini",
|
|
15792
|
+
reasoning: {
|
|
15793
|
+
style: "budget",
|
|
15794
|
+
efforts: [
|
|
15795
|
+
"none",
|
|
15796
|
+
"minimal",
|
|
15797
|
+
"low",
|
|
15798
|
+
"medium",
|
|
15799
|
+
"high",
|
|
15800
|
+
"xhigh",
|
|
15801
|
+
"max"
|
|
15802
|
+
],
|
|
15803
|
+
off: "none"
|
|
15804
|
+
},
|
|
15805
|
+
sampling: {
|
|
15806
|
+
temperature: "any",
|
|
15807
|
+
topP: true,
|
|
15808
|
+
topK: true,
|
|
15809
|
+
penalties: true,
|
|
15810
|
+
logprobs: true
|
|
15811
|
+
},
|
|
15812
|
+
maxTokensParam: "max_tokens",
|
|
15813
|
+
chatTools: {
|
|
15814
|
+
reasoning: "any"
|
|
15815
|
+
},
|
|
15816
|
+
source: "docs",
|
|
15817
|
+
note: "Gemini 2.5-style thinkingBudget; effort maps to a token budget, none = budget 0."
|
|
15818
|
+
},
|
|
15819
|
+
{
|
|
15820
|
+
id: "gemini-default",
|
|
15821
|
+
family: "gemini",
|
|
15822
|
+
match: ".*",
|
|
15823
|
+
reasoning: {
|
|
15824
|
+
style: "budget",
|
|
15825
|
+
efforts: [
|
|
15826
|
+
"none",
|
|
15827
|
+
"minimal",
|
|
15828
|
+
"low",
|
|
15829
|
+
"medium",
|
|
15830
|
+
"high",
|
|
15831
|
+
"xhigh",
|
|
15832
|
+
"max"
|
|
15833
|
+
],
|
|
15834
|
+
off: "none"
|
|
15835
|
+
},
|
|
15836
|
+
sampling: {
|
|
15837
|
+
temperature: "any",
|
|
15838
|
+
topP: true,
|
|
15839
|
+
topK: true,
|
|
15840
|
+
penalties: true,
|
|
15841
|
+
logprobs: true
|
|
15842
|
+
},
|
|
15843
|
+
maxTokensParam: "max_tokens",
|
|
15844
|
+
chatTools: {
|
|
15845
|
+
reasoning: "any"
|
|
15846
|
+
},
|
|
15847
|
+
source: "docs",
|
|
15848
|
+
note: "Permissive default for unknown Gemini-wire models."
|
|
15849
|
+
},
|
|
15850
|
+
{
|
|
15851
|
+
id: "other-default",
|
|
15852
|
+
family: "other",
|
|
15853
|
+
match: ".*",
|
|
15854
|
+
reasoning: {
|
|
15855
|
+
style: "effort",
|
|
15856
|
+
efforts: [
|
|
15857
|
+
"none",
|
|
15858
|
+
"minimal",
|
|
15859
|
+
"low",
|
|
15860
|
+
"medium",
|
|
15861
|
+
"high",
|
|
15862
|
+
"xhigh",
|
|
15863
|
+
"max"
|
|
15864
|
+
],
|
|
15865
|
+
off: "none"
|
|
15866
|
+
},
|
|
15867
|
+
sampling: {
|
|
15868
|
+
temperature: "any",
|
|
15869
|
+
topP: true,
|
|
15870
|
+
topK: true,
|
|
15871
|
+
penalties: true,
|
|
15872
|
+
logprobs: true
|
|
15873
|
+
},
|
|
15874
|
+
maxTokensParam: "max_tokens",
|
|
15875
|
+
chatTools: {
|
|
15876
|
+
reasoning: "any"
|
|
15877
|
+
},
|
|
15878
|
+
source: "docs",
|
|
15879
|
+
note: "Permissive default for model families the SDK has no rules for."
|
|
15209
15880
|
}
|
|
15210
|
-
|
|
15211
|
-
|
|
15212
|
-
|
|
15881
|
+
]
|
|
15882
|
+
};
|
|
15883
|
+
|
|
15884
|
+
// src/models/rules.ts
|
|
15885
|
+
var MODEL_RULES = model_rules_default;
|
|
15886
|
+
var LADDER = MODEL_RULES.effortLadder;
|
|
15887
|
+
var compiled = /* @__PURE__ */ new Map();
|
|
15888
|
+
function regexFor(rule) {
|
|
15889
|
+
let re = compiled.get(rule.id);
|
|
15890
|
+
if (!re) {
|
|
15891
|
+
re = new RegExp(rule.match, "i");
|
|
15892
|
+
compiled.set(rule.id, re);
|
|
15893
|
+
}
|
|
15894
|
+
return re;
|
|
15895
|
+
}
|
|
15896
|
+
var GATEWAY_PREFIX = /^(?:(?:global|us|eu|apac|jp|au|ca|us-gov)\.)?(?:(?:openai|anthropic|google|meta|amazon|deepseek|qwen|mistral|cohere|ai21)\.)?/;
|
|
15897
|
+
function modelIdCandidates(model) {
|
|
15898
|
+
if (!model) return [];
|
|
15899
|
+
const lower = String(model).trim().toLowerCase();
|
|
15900
|
+
const last = lower.split("/").pop() ?? lower;
|
|
15901
|
+
const out = [];
|
|
15902
|
+
for (const id of [lower, last]) {
|
|
15903
|
+
for (const c of [id, id.replace(GATEWAY_PREFIX, "")]) {
|
|
15904
|
+
if (c && !out.includes(c)) out.push(c);
|
|
15213
15905
|
}
|
|
15214
|
-
} finally {
|
|
15215
|
-
reader.cancel().catch(() => void 0);
|
|
15216
|
-
reader.releaseLock();
|
|
15217
15906
|
}
|
|
15907
|
+
return out;
|
|
15218
15908
|
}
|
|
15219
|
-
|
|
15220
|
-
|
|
15221
|
-
|
|
15222
|
-
|
|
15223
|
-
|
|
15224
|
-
|
|
15225
|
-
|
|
15226
|
-
|
|
15227
|
-
|
|
15228
|
-
|
|
15229
|
-
|
|
15230
|
-
|
|
15231
|
-
|
|
15232
|
-
|
|
15233
|
-
|
|
15234
|
-
value = line.slice(colonIdx + 1);
|
|
15235
|
-
if (value.startsWith(" ")) value = value.slice(1);
|
|
15236
|
-
}
|
|
15237
|
-
switch (field) {
|
|
15238
|
-
case "event":
|
|
15239
|
-
event = value;
|
|
15240
|
-
break;
|
|
15241
|
-
case "data":
|
|
15242
|
-
dataLines.push(value);
|
|
15243
|
-
break;
|
|
15244
|
-
case "id":
|
|
15245
|
-
id = value;
|
|
15246
|
-
break;
|
|
15247
|
-
case "retry": {
|
|
15248
|
-
const n = parseInt(value, 10);
|
|
15249
|
-
if (!isNaN(n)) retry = n;
|
|
15250
|
-
break;
|
|
15251
|
-
}
|
|
15909
|
+
var OPENAI_WIRE = /* @__PURE__ */ new Set(["openai", "azure", "openai-compatible", "together", "openrouter", "groq", "fireworks", "ollama", "vllm", "litellm", "mistral", "deepseek", "xai", "jev"]);
|
|
15910
|
+
function familiesFor(provider) {
|
|
15911
|
+
const p = (provider ?? "").toLowerCase();
|
|
15912
|
+
if (OPENAI_WIRE.has(p)) return ["openai"];
|
|
15913
|
+
if (p === "anthropic") return ["anthropic"];
|
|
15914
|
+
if (p === "bedrock") return ["anthropic", "openai", "other"];
|
|
15915
|
+
if (p === "vertex" || p === "gemini" || p === "google") return ["gemini", "anthropic"];
|
|
15916
|
+
return ["openai", "anthropic", "gemini", "other"];
|
|
15917
|
+
}
|
|
15918
|
+
function matchRule(family, ids, allowDefault) {
|
|
15919
|
+
for (const rule of MODEL_RULES.rules) {
|
|
15920
|
+
if (rule.family !== family) continue;
|
|
15921
|
+
if (rule.match === ".*") {
|
|
15922
|
+
if (allowDefault) return rule;
|
|
15923
|
+
continue;
|
|
15252
15924
|
}
|
|
15925
|
+
const re = regexFor(rule);
|
|
15926
|
+
if (ids.some((id) => re.test(id))) return rule;
|
|
15253
15927
|
}
|
|
15254
|
-
|
|
15255
|
-
return { event, data: dataLines.join("\n"), id, retry };
|
|
15928
|
+
return void 0;
|
|
15256
15929
|
}
|
|
15257
|
-
|
|
15258
|
-
|
|
15259
|
-
|
|
15260
|
-
|
|
15261
|
-
|
|
15930
|
+
function mergeRulePatch(base, patch) {
|
|
15931
|
+
if (!patch) return base;
|
|
15932
|
+
const out = { ...base };
|
|
15933
|
+
if (patch.reasoning) out.reasoning = { ...base.reasoning ?? {}, ...patch.reasoning };
|
|
15934
|
+
if (patch.sampling) out.sampling = { ...base.sampling ?? {}, ...patch.sampling };
|
|
15935
|
+
if (patch.chatTools) out.chatTools = { ...base.chatTools ?? {}, ...patch.chatTools };
|
|
15936
|
+
if (patch.maxTokensParam) out.maxTokensParam = patch.maxTokensParam;
|
|
15937
|
+
if (patch.dropParams) out.dropParams = [.../* @__PURE__ */ new Set([...base.dropParams ?? [], ...patch.dropParams])];
|
|
15938
|
+
return out;
|
|
15939
|
+
}
|
|
15940
|
+
var LEARNED_MAX = 500;
|
|
15941
|
+
var learned = /* @__PURE__ */ new Map();
|
|
15942
|
+
function learnedKey(provider, model, scope) {
|
|
15943
|
+
return `${(provider ?? "").toLowerCase()}@${scope ?? ""}::${(model ?? "").trim().toLowerCase()}`;
|
|
15944
|
+
}
|
|
15945
|
+
function rememberModelRulePatch(provider, model, patch, scope) {
|
|
15946
|
+
const key = learnedKey(provider, model, scope);
|
|
15947
|
+
const merged = mergeRulePatch(learned.get(key)?.patch ?? {}, patch);
|
|
15948
|
+
learned.delete(key);
|
|
15949
|
+
learned.set(key, { provider: provider.toLowerCase(), model: model.trim().toLowerCase(), scope, patch: merged });
|
|
15950
|
+
if (learned.size > LEARNED_MAX) learned.delete(learned.keys().next().value);
|
|
15951
|
+
}
|
|
15952
|
+
function getLearnedModelRulePatch(provider, model, scope) {
|
|
15953
|
+
return learned.get(learnedKey(provider, model, scope))?.patch;
|
|
15954
|
+
}
|
|
15955
|
+
function listLearnedModelRules() {
|
|
15956
|
+
return [...learned.values()].map((e) => ({ ...e }));
|
|
15957
|
+
}
|
|
15958
|
+
function clearLearnedModelRules() {
|
|
15959
|
+
learned.clear();
|
|
15960
|
+
}
|
|
15961
|
+
function resolveModelRule(opts) {
|
|
15962
|
+
const families = familiesFor(opts.provider);
|
|
15963
|
+
const ids = modelIdCandidates(opts.model);
|
|
15964
|
+
let rule;
|
|
15965
|
+
for (const family of families) {
|
|
15966
|
+
rule = matchRule(family, ids, false);
|
|
15967
|
+
if (rule) break;
|
|
15968
|
+
}
|
|
15969
|
+
let isDefault = false;
|
|
15970
|
+
if (!rule) {
|
|
15971
|
+
isDefault = true;
|
|
15972
|
+
rule = matchRule(families[0], ids, true) ?? MODEL_RULES.rules[MODEL_RULES.rules.length - 1];
|
|
15973
|
+
}
|
|
15974
|
+
let effective = rule;
|
|
15975
|
+
const known = opts.model ? learned.get(learnedKey(opts.provider, opts.model, opts.scope))?.patch : void 0;
|
|
15976
|
+
if (known) effective = mergeRulePatch(effective, known);
|
|
15977
|
+
if (opts.patch) effective = mergeRulePatch(effective, opts.patch);
|
|
15978
|
+
return { ...effective, matchedRuleId: rule.id, isDefault, learned: !!known };
|
|
15979
|
+
}
|
|
15980
|
+
function mapReasoningEffort(rule, effort, endpoint = "chat") {
|
|
15981
|
+
const efforts = endpoint === "responses" && rule.reasoning.responsesEfforts || rule.reasoning.efforts;
|
|
15982
|
+
if (rule.reasoning.style === "none" || efforts.length === 0) return { mapped: true };
|
|
15983
|
+
const supported = LADDER.filter((e) => efforts.includes(e));
|
|
15984
|
+
if (supported.includes(effort)) return { effort, mapped: false };
|
|
15985
|
+
if (effort === "none") {
|
|
15986
|
+
const off = rule.reasoning.off;
|
|
15987
|
+
if (off && off !== "none") return { off, mapped: true };
|
|
15988
|
+
const lowest = supported.find((e) => e !== "none");
|
|
15989
|
+
return lowest ? { effort: lowest, mapped: true } : { mapped: true };
|
|
15990
|
+
}
|
|
15991
|
+
const at = LADDER.indexOf(effort);
|
|
15992
|
+
if (at < 0) return { mapped: true };
|
|
15993
|
+
for (let i = at - 1; i >= 1; i--) if (supported.includes(LADDER[i])) return { effort: LADDER[i], mapped: true };
|
|
15994
|
+
for (let i = at + 1; i < LADDER.length; i++) if (supported.includes(LADDER[i])) return { effort: LADDER[i], mapped: true };
|
|
15995
|
+
return supported.includes("none") ? { effort: "none", mapped: true } : { mapped: true };
|
|
15996
|
+
}
|
|
15997
|
+
function allowsSampling(rule, field, value, thinkingOn = false) {
|
|
15998
|
+
const s = rule.sampling;
|
|
15999
|
+
switch (field) {
|
|
16000
|
+
case "temperature":
|
|
16001
|
+
switch (s.temperature) {
|
|
16002
|
+
case "any":
|
|
16003
|
+
return true;
|
|
16004
|
+
case "unsupported":
|
|
16005
|
+
return false;
|
|
16006
|
+
// The default is what the server applies anyway, so it is never sent.
|
|
16007
|
+
case "default-only":
|
|
16008
|
+
return false;
|
|
16009
|
+
case "thinking-requires-1":
|
|
16010
|
+
return !thinkingOn || value === 1;
|
|
16011
|
+
}
|
|
16012
|
+
return true;
|
|
16013
|
+
// Anthropic's thinking restriction covers top_p / top_k as well as temperature.
|
|
16014
|
+
case "topP":
|
|
16015
|
+
return s.topP && !(thinkingOn && s.temperature === "thinking-requires-1");
|
|
16016
|
+
case "topK":
|
|
16017
|
+
return s.topK && !(thinkingOn && s.temperature === "thinking-requires-1");
|
|
16018
|
+
case "presencePenalty":
|
|
16019
|
+
case "frequencyPenalty":
|
|
16020
|
+
return s.penalties;
|
|
16021
|
+
case "logprobs":
|
|
16022
|
+
return s.logprobs;
|
|
16023
|
+
}
|
|
16024
|
+
}
|
|
16025
|
+
function applyDropParams(body, rule) {
|
|
16026
|
+
for (const p of rule.dropParams ?? []) {
|
|
16027
|
+
const dot = p.indexOf(".");
|
|
16028
|
+
if (dot < 0) delete body[p];
|
|
16029
|
+
else if (body[p.slice(0, dot)] && typeof body[p.slice(0, dot)] === "object") delete body[p.slice(0, dot)][p.slice(dot + 1)];
|
|
16030
|
+
}
|
|
16031
|
+
}
|
|
16032
|
+
function effortBudget(effort, table = "anthropic") {
|
|
16033
|
+
if (effort === "none") return 0;
|
|
16034
|
+
return (table === "gemini" ? MODEL_RULES.geminiBudgets : MODEL_RULES.budgets)[effort] ?? 0;
|
|
16035
|
+
}
|
|
16036
|
+
|
|
16037
|
+
// src/providers/utils/reasoning.ts
|
|
16038
|
+
var ANTHROPIC_EFFORT_BUDGET = {
|
|
16039
|
+
// 0 = off. `applyAnthropicReasoning` bails on a falsy budget and emits no
|
|
16040
|
+
// thinking block, which on Anthropic IS off — thinking there is opt-in.
|
|
15262
16041
|
none: 0,
|
|
15263
|
-
|
|
15264
|
-
low: 2048,
|
|
15265
|
-
medium: 8192,
|
|
15266
|
-
high: 16384
|
|
16042
|
+
...MODEL_RULES.budgets
|
|
15267
16043
|
};
|
|
15268
16044
|
var GEMINI_EFFORT_BUDGET = {
|
|
15269
16045
|
// 0 is Gemini's own documented spelling for "do not think", and unlike
|
|
15270
16046
|
// Anthropic it has to be SENT — hence `applyGeminiReasoning` testing for null
|
|
15271
16047
|
// rather than falsiness.
|
|
15272
16048
|
none: 0,
|
|
15273
|
-
|
|
15274
|
-
low: 1024,
|
|
15275
|
-
medium: 4096,
|
|
15276
|
-
high: 12e3
|
|
16049
|
+
...MODEL_RULES.geminiBudgets
|
|
15277
16050
|
};
|
|
15278
16051
|
var THINKING_OUTPUT_RESERVE = 1024;
|
|
16052
|
+
var MIN_THINKING_BUDGET = 1024;
|
|
15279
16053
|
var THINKING_MIN_MAX_TOKENS = 4096;
|
|
15280
|
-
function applyOpenAIReasoning(body, reasoning, mode = "legacy_effort") {
|
|
16054
|
+
function applyOpenAIReasoning(body, reasoning, mode = "legacy_effort", model, rule) {
|
|
15281
16055
|
if (!reasoning) return;
|
|
15282
|
-
const
|
|
16056
|
+
const requested = normalizeEffort(reasoning.effort);
|
|
16057
|
+
const r = rule ?? resolveModelRule({ provider: "openai", model: model ?? body.model });
|
|
16058
|
+
const effort = requested && mapReasoningEffort(r, requested, mode === "responses" ? "responses" : "chat").effort;
|
|
15283
16059
|
if (mode === "responses") {
|
|
15284
16060
|
const obj = {};
|
|
15285
16061
|
if (effort) obj.effort = effort;
|
|
@@ -15291,52 +16067,107 @@ function applyOpenAIReasoning(body, reasoning, mode = "legacy_effort") {
|
|
|
15291
16067
|
if (reasoning.providerExtras) Object.assign(body, reasoning.providerExtras);
|
|
15292
16068
|
}
|
|
15293
16069
|
}
|
|
15294
|
-
function
|
|
15295
|
-
if (
|
|
15296
|
-
|
|
15297
|
-
|
|
16070
|
+
function supportsAdaptiveThinking(model) {
|
|
16071
|
+
if (typeof model !== "string") return false;
|
|
16072
|
+
return resolveModelRule({ provider: "anthropic", model }).reasoning.style === "adaptive";
|
|
16073
|
+
}
|
|
16074
|
+
function resolveThinkingForm(model, mode, rule) {
|
|
16075
|
+
if (mode === "adaptive" || mode === "budget") return mode;
|
|
16076
|
+
if (rule) return rule.reasoning.style === "adaptive" ? "adaptive" : "budget";
|
|
16077
|
+
return supportsAdaptiveThinking(model) ? "adaptive" : "budget";
|
|
16078
|
+
}
|
|
16079
|
+
function enforceAnthropicSampling(target, rule, thinkingOn, bedrock = false) {
|
|
16080
|
+
const fields = bedrock ? [["temperature", "temperature"], ["topP", "topP"]] : [["temperature", "temperature"], ["top_p", "topP"], ["top_k", "topK"]];
|
|
16081
|
+
for (const [key, field] of fields) {
|
|
16082
|
+
if (key in target && !allowsSampling(rule, field, target[key], thinkingOn)) delete target[key];
|
|
16083
|
+
}
|
|
16084
|
+
}
|
|
16085
|
+
function applyAdaptiveThinking(reasoning, rule, setThinking, setOutputConfig) {
|
|
16086
|
+
let requested = normalizeEffort(reasoning.effort);
|
|
16087
|
+
if (!requested && typeof reasoning.budgetTokens === "number" && reasoning.budgetTokens > 0) {
|
|
16088
|
+
requested = reasoning.budgetTokens <= ANTHROPIC_EFFORT_BUDGET.low ? "low" : reasoning.budgetTokens <= ANTHROPIC_EFFORT_BUDGET.medium ? "medium" : "high";
|
|
16089
|
+
}
|
|
16090
|
+
if (!requested) return false;
|
|
16091
|
+
const mapped = mapReasoningEffort(rule, requested);
|
|
16092
|
+
if (mapped.off) {
|
|
16093
|
+
setThinking({ type: mapped.off });
|
|
16094
|
+
return false;
|
|
16095
|
+
}
|
|
16096
|
+
if (!mapped.effort || mapped.effort === "none") return false;
|
|
16097
|
+
const thinking = { type: "adaptive" };
|
|
16098
|
+
if (reasoning.includeThoughts !== false) thinking.display = "summarized";
|
|
16099
|
+
if (reasoning.providerExtras) Object.assign(thinking, reasoning.providerExtras);
|
|
16100
|
+
setThinking(thinking);
|
|
16101
|
+
setOutputConfig({ effort: mapped.effort });
|
|
16102
|
+
return true;
|
|
16103
|
+
}
|
|
16104
|
+
function applyAnthropicReasoning(body, reasoning, opts) {
|
|
16105
|
+
const rule = opts?.rule ?? resolveModelRule({ provider: "anthropic", model: opts?.model ?? body.model });
|
|
16106
|
+
if (!reasoning) {
|
|
16107
|
+
enforceAnthropicSampling(body, rule, false);
|
|
16108
|
+
return;
|
|
16109
|
+
}
|
|
16110
|
+
if (resolveThinkingForm(opts?.model ?? body.model, opts?.mode, rule) === "adaptive") {
|
|
16111
|
+
const on = applyAdaptiveThinking(reasoning, rule, (t) => body.thinking = t, (o) => body.output_config = { ...body.output_config ?? {}, ...o });
|
|
16112
|
+
enforceAnthropicSampling(body, rule, on);
|
|
16113
|
+
return;
|
|
16114
|
+
}
|
|
16115
|
+
let budget = resolveBudget(reasoning, ANTHROPIC_EFFORT_BUDGET, rule);
|
|
16116
|
+
if (!budget) {
|
|
16117
|
+
enforceAnthropicSampling(body, rule, false);
|
|
16118
|
+
return;
|
|
16119
|
+
}
|
|
15298
16120
|
const currentMax = typeof body.max_tokens === "number" ? body.max_tokens : 0;
|
|
15299
16121
|
const requiredMax = Math.max(THINKING_MIN_MAX_TOKENS, budget + THINKING_OUTPUT_RESERVE);
|
|
15300
16122
|
if (currentMax < requiredMax) {
|
|
15301
16123
|
body.max_tokens = requiredMax;
|
|
15302
16124
|
}
|
|
15303
|
-
budget = clampBudget(budget, body.max_tokens);
|
|
16125
|
+
budget = Math.max(MIN_THINKING_BUDGET, clampBudget(budget, body.max_tokens));
|
|
15304
16126
|
const thinking = { type: "enabled", budget_tokens: budget };
|
|
15305
16127
|
if (reasoning.providerExtras) Object.assign(thinking, reasoning.providerExtras);
|
|
15306
16128
|
body.thinking = thinking;
|
|
15307
|
-
|
|
16129
|
+
enforceAnthropicSampling(body, rule, true);
|
|
15308
16130
|
}
|
|
15309
|
-
function applyBedrockReasoning(body, reasoning) {
|
|
15310
|
-
|
|
15311
|
-
|
|
15312
|
-
|
|
16131
|
+
function applyBedrockReasoning(body, reasoning, opts) {
|
|
16132
|
+
const rule = opts?.rule ?? resolveModelRule({ provider: "bedrock", model: opts?.model ?? body.modelId });
|
|
16133
|
+
if (!reasoning) {
|
|
16134
|
+
if (body.inferenceConfig) enforceAnthropicSampling(body.inferenceConfig, rule, false, true);
|
|
16135
|
+
return;
|
|
16136
|
+
}
|
|
16137
|
+
if (resolveThinkingForm(opts?.model ?? body.modelId, opts?.mode, rule) === "adaptive") {
|
|
16138
|
+
const fields = () => body.additionalModelRequestFields ?? (body.additionalModelRequestFields = {});
|
|
16139
|
+
const on = applyAdaptiveThinking(reasoning, rule, (t) => fields().thinking = t, (o) => fields().output_config = { ...fields().output_config ?? {}, ...o });
|
|
16140
|
+
if (body.inferenceConfig) enforceAnthropicSampling(body.inferenceConfig, rule, on, true);
|
|
16141
|
+
return;
|
|
16142
|
+
}
|
|
16143
|
+
let budget = resolveBudget(reasoning, ANTHROPIC_EFFORT_BUDGET, rule);
|
|
16144
|
+
if (!budget) {
|
|
16145
|
+
if (body.inferenceConfig) enforceAnthropicSampling(body.inferenceConfig, rule, false, true);
|
|
16146
|
+
return;
|
|
16147
|
+
}
|
|
15313
16148
|
const inference = body.inferenceConfig ?? (body.inferenceConfig = {});
|
|
15314
16149
|
const currentMax = typeof inference.maxTokens === "number" ? inference.maxTokens : 0;
|
|
15315
16150
|
const requiredMax = Math.max(THINKING_MIN_MAX_TOKENS, budget + THINKING_OUTPUT_RESERVE);
|
|
15316
16151
|
if (currentMax < requiredMax) {
|
|
15317
16152
|
inference.maxTokens = requiredMax;
|
|
15318
16153
|
}
|
|
15319
|
-
budget = clampBudget(budget, inference.maxTokens);
|
|
16154
|
+
budget = Math.max(MIN_THINKING_BUDGET, clampBudget(budget, inference.maxTokens));
|
|
15320
16155
|
const extra = body.additionalModelRequestFields ?? (body.additionalModelRequestFields = {});
|
|
15321
16156
|
const thinking = { type: "enabled", budget_tokens: budget };
|
|
15322
16157
|
if (reasoning.providerExtras) Object.assign(thinking, reasoning.providerExtras);
|
|
15323
16158
|
extra.thinking = thinking;
|
|
15324
|
-
|
|
16159
|
+
enforceAnthropicSampling(inference, rule, true, true);
|
|
15325
16160
|
}
|
|
15326
16161
|
function applyGeminiReasoning(generationConfig, reasoning) {
|
|
15327
16162
|
if (!reasoning) return;
|
|
15328
16163
|
const budget = resolveBudget(reasoning, GEMINI_EFFORT_BUDGET);
|
|
15329
|
-
|
|
15330
|
-
|
|
16164
|
+
const level = typeof reasoning.thinkingLevel === "string" && reasoning.thinkingLevel ? reasoning.thinkingLevel : void 0;
|
|
16165
|
+
if (budget == null && !level) return;
|
|
16166
|
+
const thinkingConfig = level && budget !== 0 ? { thinkingLevel: level } : { thinkingBudget: budget ?? 0 };
|
|
15331
16167
|
if (reasoning.includeThoughts) thinkingConfig.includeThoughts = true;
|
|
15332
16168
|
if (reasoning.providerExtras) Object.assign(thinkingConfig, reasoning.providerExtras);
|
|
15333
16169
|
generationConfig.thinkingConfig = thinkingConfig;
|
|
15334
16170
|
}
|
|
15335
|
-
function stripSamplingParams(target, keys) {
|
|
15336
|
-
for (const k of keys) {
|
|
15337
|
-
if (k in target) delete target[k];
|
|
15338
|
-
}
|
|
15339
|
-
}
|
|
15340
16171
|
function clampBudget(budget, maxTokens) {
|
|
15341
16172
|
if (typeof maxTokens !== "number" || maxTokens <= 0) return budget;
|
|
15342
16173
|
const ceiling = maxTokens - THINKING_OUTPUT_RESERVE;
|
|
@@ -15345,19 +16176,292 @@ function clampBudget(budget, maxTokens) {
|
|
|
15345
16176
|
}
|
|
15346
16177
|
function normalizeEffort(effort) {
|
|
15347
16178
|
if (!effort) return void 0;
|
|
15348
|
-
const allowed = ["none", "minimal", "low", "medium", "high"];
|
|
16179
|
+
const allowed = ["none", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
15349
16180
|
return allowed.includes(effort) ? effort : void 0;
|
|
15350
16181
|
}
|
|
15351
|
-
function resolveBudget(reasoning,
|
|
16182
|
+
function resolveBudget(reasoning, effortBudget2, rule) {
|
|
15352
16183
|
const effort = normalizeEffort(reasoning.effort);
|
|
15353
16184
|
if (effort === "none") return 0;
|
|
15354
16185
|
if (typeof reasoning.budgetTokens === "number" && reasoning.budgetTokens > 0) {
|
|
15355
16186
|
return Math.floor(reasoning.budgetTokens);
|
|
15356
16187
|
}
|
|
15357
|
-
|
|
16188
|
+
const mapped = effort && rule ? mapReasoningEffort(rule, effort).effort : effort;
|
|
16189
|
+
if (mapped && effortBudget2[mapped]) return effortBudget2[mapped];
|
|
15358
16190
|
return void 0;
|
|
15359
16191
|
}
|
|
15360
16192
|
|
|
16193
|
+
// src/providers/utils/sse.ts
|
|
16194
|
+
async function* parseSSEStream(body, signal) {
|
|
16195
|
+
const reader = body.getReader();
|
|
16196
|
+
const decoder = new TextDecoder();
|
|
16197
|
+
let buffer = "";
|
|
16198
|
+
try {
|
|
16199
|
+
while (true) {
|
|
16200
|
+
if (signal?.aborted) throw abortReason(signal);
|
|
16201
|
+
const { done, value } = await reader.read();
|
|
16202
|
+
if (done) break;
|
|
16203
|
+
buffer += decoder.decode(value, { stream: true });
|
|
16204
|
+
const parts = buffer.split(/\r?\n\r?\n/);
|
|
16205
|
+
buffer = parts.pop() ?? "";
|
|
16206
|
+
for (const part of parts) {
|
|
16207
|
+
if (!part.trim()) continue;
|
|
16208
|
+
const event = parseSSEBlock(part);
|
|
16209
|
+
if (event) yield event;
|
|
16210
|
+
}
|
|
16211
|
+
}
|
|
16212
|
+
if (buffer.trim()) {
|
|
16213
|
+
const event = parseSSEBlock(buffer);
|
|
16214
|
+
if (event) yield event;
|
|
16215
|
+
}
|
|
16216
|
+
} finally {
|
|
16217
|
+
reader.cancel().catch(() => void 0);
|
|
16218
|
+
reader.releaseLock();
|
|
16219
|
+
}
|
|
16220
|
+
}
|
|
16221
|
+
function parseSSEBlock(block) {
|
|
16222
|
+
let event;
|
|
16223
|
+
let id;
|
|
16224
|
+
let retry;
|
|
16225
|
+
const dataLines = [];
|
|
16226
|
+
for (const line of block.split(/\r?\n/)) {
|
|
16227
|
+
if (line.startsWith(":")) continue;
|
|
16228
|
+
const colonIdx = line.indexOf(":");
|
|
16229
|
+
let field;
|
|
16230
|
+
let value;
|
|
16231
|
+
if (colonIdx === -1) {
|
|
16232
|
+
field = line;
|
|
16233
|
+
value = "";
|
|
16234
|
+
} else {
|
|
16235
|
+
field = line.slice(0, colonIdx);
|
|
16236
|
+
value = line.slice(colonIdx + 1);
|
|
16237
|
+
if (value.startsWith(" ")) value = value.slice(1);
|
|
16238
|
+
}
|
|
16239
|
+
switch (field) {
|
|
16240
|
+
case "event":
|
|
16241
|
+
event = value;
|
|
16242
|
+
break;
|
|
16243
|
+
case "data":
|
|
16244
|
+
dataLines.push(value);
|
|
16245
|
+
break;
|
|
16246
|
+
case "id":
|
|
16247
|
+
id = value;
|
|
16248
|
+
break;
|
|
16249
|
+
case "retry": {
|
|
16250
|
+
const n = parseInt(value, 10);
|
|
16251
|
+
if (!isNaN(n)) retry = n;
|
|
16252
|
+
break;
|
|
16253
|
+
}
|
|
16254
|
+
}
|
|
16255
|
+
}
|
|
16256
|
+
if (dataLines.length === 0) return null;
|
|
16257
|
+
return { event, data: dataLines.join("\n"), id, retry };
|
|
16258
|
+
}
|
|
16259
|
+
|
|
16260
|
+
// src/models/errors.ts
|
|
16261
|
+
var ModelRequestError = class extends ProviderError {
|
|
16262
|
+
constructor(init) {
|
|
16263
|
+
super(init.message, init.provider, init.status ?? 400, init.responseBody);
|
|
16264
|
+
this.status = init.status ?? 400;
|
|
16265
|
+
this.code = init.code;
|
|
16266
|
+
this.param = init.param;
|
|
16267
|
+
this.value = init.value;
|
|
16268
|
+
this.supportedValues = init.supportedValues;
|
|
16269
|
+
this.model = init.model;
|
|
16270
|
+
}
|
|
16271
|
+
};
|
|
16272
|
+
|
|
16273
|
+
// src/models/adjust.ts
|
|
16274
|
+
var MAX_ADJUSTMENTS = 3;
|
|
16275
|
+
var Q = "['\"`]";
|
|
16276
|
+
function errorMessage(text) {
|
|
16277
|
+
try {
|
|
16278
|
+
const j = JSON.parse(text);
|
|
16279
|
+
const e = j?.error ?? j;
|
|
16280
|
+
const message = typeof e?.message === "string" ? e.message : typeof j?.message === "string" ? j.message : text;
|
|
16281
|
+
return { message, param: typeof e?.param === "string" ? e.param : void 0, code: typeof e?.code === "string" ? e.code : void 0 };
|
|
16282
|
+
} catch {
|
|
16283
|
+
return { message: text };
|
|
16284
|
+
}
|
|
16285
|
+
}
|
|
16286
|
+
function quotedList(s) {
|
|
16287
|
+
const quoted = [...s.matchAll(new RegExp(`${Q}([^'"\`]+)${Q}`, "g"))].map((m) => m[1]);
|
|
16288
|
+
if (quoted.length > 0) return quoted;
|
|
16289
|
+
return s.split(/[,\s]+/).map((x) => x.replace(/[.\s]+$/, "")).filter(Boolean);
|
|
16290
|
+
}
|
|
16291
|
+
function parseModelError(text) {
|
|
16292
|
+
const { message, param: errParam } = errorMessage(String(text ?? ""));
|
|
16293
|
+
const m = message.toLowerCase();
|
|
16294
|
+
if (m.includes("function tools with reasoning_effort") && m.includes("not supported")) {
|
|
16295
|
+
return { kind: "chat_tools_effort", message };
|
|
16296
|
+
}
|
|
16297
|
+
if (m.includes("between_tools") && m.includes("thinking")) return { kind: "thinking_off_between_tools", message };
|
|
16298
|
+
if (m.includes("thinking.type.enabled") && m.includes("not supported")) return { kind: "thinking_enabled_unsupported", message };
|
|
16299
|
+
if (m.includes("thinking.type.adaptive") && m.includes("not supported")) return { kind: "thinking_adaptive_unsupported", message };
|
|
16300
|
+
if (m.includes("thinking.type.disabled") && m.includes("not supported")) return { kind: "thinking_disabled_unsupported", message };
|
|
16301
|
+
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);
|
|
16302
|
+
if (tt) return { kind: "temperature_thinking", param: tt[1].toLowerCase(), message };
|
|
16303
|
+
const dep = new RegExp(`${Q}([\\w.]+)${Q}\\s+is deprecated for this model`, "i").exec(message);
|
|
16304
|
+
if (dep) return { kind: "unsupported_parameter", param: dep[1], message };
|
|
16305
|
+
const rename = new RegExp(`use ${Q}(max_completion_tokens|max_tokens)${Q} instead`, "i").exec(message);
|
|
16306
|
+
if (rename) return { kind: "max_tokens_rename", renameTo: rename[1].toLowerCase(), param: rename[1].toLowerCase() === "max_tokens" ? "max_completion_tokens" : "max_tokens", message };
|
|
16307
|
+
const val = new RegExp(`unsupported value:?\\s*${Q}?([\\w.]+)${Q}?\\s+does not support\\s+(${Q}[^'"\`]*${Q}|[^\\s]+)`, "i").exec(message);
|
|
16308
|
+
if (val) {
|
|
16309
|
+
const param = val[1];
|
|
16310
|
+
const value = val[2].replace(/^['"`]|['"`]$/g, "");
|
|
16311
|
+
if (m.includes("only the default") && m.includes("value is supported")) return { kind: "default_only", param, value, message };
|
|
16312
|
+
const sup = /supported values? (?:are|is):?\s*([^\n]*)/i.exec(message);
|
|
16313
|
+
return { kind: "unsupported_value", param, value, supportedValues: sup ? quotedList(sup[1]) : void 0, message };
|
|
16314
|
+
}
|
|
16315
|
+
if (m.includes("only the default") && m.includes("value is supported")) {
|
|
16316
|
+
return { kind: "default_only", param: errParam ?? "temperature", message };
|
|
16317
|
+
}
|
|
16318
|
+
const prm = new RegExp(`unsupported parameter:?\\s*${Q}?([\\w.]+)${Q}?`, "i").exec(message);
|
|
16319
|
+
if (prm) return { kind: "unsupported_parameter", param: prm[1], message };
|
|
16320
|
+
return void 0;
|
|
16321
|
+
}
|
|
16322
|
+
var normParam = (p) => p.toLowerCase().replace(/[-\s]/g, "_");
|
|
16323
|
+
var LADDER2 = new Set(MODEL_RULES.effortLadder);
|
|
16324
|
+
function patchFromParsedError(parsed, endpoint = "chat") {
|
|
16325
|
+
const param = parsed.param ? normParam(parsed.param) : "";
|
|
16326
|
+
switch (parsed.kind) {
|
|
16327
|
+
case "chat_tools_effort":
|
|
16328
|
+
return { patch: { chatTools: { reasoning: "force-none" } }, adjustment: "chat-tools:force-effort-none" };
|
|
16329
|
+
case "max_tokens_rename":
|
|
16330
|
+
return { patch: { maxTokensParam: parsed.renameTo }, adjustment: `${parsed.param}->${parsed.renameTo}` };
|
|
16331
|
+
case "thinking_enabled_unsupported":
|
|
16332
|
+
return { patch: { reasoning: { style: "adaptive" } }, adjustment: "thinking:adaptive" };
|
|
16333
|
+
case "thinking_adaptive_unsupported":
|
|
16334
|
+
return { patch: { reasoning: { style: "budget" } }, adjustment: "thinking:budget" };
|
|
16335
|
+
case "thinking_off_between_tools":
|
|
16336
|
+
return { patch: { reasoning: { off: "between_tools" } }, adjustment: "thinking-off:between_tools" };
|
|
16337
|
+
case "thinking_disabled_unsupported":
|
|
16338
|
+
return { patch: { reasoning: { off: null } }, adjustment: "thinking-off:none" };
|
|
16339
|
+
case "temperature_thinking":
|
|
16340
|
+
return { patch: { sampling: { temperature: "unsupported" } }, adjustment: "drop:temperature" };
|
|
16341
|
+
case "default_only":
|
|
16342
|
+
if (param === "temperature") return { patch: { sampling: { temperature: "default-only" } }, adjustment: "temperature:default-only" };
|
|
16343
|
+
return { patch: { dropParams: [parsed.param ?? param] }, adjustment: `drop:${parsed.param ?? param}` };
|
|
16344
|
+
case "unsupported_value": {
|
|
16345
|
+
if (/^(reasoning_effort|reasoning\.effort|effort|output_config\.effort)$/.test(param)) {
|
|
16346
|
+
const list = (parsed.supportedValues ?? []).map((v) => v.toLowerCase()).filter((v) => LADDER2.has(v));
|
|
16347
|
+
if (list.length === 0) return void 0;
|
|
16348
|
+
const reasoning = endpoint === "responses" ? { responsesEfforts: list } : { efforts: list };
|
|
16349
|
+
return { patch: { reasoning }, adjustment: `efforts:${list.join("|")}` };
|
|
16350
|
+
}
|
|
16351
|
+
return paramDropPatch(param, parsed);
|
|
16352
|
+
}
|
|
16353
|
+
case "unsupported_parameter":
|
|
16354
|
+
return paramDropPatch(param, parsed);
|
|
16355
|
+
}
|
|
16356
|
+
}
|
|
16357
|
+
function paramDropPatch(param, parsed) {
|
|
16358
|
+
if (!param) return void 0;
|
|
16359
|
+
const label = `drop:${parsed.param ?? param}`;
|
|
16360
|
+
switch (param) {
|
|
16361
|
+
case "temperature":
|
|
16362
|
+
return { patch: { sampling: { temperature: "unsupported" } }, adjustment: label };
|
|
16363
|
+
case "top_p":
|
|
16364
|
+
return { patch: { sampling: { topP: false } }, adjustment: label };
|
|
16365
|
+
case "top_k":
|
|
16366
|
+
return { patch: { sampling: { topK: false } }, adjustment: label };
|
|
16367
|
+
case "presence_penalty":
|
|
16368
|
+
case "frequency_penalty":
|
|
16369
|
+
return { patch: { sampling: { penalties: false } }, adjustment: label };
|
|
16370
|
+
case "logprobs":
|
|
16371
|
+
case "top_logprobs":
|
|
16372
|
+
return { patch: { sampling: { logprobs: false } }, adjustment: label };
|
|
16373
|
+
case "max_tokens":
|
|
16374
|
+
return { patch: { maxTokensParam: "max_completion_tokens" }, adjustment: "max_tokens->max_completion_tokens" };
|
|
16375
|
+
case "max_completion_tokens":
|
|
16376
|
+
return { patch: { maxTokensParam: "max_tokens" }, adjustment: "max_completion_tokens->max_tokens" };
|
|
16377
|
+
case "reasoning_effort":
|
|
16378
|
+
case "reasoning.effort":
|
|
16379
|
+
case "reasoning":
|
|
16380
|
+
return { patch: { reasoning: { style: "none", efforts: [], responsesEfforts: [] }, dropParams: [param] }, adjustment: label };
|
|
16381
|
+
default:
|
|
16382
|
+
return { patch: { dropParams: [parsed.param ?? param] }, adjustment: label };
|
|
16383
|
+
}
|
|
16384
|
+
}
|
|
16385
|
+
function codeFor(parsed) {
|
|
16386
|
+
if (!parsed) return "model_request_invalid";
|
|
16387
|
+
if (parsed.kind === "unsupported_value" || parsed.kind === "default_only") return "unsupported_value";
|
|
16388
|
+
if (parsed.kind === "unsupported_parameter" || parsed.kind === "max_tokens_rename" || parsed.kind === "temperature_thinking") return "unsupported_parameter";
|
|
16389
|
+
return "model_request_invalid";
|
|
16390
|
+
}
|
|
16391
|
+
function toModelRequestError(err, parsed, provider, model) {
|
|
16392
|
+
return new ModelRequestError({
|
|
16393
|
+
status: err.statusCode ?? 400,
|
|
16394
|
+
code: codeFor(parsed),
|
|
16395
|
+
param: parsed?.param,
|
|
16396
|
+
value: parsed?.value,
|
|
16397
|
+
supportedValues: parsed?.supportedValues,
|
|
16398
|
+
provider: err.provider || provider,
|
|
16399
|
+
model,
|
|
16400
|
+
message: err.message,
|
|
16401
|
+
responseBody: err.responseBody
|
|
16402
|
+
});
|
|
16403
|
+
}
|
|
16404
|
+
var SameRequest = class extends Error {
|
|
16405
|
+
};
|
|
16406
|
+
function withoutCallerParams(step, callerParams) {
|
|
16407
|
+
const drops = step.patch.dropParams;
|
|
16408
|
+
if (!callerParams?.length || !drops) return step;
|
|
16409
|
+
const mine = (p) => callerParams.includes(p.split(".")[0]);
|
|
16410
|
+
if (!drops.some(mine)) return step;
|
|
16411
|
+
const { dropParams: _ignored, ...rest } = step.patch;
|
|
16412
|
+
const kept = drops.filter((p) => !mine(p));
|
|
16413
|
+
const patch = kept.length ? { ...rest, dropParams: kept } : rest;
|
|
16414
|
+
return Object.keys(patch).length ? { ...step, patch } : void 0;
|
|
16415
|
+
}
|
|
16416
|
+
async function runWithModelAdjustments(opts) {
|
|
16417
|
+
let overlay = {};
|
|
16418
|
+
const steps = [];
|
|
16419
|
+
let previous;
|
|
16420
|
+
let lastError;
|
|
16421
|
+
let lastParsed;
|
|
16422
|
+
for (; ; ) {
|
|
16423
|
+
const guard = (body) => {
|
|
16424
|
+
let json;
|
|
16425
|
+
try {
|
|
16426
|
+
json = JSON.stringify(body);
|
|
16427
|
+
} catch {
|
|
16428
|
+
return;
|
|
16429
|
+
}
|
|
16430
|
+
if (previous !== void 0 && json === previous) throw new SameRequest();
|
|
16431
|
+
previous = json;
|
|
16432
|
+
};
|
|
16433
|
+
try {
|
|
16434
|
+
const result = await opts.run(overlay, guard);
|
|
16435
|
+
for (const step of steps) {
|
|
16436
|
+
const s = withoutCallerParams(step, opts.callerParams);
|
|
16437
|
+
if (!s) continue;
|
|
16438
|
+
rememberModelRulePatch(opts.provider, opts.model, s.patch, opts.scope);
|
|
16439
|
+
if (opts.onLearned) {
|
|
16440
|
+
try {
|
|
16441
|
+
opts.onLearned({ provider: opts.provider, model: opts.model, adjustment: s.adjustment, patch: s.patch, reason: s.reason });
|
|
16442
|
+
} catch {
|
|
16443
|
+
}
|
|
16444
|
+
}
|
|
16445
|
+
}
|
|
16446
|
+
return result;
|
|
16447
|
+
} catch (err) {
|
|
16448
|
+
if (err instanceof SameRequest) throw toModelRequestError(lastError, lastParsed, opts.provider, opts.model);
|
|
16449
|
+
if (!(err instanceof ProviderError) || err instanceof ModelRequestError || err.statusCode !== 400) throw err;
|
|
16450
|
+
const parsed = parseModelError(String(err.responseBody ?? err.message));
|
|
16451
|
+
const fix = parsed ? patchFromParsedError(parsed, opts.endpoint) : void 0;
|
|
16452
|
+
lastError = err;
|
|
16453
|
+
lastParsed = parsed;
|
|
16454
|
+
if (!fix || steps.length >= MAX_ADJUSTMENTS) throw toModelRequestError(err, parsed, opts.provider, opts.model);
|
|
16455
|
+
overlay = mergeRulePatch(overlay, fix.patch);
|
|
16456
|
+
steps.push({ ...fix, reason: parsed.message });
|
|
16457
|
+
}
|
|
16458
|
+
}
|
|
16459
|
+
}
|
|
16460
|
+
function asModelRequestError(err, provider, model) {
|
|
16461
|
+
if (!(err instanceof ProviderError) || err instanceof ModelRequestError || err.statusCode !== 400) return err;
|
|
16462
|
+
return toModelRequestError(err, parseModelError(String(err.responseBody ?? err.message)), provider, model);
|
|
16463
|
+
}
|
|
16464
|
+
|
|
15361
16465
|
// src/providers/utils/media.ts
|
|
15362
16466
|
var EXTENSION_MIME = {
|
|
15363
16467
|
jpg: "image/jpeg",
|
|
@@ -15549,11 +16653,64 @@ function isObject2(value) {
|
|
|
15549
16653
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15550
16654
|
}
|
|
15551
16655
|
|
|
16656
|
+
// src/providers/utils/embeddings.ts
|
|
16657
|
+
function chunkArray(items, size) {
|
|
16658
|
+
const n = Math.max(1, Math.floor(size));
|
|
16659
|
+
const out = [];
|
|
16660
|
+
for (let i = 0; i < items.length; i += n) out.push(items.slice(i, i + n));
|
|
16661
|
+
return out;
|
|
16662
|
+
}
|
|
16663
|
+
async function mapWithConcurrency(items, limit, fn, signal) {
|
|
16664
|
+
const results = new Array(items.length);
|
|
16665
|
+
let next = 0;
|
|
16666
|
+
let failure;
|
|
16667
|
+
let failed = false;
|
|
16668
|
+
const worker = async () => {
|
|
16669
|
+
while (!failed) {
|
|
16670
|
+
if (signal?.aborted) throw signal.reason ?? new Error("aborted");
|
|
16671
|
+
const i = next++;
|
|
16672
|
+
if (i >= items.length) return;
|
|
16673
|
+
try {
|
|
16674
|
+
results[i] = await fn(items[i], i);
|
|
16675
|
+
} catch (err) {
|
|
16676
|
+
failed = true;
|
|
16677
|
+
failure = err;
|
|
16678
|
+
return;
|
|
16679
|
+
}
|
|
16680
|
+
}
|
|
16681
|
+
};
|
|
16682
|
+
await Promise.all(Array.from({ length: Math.min(Math.max(1, limit), items.length) }, worker));
|
|
16683
|
+
if (failed) throw failure;
|
|
16684
|
+
return results;
|
|
16685
|
+
}
|
|
16686
|
+
function decodeBase64Vector(b64) {
|
|
16687
|
+
const buf = Buffer.from(b64, "base64");
|
|
16688
|
+
const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
16689
|
+
const out = new Array(Math.floor(buf.byteLength / 4));
|
|
16690
|
+
for (let i = 0; i < out.length; i++) out[i] = view.getFloat32(i * 4, true);
|
|
16691
|
+
return out;
|
|
16692
|
+
}
|
|
16693
|
+
function assertVectorCount(provider, vectors, expected) {
|
|
16694
|
+
if (vectors.length !== expected) {
|
|
16695
|
+
throw new ProviderError(
|
|
16696
|
+
`${provider} embeddings returned ${vectors.length} vectors for ${expected} inputs`,
|
|
16697
|
+
provider,
|
|
16698
|
+
502
|
|
16699
|
+
);
|
|
16700
|
+
}
|
|
16701
|
+
}
|
|
16702
|
+
function requireEmbeddingModel(provider, model) {
|
|
16703
|
+
if (!model) throw new ProviderError(`${provider} embeddings require a model`, provider, 400);
|
|
16704
|
+
return model;
|
|
16705
|
+
}
|
|
16706
|
+
|
|
15552
16707
|
// src/providers/openai.ts
|
|
15553
|
-
var OpenAIProvider = class
|
|
16708
|
+
var OpenAIProvider = class extends BaseProvider {
|
|
15554
16709
|
constructor(config) {
|
|
15555
16710
|
super();
|
|
15556
16711
|
this.providerName = "openai";
|
|
16712
|
+
this.configureTransport(config);
|
|
16713
|
+
this.maxTokensParam = config.maxTokensParam ?? "auto";
|
|
15557
16714
|
this.apiKey = config.apiKey;
|
|
15558
16715
|
this.baseURL = (config.baseURL ?? "https://api.openai.com/v1").replace(/\/$/, "");
|
|
15559
16716
|
this.defaultModel = config.defaultModel ?? "gpt-4o";
|
|
@@ -15561,10 +16718,14 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15561
16718
|
...config.defaultHeaders,
|
|
15562
16719
|
...config.organization ? { "OpenAI-Organization": config.organization } : {}
|
|
15563
16720
|
};
|
|
15564
|
-
|
|
15565
|
-
const
|
|
15566
|
-
this.
|
|
15567
|
-
this.
|
|
16721
|
+
const legacy = config.responsesApi;
|
|
16722
|
+
const explicit = config.api === "chat" || config.api === "responses" ? config.api : void 0;
|
|
16723
|
+
this.responsesApi = explicit === "responses" ? "always" : explicit === "chat" ? "never" : legacy ?? (config._autoMeansChat ? "never" : "auto");
|
|
16724
|
+
this.apiExplicitChat = explicit === "chat" || explicit === void 0 && legacy === "never";
|
|
16725
|
+
this.apiExplicitResponses = this.responsesApi === "always";
|
|
16726
|
+
this.apiResponsesNative = explicit === "responses";
|
|
16727
|
+
this.responsesApiModels = [...config.responsesApiModels ?? []];
|
|
16728
|
+
this.responsesStreaming = config.responsesStreaming ?? this.apiResponsesNative;
|
|
15568
16729
|
if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
|
|
15569
16730
|
}
|
|
15570
16731
|
/** True when the caller listed this request's model in `responsesApiModels`. */
|
|
@@ -15590,9 +16751,10 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15590
16751
|
* A model listed in `responsesApiModels` is the caller stating the answer
|
|
15591
16752
|
* for that model alone; `never` still overrides it. */
|
|
15592
16753
|
useResponsesApi(request) {
|
|
15593
|
-
if (this.
|
|
15594
|
-
if (this.
|
|
16754
|
+
if (this.apiExplicitChat) return false;
|
|
16755
|
+
if (this.apiExplicitResponses) return true;
|
|
15595
16756
|
if (this.isResponsesApiModel(request)) return true;
|
|
16757
|
+
if (this.responsesApi !== "auto") return false;
|
|
15596
16758
|
if (!request.reasoning) return false;
|
|
15597
16759
|
return isReasoningModel(request.model || this.defaultModel);
|
|
15598
16760
|
}
|
|
@@ -15600,14 +16762,13 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15600
16762
|
if (this.useResponsesApi(request)) {
|
|
15601
16763
|
return this.completeResponses(request);
|
|
15602
16764
|
}
|
|
15603
|
-
const
|
|
15604
|
-
const res = await this.doFetch(body, request.signal);
|
|
16765
|
+
const res = await this.fetchChat(request, false);
|
|
15605
16766
|
const json = await res.json();
|
|
15606
16767
|
return this.parseResponse(json);
|
|
15607
16768
|
}
|
|
15608
16769
|
async *completeStream(request) {
|
|
15609
16770
|
if (this.useResponsesApi(request)) {
|
|
15610
|
-
if (this.responsesStreaming && this.isResponsesApiModel(request)) {
|
|
16771
|
+
if (this.responsesStreaming && (this.apiResponsesNative || this.isResponsesApiModel(request))) {
|
|
15611
16772
|
yield* this.streamResponses(request);
|
|
15612
16773
|
return;
|
|
15613
16774
|
}
|
|
@@ -15625,8 +16786,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15625
16786
|
};
|
|
15626
16787
|
return;
|
|
15627
16788
|
}
|
|
15628
|
-
const
|
|
15629
|
-
const res = await this.doFetch(body, request.signal);
|
|
16789
|
+
const res = await this.fetchChat(request, true);
|
|
15630
16790
|
if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
|
|
15631
16791
|
let id = "";
|
|
15632
16792
|
let model = "";
|
|
@@ -15657,9 +16817,14 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15657
16817
|
delta: {},
|
|
15658
16818
|
finishReason: mapFinishReason(choice.finish_reason)
|
|
15659
16819
|
};
|
|
16820
|
+
if (typeof choice.finish_reason === "string") out.rawFinishReason = choice.finish_reason;
|
|
16821
|
+
const fields = pickProviderFields(chunk, delta, choice);
|
|
16822
|
+
if (fields) out.providerFields = fields;
|
|
15660
16823
|
if (delta.content) {
|
|
15661
16824
|
out.delta.content = delta.content;
|
|
15662
16825
|
}
|
|
16826
|
+
const reasoningDelta = extractReasoningText(delta);
|
|
16827
|
+
if (reasoningDelta) out.delta.reasoning = { summary: reasoningDelta };
|
|
15663
16828
|
if (delta.tool_calls) {
|
|
15664
16829
|
const partials = [];
|
|
15665
16830
|
for (const tc of delta.tool_calls) {
|
|
@@ -15671,7 +16836,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15671
16836
|
if (tc.id) buf.id = tc.id;
|
|
15672
16837
|
if (tc.function?.name) buf.name = tc.function.name;
|
|
15673
16838
|
if (tc.function?.arguments) buf.arguments += tc.function.arguments;
|
|
15674
|
-
partials.push({ id: buf.id, name: buf.name || void 0, arguments: tc.function?.arguments });
|
|
16839
|
+
partials.push({ id: buf.id, name: buf.name || void 0, arguments: tc.function?.arguments, index: idx });
|
|
15675
16840
|
}
|
|
15676
16841
|
out.delta.toolCalls = partials;
|
|
15677
16842
|
}
|
|
@@ -15679,22 +16844,115 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15679
16844
|
yield out;
|
|
15680
16845
|
}
|
|
15681
16846
|
}
|
|
16847
|
+
// ─── Embeddings ──────────────────────────────────────────────────────────
|
|
16848
|
+
/** POST /embeddings, batched (default 2048 inputs per request, the OpenAI cap). */
|
|
16849
|
+
async embed(request) {
|
|
16850
|
+
const model = requireEmbeddingModel(this.providerName, request.model);
|
|
16851
|
+
const batches = chunkArray(request.input, request.batchSize ?? 2048);
|
|
16852
|
+
const vectors = [];
|
|
16853
|
+
const raw = [];
|
|
16854
|
+
let inputTokens = 0;
|
|
16855
|
+
let totalTokens = 0;
|
|
16856
|
+
let responseModel = model;
|
|
16857
|
+
for (const batch of batches) {
|
|
16858
|
+
const body = { model, input: batch };
|
|
16859
|
+
if (request.dimensions != null) body.dimensions = request.dimensions;
|
|
16860
|
+
if (request.encodingFormat) body.encoding_format = request.encodingFormat;
|
|
16861
|
+
if (request.extra) Object.assign(body, request.extra);
|
|
16862
|
+
const res = await this.embeddingsFetch(body, request.signal);
|
|
16863
|
+
const json = await res.json();
|
|
16864
|
+
raw.push(json);
|
|
16865
|
+
const data = Array.isArray(json.data) ? [...json.data] : [];
|
|
16866
|
+
data.sort((a, b) => (a.index ?? 0) - (b.index ?? 0));
|
|
16867
|
+
for (const d of data) {
|
|
16868
|
+
vectors.push(typeof d.embedding === "string" ? decodeBase64Vector(d.embedding) : d.embedding);
|
|
16869
|
+
}
|
|
16870
|
+
inputTokens += json.usage?.prompt_tokens ?? 0;
|
|
16871
|
+
totalTokens += json.usage?.total_tokens ?? json.usage?.prompt_tokens ?? 0;
|
|
16872
|
+
responseModel = json.model ?? responseModel;
|
|
16873
|
+
}
|
|
16874
|
+
assertVectorCount(this.providerName, vectors, request.input.length);
|
|
16875
|
+
return { model: responseModel, vectors, usage: { inputTokens, totalTokens }, raw };
|
|
16876
|
+
}
|
|
16877
|
+
async embeddingsFetch(body, signal) {
|
|
16878
|
+
const url = `${this.baseURL}/embeddings`;
|
|
16879
|
+
const headers = {
|
|
16880
|
+
"Content-Type": "application/json",
|
|
16881
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
16882
|
+
...this.defaultHeaders
|
|
16883
|
+
};
|
|
16884
|
+
const payload = JSON.stringify(body);
|
|
16885
|
+
const res = await this.doFetchWithRetry(() => this.httpFetch(url, { method: "POST", headers, body: payload, signal }), signal);
|
|
16886
|
+
if (!res.ok) {
|
|
16887
|
+
const text = await res.text().catch(() => "");
|
|
16888
|
+
throw new ProviderError(`OpenAI embeddings API error ${res.status}: ${text}`, this.providerName, res.status, text);
|
|
16889
|
+
}
|
|
16890
|
+
return res;
|
|
16891
|
+
}
|
|
15682
16892
|
// ─── Internals ───────────────────────────────────────────────────────────
|
|
15683
|
-
|
|
16893
|
+
/** Chat Completions call that corrects itself from the provider's own 400s (see models/adjust.ts). */
|
|
16894
|
+
fetchChat(request, stream) {
|
|
16895
|
+
const model = request.model || this.defaultModel;
|
|
16896
|
+
return runWithModelAdjustments({
|
|
16897
|
+
provider: this.providerName,
|
|
16898
|
+
model,
|
|
16899
|
+
endpoint: "chat",
|
|
16900
|
+
scope: this.baseURL,
|
|
16901
|
+
callerParams: request.extra ? Object.keys(request.extra) : void 0,
|
|
16902
|
+
onLearned: this.onModelRuleLearned,
|
|
16903
|
+
run: (overlay, guard) => {
|
|
16904
|
+
const body = this.buildRequestBody(request, stream, overlay);
|
|
16905
|
+
guard(body);
|
|
16906
|
+
return this.doFetch(body, request.signal);
|
|
16907
|
+
}
|
|
16908
|
+
});
|
|
16909
|
+
}
|
|
16910
|
+
/** Same for the Responses API. */
|
|
16911
|
+
fetchResponses(request, adaptExtras, stream = false) {
|
|
16912
|
+
const model = request.model || this.defaultModel;
|
|
16913
|
+
return runWithModelAdjustments({
|
|
16914
|
+
provider: this.providerName,
|
|
16915
|
+
model,
|
|
16916
|
+
endpoint: "responses",
|
|
16917
|
+
scope: this.baseURL,
|
|
16918
|
+
callerParams: request.extra ? Object.keys(request.extra) : void 0,
|
|
16919
|
+
onLearned: this.onModelRuleLearned,
|
|
16920
|
+
run: (overlay, guard) => {
|
|
16921
|
+
const body = this.buildResponsesBody(request, overlay);
|
|
16922
|
+
if (adaptExtras) adaptChatExtrasForResponses(body, request.extra);
|
|
16923
|
+
if (stream) body.stream = true;
|
|
16924
|
+
guard(body);
|
|
16925
|
+
return this.responsesFetch(body, request.signal);
|
|
16926
|
+
}
|
|
16927
|
+
});
|
|
16928
|
+
}
|
|
16929
|
+
buildRequestBody(request, stream, overlay) {
|
|
15684
16930
|
const body = {
|
|
15685
16931
|
model: request.model || this.defaultModel,
|
|
15686
16932
|
messages: request.messages.map((m) => this.toOpenAIMessage(m)),
|
|
15687
16933
|
stream
|
|
15688
16934
|
};
|
|
15689
|
-
if (stream) {
|
|
16935
|
+
if (stream && request.streamUsage !== false) {
|
|
15690
16936
|
body.stream_options = { include_usage: true };
|
|
15691
16937
|
}
|
|
15692
|
-
|
|
15693
|
-
|
|
15694
|
-
if (request.
|
|
16938
|
+
const modelId = String(body.model);
|
|
16939
|
+
const rule = resolveModelRule({ provider: this.providerName, model: modelId, patch: overlay, scope: this.baseURL });
|
|
16940
|
+
if (request.temperature != null && allowsSampling(rule, "temperature", request.temperature)) body.temperature = request.temperature;
|
|
16941
|
+
if (request.maxTokens != null) {
|
|
16942
|
+
const param = this.maxTokensParam === "auto" ? rule.maxTokensParam : this.maxTokensParam;
|
|
16943
|
+
body[param] = request.maxTokens;
|
|
16944
|
+
}
|
|
16945
|
+
if (request.topP != null && allowsSampling(rule, "topP")) body.top_p = request.topP;
|
|
15695
16946
|
if (request.stop) body.stop = request.stop;
|
|
16947
|
+
if (request.presencePenalty != null && allowsSampling(rule, "presencePenalty")) body.presence_penalty = request.presencePenalty;
|
|
16948
|
+
if (request.frequencyPenalty != null && allowsSampling(rule, "frequencyPenalty")) body.frequency_penalty = request.frequencyPenalty;
|
|
16949
|
+
if (request.seed != null) body.seed = request.seed;
|
|
16950
|
+
if (request.n != null) body.n = request.n;
|
|
16951
|
+
if (request.logprobs != null && allowsSampling(rule, "logprobs")) body.logprobs = request.logprobs;
|
|
16952
|
+
if (request.topLogprobs != null && allowsSampling(rule, "logprobs")) body.top_logprobs = request.topLogprobs;
|
|
15696
16953
|
if (request.tools?.length) {
|
|
15697
16954
|
body.tools = request.tools.map((t) => this.toOpenAITool(t));
|
|
16955
|
+
if (request.parallelToolCalls != null) body.parallel_tool_calls = request.parallelToolCalls;
|
|
15698
16956
|
}
|
|
15699
16957
|
if (request.toolChoice != null && request.tools?.length) {
|
|
15700
16958
|
if (typeof request.toolChoice === "string") {
|
|
@@ -15720,14 +16978,17 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15720
16978
|
if (request.extra) {
|
|
15721
16979
|
Object.assign(body, request.extra);
|
|
15722
16980
|
}
|
|
15723
|
-
applyOpenAIReasoning(body, request.reasoning, "legacy_effort");
|
|
16981
|
+
applyOpenAIReasoning(body, request.reasoning, "legacy_effort", modelId, rule);
|
|
16982
|
+
if (body.tools?.length && rule.chatTools.reasoning === "force-none" && rule.reasoning.style !== "none") {
|
|
16983
|
+
body.reasoning_effort = "none";
|
|
16984
|
+
}
|
|
16985
|
+
applyDropParams(body, rule);
|
|
15724
16986
|
return body;
|
|
15725
16987
|
}
|
|
15726
16988
|
// ─── Responses API (reasoning models) ──────────────────────────────────────
|
|
15727
16989
|
async completeResponses(request) {
|
|
15728
|
-
const
|
|
15729
|
-
|
|
15730
|
-
const res = await this.responsesFetch(body, request.signal);
|
|
16990
|
+
const adapt = this.apiResponsesNative || this.isResponsesApiModel(request);
|
|
16991
|
+
const res = await this.fetchResponses(request, adapt);
|
|
15731
16992
|
const json = await res.json();
|
|
15732
16993
|
return this.parseResponsesResponse(json, request.model || this.defaultModel);
|
|
15733
16994
|
}
|
|
@@ -15740,15 +17001,13 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15740
17001
|
* reads it). */
|
|
15741
17002
|
async *streamResponses(request) {
|
|
15742
17003
|
const modelId = request.model || this.defaultModel;
|
|
15743
|
-
const
|
|
15744
|
-
adaptChatExtrasForResponses(body, request.extra);
|
|
15745
|
-
body.stream = true;
|
|
15746
|
-
const res = await this.responsesFetch(body, request.signal);
|
|
17004
|
+
const res = await this.fetchResponses(request, true, true);
|
|
15747
17005
|
if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
|
|
15748
17006
|
let id = "";
|
|
15749
17007
|
let model = modelId;
|
|
15750
17008
|
const calls = /* @__PURE__ */ new Map();
|
|
15751
17009
|
let final;
|
|
17010
|
+
let streamedSummary = false;
|
|
15752
17011
|
for await (const event of parseSSEStream(res.body, request.signal)) {
|
|
15753
17012
|
if (event.data === "[DONE]") break;
|
|
15754
17013
|
let data;
|
|
@@ -15766,19 +17025,28 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15766
17025
|
case "response.output_text.delta":
|
|
15767
17026
|
if (data.delta) yield { id, model, delta: { content: data.delta } };
|
|
15768
17027
|
break;
|
|
17028
|
+
case "response.reasoning_summary_part.added":
|
|
17029
|
+
if (streamedSummary) yield { id, model, delta: { reasoning: { summary: "\n\n" } } };
|
|
17030
|
+
break;
|
|
17031
|
+
case "response.reasoning_summary_text.delta":
|
|
17032
|
+
if (typeof data.delta === "string" && data.delta) {
|
|
17033
|
+
streamedSummary = true;
|
|
17034
|
+
yield { id, model, delta: { reasoning: { summary: data.delta } } };
|
|
17035
|
+
}
|
|
17036
|
+
break;
|
|
15769
17037
|
case "response.output_item.added": {
|
|
15770
17038
|
const item = data.item;
|
|
15771
17039
|
if (item?.type !== "function_call") break;
|
|
15772
|
-
const call = { callId: item.call_id ?? item.id ?? "", name: item.name ?? "", arguments: item.arguments ?? "" };
|
|
17040
|
+
const call = { callId: item.call_id ?? item.id ?? "", name: item.name ?? "", arguments: item.arguments ?? "", index: calls.size };
|
|
15773
17041
|
calls.set(item.id ?? call.callId, call);
|
|
15774
|
-
yield { id, model, delta: { toolCalls: [{ id: call.callId, name: call.name, arguments: call.arguments }] } };
|
|
17042
|
+
yield { id, model, delta: { toolCalls: [{ id: call.callId, name: call.name, arguments: call.arguments, index: call.index }] } };
|
|
15775
17043
|
break;
|
|
15776
17044
|
}
|
|
15777
17045
|
case "response.function_call_arguments.delta": {
|
|
15778
17046
|
const call = calls.get(data.item_id);
|
|
15779
17047
|
if (!call || !data.delta) break;
|
|
15780
17048
|
call.arguments += data.delta;
|
|
15781
|
-
yield { id, model, delta: { toolCalls: [{ id: call.callId, arguments: data.delta }] } };
|
|
17049
|
+
yield { id, model, delta: { toolCalls: [{ id: call.callId, arguments: data.delta, index: call.index }] } };
|
|
15782
17050
|
break;
|
|
15783
17051
|
}
|
|
15784
17052
|
case "response.output_item.done": {
|
|
@@ -15787,13 +17055,13 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15787
17055
|
const full = typeof item.arguments === "string" ? item.arguments : "";
|
|
15788
17056
|
const call = calls.get(item.id ?? item.call_id);
|
|
15789
17057
|
if (!call) {
|
|
15790
|
-
const added = { callId: item.call_id ?? item.id ?? "", name: item.name ?? "", arguments: full };
|
|
17058
|
+
const added = { callId: item.call_id ?? item.id ?? "", name: item.name ?? "", arguments: full, index: calls.size };
|
|
15791
17059
|
calls.set(item.id ?? added.callId, added);
|
|
15792
|
-
yield { id, model, delta: { toolCalls: [{ id: added.callId, name: added.name, arguments: full }] } };
|
|
17060
|
+
yield { id, model, delta: { toolCalls: [{ id: added.callId, name: added.name, arguments: full, index: added.index }] } };
|
|
15793
17061
|
} else if (full.length > call.arguments.length && full.startsWith(call.arguments)) {
|
|
15794
17062
|
const rest = full.slice(call.arguments.length);
|
|
15795
17063
|
call.arguments = full;
|
|
15796
|
-
yield { id, model, delta: { toolCalls: [{ id: call.callId, arguments: rest }] } };
|
|
17064
|
+
yield { id, model, delta: { toolCalls: [{ id: call.callId, arguments: rest, index: call.index }] } };
|
|
15797
17065
|
}
|
|
15798
17066
|
break;
|
|
15799
17067
|
}
|
|
@@ -15816,18 +17084,20 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15816
17084
|
yield {
|
|
15817
17085
|
id: final?.id || id,
|
|
15818
17086
|
model: final?.model || model,
|
|
15819
|
-
|
|
17087
|
+
// Summary text already went out as deltas; do not repeat it.
|
|
17088
|
+
delta: final?.reasoning && !streamedSummary ? { reasoning: final.reasoning } : {},
|
|
15820
17089
|
usage: final?.usage,
|
|
15821
17090
|
finishReason: final?.finishReason ?? (calls.size > 0 ? "tool_calls" : "stop")
|
|
15822
17091
|
};
|
|
15823
17092
|
}
|
|
15824
|
-
buildResponsesBody(request) {
|
|
17093
|
+
buildResponsesBody(request, overlay) {
|
|
15825
17094
|
const body = {
|
|
15826
17095
|
model: request.model || this.defaultModel,
|
|
15827
17096
|
input: request.messages.map((m) => this.toResponsesInput(m))
|
|
15828
17097
|
};
|
|
15829
17098
|
if (request.maxTokens != null) body.max_output_tokens = request.maxTokens;
|
|
15830
|
-
|
|
17099
|
+
const rule = resolveModelRule({ provider: this.providerName, model: String(body.model), patch: overlay, scope: this.baseURL });
|
|
17100
|
+
if (request.topP != null && allowsSampling(rule, "topP")) body.top_p = request.topP;
|
|
15831
17101
|
if (request.tools?.length) {
|
|
15832
17102
|
body.tools = request.tools.map((t) => ({
|
|
15833
17103
|
type: "function",
|
|
@@ -15859,7 +17129,8 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15859
17129
|
}
|
|
15860
17130
|
}
|
|
15861
17131
|
if (request.extra) Object.assign(body, request.extra);
|
|
15862
|
-
applyOpenAIReasoning(body, request.reasoning, "responses");
|
|
17132
|
+
applyOpenAIReasoning(body, request.reasoning, "responses", String(body.model), rule);
|
|
17133
|
+
applyDropParams(body, rule);
|
|
15863
17134
|
return body;
|
|
15864
17135
|
}
|
|
15865
17136
|
/** Maps a unified message to a Responses API `input` item. */
|
|
@@ -15926,7 +17197,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
15926
17197
|
...this.defaultHeaders
|
|
15927
17198
|
};
|
|
15928
17199
|
const payload = JSON.stringify(body);
|
|
15929
|
-
const res = await this.doFetchWithRetry(() =>
|
|
17200
|
+
const res = await this.doFetchWithRetry(() => this.httpFetch(url, { method: "POST", headers, body: payload, signal }), signal);
|
|
15930
17201
|
if (!res.ok) {
|
|
15931
17202
|
const text = await res.text().catch(() => "");
|
|
15932
17203
|
throw new ProviderError(
|
|
@@ -16055,7 +17326,7 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
16055
17326
|
...this.defaultHeaders
|
|
16056
17327
|
};
|
|
16057
17328
|
const payload = JSON.stringify(body);
|
|
16058
|
-
const res = await this.doFetchWithRetry(() =>
|
|
17329
|
+
const res = await this.doFetchWithRetry(() => this.httpFetch(url, { method: "POST", headers, body: payload, signal }), signal);
|
|
16059
17330
|
if (!res.ok) {
|
|
16060
17331
|
const text = await res.text().catch(() => "");
|
|
16061
17332
|
throw new ProviderError(
|
|
@@ -16075,6 +17346,8 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
16075
17346
|
name: tc.function?.name ?? "",
|
|
16076
17347
|
arguments: tc.function?.arguments ?? "{}"
|
|
16077
17348
|
}));
|
|
17349
|
+
const reasoningText = extractReasoningText(message);
|
|
17350
|
+
const providerFields = pickProviderFields(json, message, choice);
|
|
16078
17351
|
return {
|
|
16079
17352
|
id: json.id ?? "",
|
|
16080
17353
|
model: json.model ?? "",
|
|
@@ -16082,6 +17355,9 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
16082
17355
|
toolCalls,
|
|
16083
17356
|
usage: this.extractUsage(json.usage),
|
|
16084
17357
|
finishReason: mapFinishReason(choice?.finish_reason),
|
|
17358
|
+
...typeof choice?.finish_reason === "string" ? { rawFinishReason: choice.finish_reason } : {},
|
|
17359
|
+
...providerFields ? { providerFields } : {},
|
|
17360
|
+
...reasoningText ? { reasoning: { summary: reasoningText } } : {},
|
|
16085
17361
|
raw: json
|
|
16086
17362
|
};
|
|
16087
17363
|
}
|
|
@@ -16100,10 +17376,27 @@ var OpenAIProvider = class _OpenAIProvider extends BaseProvider {
|
|
|
16100
17376
|
};
|
|
16101
17377
|
}
|
|
16102
17378
|
};
|
|
17379
|
+
function extractReasoningText(src) {
|
|
17380
|
+
if (!src || typeof src !== "object") return void 0;
|
|
17381
|
+
for (const key of ["reasoning_content", "reasoning"]) {
|
|
17382
|
+
const v = src[key];
|
|
17383
|
+
if (typeof v === "string" && v.length > 0) return v;
|
|
17384
|
+
}
|
|
17385
|
+
return void 0;
|
|
17386
|
+
}
|
|
17387
|
+
function pickProviderFields(top, message, choice) {
|
|
17388
|
+
const out = {};
|
|
17389
|
+
if (top?.system_fingerprint != null) out.system_fingerprint = top.system_fingerprint;
|
|
17390
|
+
if (top?.service_tier != null) out.service_tier = top.service_tier;
|
|
17391
|
+
if (message?.annotations != null) out.annotations = message.annotations;
|
|
17392
|
+
if (message?.refusal != null) out.refusal = message.refusal;
|
|
17393
|
+
if (choice?.logprobs != null) out.logprobs = choice.logprobs;
|
|
17394
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
17395
|
+
}
|
|
16103
17396
|
function isReasoningModel(model) {
|
|
16104
17397
|
if (!model) return false;
|
|
16105
|
-
const
|
|
16106
|
-
return
|
|
17398
|
+
const rule = resolveModelRule({ provider: "openai", model });
|
|
17399
|
+
return !rule.isDefault && rule.reasoning.style === "effort" && rule.sampling.temperature !== "any";
|
|
16107
17400
|
}
|
|
16108
17401
|
function adaptChatExtrasForResponses(body, extra) {
|
|
16109
17402
|
const native = extra ?? {};
|
|
@@ -16176,36 +17469,80 @@ function mapFinishReason(reason) {
|
|
|
16176
17469
|
}
|
|
16177
17470
|
}
|
|
16178
17471
|
|
|
17472
|
+
// src/providers/utils/toolChoice.ts
|
|
17473
|
+
function supportsForcedToolChoice(model) {
|
|
17474
|
+
if (typeof model !== "string") return true;
|
|
17475
|
+
const id = model.toLowerCase();
|
|
17476
|
+
const at = id.indexOf("claude-");
|
|
17477
|
+
if (at < 0) return true;
|
|
17478
|
+
const toks = id.slice(at + 7).split("-");
|
|
17479
|
+
let family = false;
|
|
17480
|
+
for (const tok of toks) {
|
|
17481
|
+
if (tok === "sonnet" || tok === "opus") {
|
|
17482
|
+
family = true;
|
|
17483
|
+
continue;
|
|
17484
|
+
}
|
|
17485
|
+
const m = /^(\d+)(?:@|:|$)/.exec(tok);
|
|
17486
|
+
if (m) {
|
|
17487
|
+
if (m[1].length > 2) continue;
|
|
17488
|
+
if (Number(m[1]) < 5) return true;
|
|
17489
|
+
if (family) return false;
|
|
17490
|
+
return !toks.some((t) => t === "sonnet" || t === "opus");
|
|
17491
|
+
}
|
|
17492
|
+
}
|
|
17493
|
+
return true;
|
|
17494
|
+
}
|
|
17495
|
+
function forcedToolChoiceRejected(text) {
|
|
17496
|
+
const t = text.toLowerCase();
|
|
17497
|
+
return t.indexOf("tool_choice") >= 0 && t.indexOf("not supported for this model") >= 0;
|
|
17498
|
+
}
|
|
17499
|
+
|
|
16179
17500
|
// src/providers/anthropic.ts
|
|
17501
|
+
var DEFAULT_MAX_TOKENS = 4096;
|
|
17502
|
+
function normalizeExplicitThinking(body) {
|
|
17503
|
+
const t = body.thinking;
|
|
17504
|
+
if (t == null) {
|
|
17505
|
+
delete body.thinking;
|
|
17506
|
+
return;
|
|
17507
|
+
}
|
|
17508
|
+
if (t.type !== "enabled") return;
|
|
17509
|
+
const budget = typeof t.budget_tokens === "number" ? t.budget_tokens : 0;
|
|
17510
|
+
if (budget > 0 && (typeof body.max_tokens !== "number" || body.max_tokens <= budget)) {
|
|
17511
|
+
body.max_tokens = budget + 1024;
|
|
17512
|
+
}
|
|
17513
|
+
for (const k of ["temperature", "top_p", "top_k"]) delete body[k];
|
|
17514
|
+
}
|
|
16180
17515
|
var AnthropicProvider = class extends BaseProvider {
|
|
16181
17516
|
constructor(config) {
|
|
16182
17517
|
super();
|
|
16183
17518
|
this.providerName = "anthropic";
|
|
17519
|
+
this.configureTransport(config);
|
|
16184
17520
|
this.apiKey = config.apiKey;
|
|
16185
17521
|
this.baseURL = (config.baseURL ?? "https://api.anthropic.com").replace(/\/$/, "");
|
|
16186
17522
|
this.defaultModel = config.defaultModel ?? "claude-sonnet-4-20250514";
|
|
16187
17523
|
this.defaultHeaders = config.defaultHeaders ?? {};
|
|
16188
17524
|
this.anthropicVersion = config.anthropicVersion ?? "2023-06-01";
|
|
17525
|
+
this.thinkingMode = config.thinkingMode ?? "auto";
|
|
16189
17526
|
this.promptCachingEnabled = config.prompt_caching?.enabled === true;
|
|
16190
17527
|
if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
|
|
16191
17528
|
}
|
|
16192
17529
|
async complete(request) {
|
|
16193
|
-
const
|
|
16194
|
-
const res = await this.doFetch(body, request.signal);
|
|
17530
|
+
const res = await this.send(request, false);
|
|
16195
17531
|
const json = await res.json();
|
|
16196
17532
|
return this.parseResponse(json);
|
|
16197
17533
|
}
|
|
16198
17534
|
async *completeStream(request) {
|
|
16199
|
-
const
|
|
16200
|
-
const res = await this.doFetch(body, request.signal);
|
|
17535
|
+
const res = await this.send(request, true);
|
|
16201
17536
|
if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
|
|
16202
17537
|
let id = "";
|
|
16203
17538
|
let model = "";
|
|
16204
17539
|
let inputTokens = 0;
|
|
16205
17540
|
let outputTokens = 0;
|
|
17541
|
+
let thinkingTokens = 0;
|
|
16206
17542
|
let cacheReadInputTokens = 0;
|
|
16207
17543
|
let cacheCreationInputTokens = 0;
|
|
16208
17544
|
const currentToolCalls = /* @__PURE__ */ new Map();
|
|
17545
|
+
let toolOrdinal = 0;
|
|
16209
17546
|
const reasoningBlocks = /* @__PURE__ */ new Map();
|
|
16210
17547
|
for await (const event of parseSSEStream(res.body, request.signal)) {
|
|
16211
17548
|
let data;
|
|
@@ -16234,8 +17571,11 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16234
17571
|
currentToolCalls.set(idx, {
|
|
16235
17572
|
id: block.id ?? "",
|
|
16236
17573
|
name: block.name ?? "",
|
|
16237
|
-
arguments: ""
|
|
17574
|
+
arguments: "",
|
|
17575
|
+
ordinal: toolOrdinal++
|
|
16238
17576
|
});
|
|
17577
|
+
const opened = currentToolCalls.get(idx);
|
|
17578
|
+
yield { id, model, delta: { toolCalls: [{ id: opened.id, name: opened.name, arguments: "", index: opened.ordinal }] } };
|
|
16239
17579
|
} else if (block?.type === "thinking") {
|
|
16240
17580
|
reasoningBlocks.set(idx, { type: "thinking", text: block.thinking ?? "", signature: block.signature });
|
|
16241
17581
|
} else if (block?.type === "redacted_thinking") {
|
|
@@ -16273,7 +17613,7 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16273
17613
|
id,
|
|
16274
17614
|
model,
|
|
16275
17615
|
delta: {
|
|
16276
|
-
toolCalls: [{ id: tc.id, name: tc.name, arguments: delta.partial_json }]
|
|
17616
|
+
toolCalls: [{ id: tc.id, name: tc.name, arguments: delta.partial_json, index: tc.ordinal }]
|
|
16277
17617
|
}
|
|
16278
17618
|
};
|
|
16279
17619
|
}
|
|
@@ -16286,8 +17626,10 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16286
17626
|
const delta = data.delta;
|
|
16287
17627
|
if (data.usage) {
|
|
16288
17628
|
outputTokens = data.usage.output_tokens ?? outputTokens;
|
|
17629
|
+
thinkingTokens = data.usage.output_tokens_details?.thinking_tokens ?? thinkingTokens;
|
|
16289
17630
|
}
|
|
16290
17631
|
const finishReason = mapAnthropicStopReason(delta?.stop_reason);
|
|
17632
|
+
const rawFinishReason = typeof delta?.stop_reason === "string" ? delta.stop_reason : void 0;
|
|
16291
17633
|
const usage = {
|
|
16292
17634
|
inputTokens,
|
|
16293
17635
|
outputTokens,
|
|
@@ -16295,7 +17637,7 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16295
17637
|
cachedInputTokens: cacheReadInputTokens,
|
|
16296
17638
|
cachedWriteTokens: cacheCreationInputTokens,
|
|
16297
17639
|
cachedOutputTokens: 0,
|
|
16298
|
-
reasoningTokens:
|
|
17640
|
+
reasoningTokens: thinkingTokens
|
|
16299
17641
|
};
|
|
16300
17642
|
const blocks = [...reasoningBlocks.values()].filter(
|
|
16301
17643
|
(b) => b.type === "thinking" && b.signature || b.type === "redacted_thinking" && b.data
|
|
@@ -16305,6 +17647,7 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16305
17647
|
model,
|
|
16306
17648
|
delta: blocks.length > 0 ? { reasoning: { blocks } } : {},
|
|
16307
17649
|
finishReason,
|
|
17650
|
+
...rawFinishReason ? { rawFinishReason } : {},
|
|
16308
17651
|
usage
|
|
16309
17652
|
};
|
|
16310
17653
|
break;
|
|
@@ -16319,12 +17662,12 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16319
17662
|
}
|
|
16320
17663
|
}
|
|
16321
17664
|
// ─── Internals ───────────────────────────────────────────────────────────
|
|
16322
|
-
buildRequestBody(request, stream) {
|
|
17665
|
+
buildRequestBody(request, stream, overlay, downgradeToolChoice = false) {
|
|
16323
17666
|
const { system, messages } = this.splitSystemMessages(request.messages);
|
|
16324
17667
|
const body = {
|
|
16325
17668
|
model: request.model || this.defaultModel,
|
|
16326
17669
|
messages: this.toAnthropicMessages(messages),
|
|
16327
|
-
max_tokens: request.maxTokens ??
|
|
17670
|
+
max_tokens: request.maxTokens ?? DEFAULT_MAX_TOKENS,
|
|
16328
17671
|
stream
|
|
16329
17672
|
};
|
|
16330
17673
|
if (system) {
|
|
@@ -16334,6 +17677,7 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16334
17677
|
body.system = system;
|
|
16335
17678
|
}
|
|
16336
17679
|
}
|
|
17680
|
+
const rule = resolveModelRule({ provider: this.providerName, model: String(body.model), patch: overlay });
|
|
16337
17681
|
if (request.temperature != null) body.temperature = request.temperature;
|
|
16338
17682
|
if (request.topP != null) body.top_p = request.topP;
|
|
16339
17683
|
if (request.stop) body.stop_sequences = request.stop;
|
|
@@ -16345,18 +17689,29 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16345
17689
|
body.tools = tools;
|
|
16346
17690
|
}
|
|
16347
17691
|
if (request.toolChoice != null) {
|
|
17692
|
+
const forceOk = !downgradeToolChoice && supportsForcedToolChoice(body.model);
|
|
16348
17693
|
if (request.toolChoice === "auto") {
|
|
16349
17694
|
body.tool_choice = { type: "auto" };
|
|
16350
17695
|
} else if (request.toolChoice === "required") {
|
|
16351
|
-
body.tool_choice = { type: "any" };
|
|
17696
|
+
body.tool_choice = forceOk ? { type: "any" } : { type: "auto" };
|
|
16352
17697
|
} else if (request.toolChoice === "none") ; else {
|
|
16353
|
-
body.tool_choice = { type: "tool", name: request.toolChoice.name };
|
|
17698
|
+
body.tool_choice = forceOk ? { type: "tool", name: request.toolChoice.name } : { type: "auto" };
|
|
16354
17699
|
}
|
|
16355
17700
|
}
|
|
16356
17701
|
if (request.extra) {
|
|
16357
17702
|
Object.assign(body, request.extra);
|
|
16358
17703
|
}
|
|
16359
|
-
|
|
17704
|
+
const explicitThinking = request.extra && typeof request.extra === "object" && "thinking" in request.extra;
|
|
17705
|
+
if (explicitThinking) {
|
|
17706
|
+
normalizeExplicitThinking(body);
|
|
17707
|
+
enforceAnthropicSampling(body, rule, body.thinking?.type === "enabled" || body.thinking?.type === "adaptive");
|
|
17708
|
+
} else {
|
|
17709
|
+
applyAnthropicReasoning(body, request.reasoning, { model: body.model, mode: this.thinkingMode, rule });
|
|
17710
|
+
}
|
|
17711
|
+
applyDropParams(body, rule);
|
|
17712
|
+
if (typeof body.max_tokens !== "number" || !(body.max_tokens > 0)) {
|
|
17713
|
+
body.max_tokens = DEFAULT_MAX_TOKENS;
|
|
17714
|
+
}
|
|
16360
17715
|
return body;
|
|
16361
17716
|
}
|
|
16362
17717
|
splitSystemMessages(messages) {
|
|
@@ -16487,6 +17842,31 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16487
17842
|
input_schema: t.parameters
|
|
16488
17843
|
};
|
|
16489
17844
|
}
|
|
17845
|
+
/** Builds and sends the request; retries once with the other thinking form
|
|
17846
|
+
* when the upstream rejects the one we picked. */
|
|
17847
|
+
send(request, stream) {
|
|
17848
|
+
let downgrade = false;
|
|
17849
|
+
return runWithModelAdjustments({
|
|
17850
|
+
provider: this.providerName,
|
|
17851
|
+
model: request.model || this.defaultModel,
|
|
17852
|
+
endpoint: "messages",
|
|
17853
|
+
callerParams: request.extra ? Object.keys(request.extra) : void 0,
|
|
17854
|
+
onLearned: this.onModelRuleLearned,
|
|
17855
|
+
run: async (overlay, guard) => {
|
|
17856
|
+
for (; ; ) {
|
|
17857
|
+
const body = this.buildRequestBody(request, stream, overlay, downgrade);
|
|
17858
|
+
guard(body);
|
|
17859
|
+
try {
|
|
17860
|
+
return await this.doFetch(body, request.signal);
|
|
17861
|
+
} catch (err) {
|
|
17862
|
+
const rejected = err instanceof ProviderError && err.statusCode === 400 && !downgrade && body.tool_choice && body.tool_choice.type !== "auto" && forcedToolChoiceRejected(String(err.responseBody ?? err.message));
|
|
17863
|
+
if (!rejected) throw err;
|
|
17864
|
+
downgrade = true;
|
|
17865
|
+
}
|
|
17866
|
+
}
|
|
17867
|
+
}
|
|
17868
|
+
});
|
|
17869
|
+
}
|
|
16490
17870
|
async doFetch(body, signal) {
|
|
16491
17871
|
const url = `${this.baseURL}/v1/messages`;
|
|
16492
17872
|
const headers = {
|
|
@@ -16496,7 +17876,7 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16496
17876
|
...this.defaultHeaders
|
|
16497
17877
|
};
|
|
16498
17878
|
const payload = JSON.stringify(body);
|
|
16499
|
-
const res = await this.doFetchWithRetry(() =>
|
|
17879
|
+
const res = await this.doFetchWithRetry(() => this.httpFetch(url, { method: "POST", headers, body: payload, signal }), signal);
|
|
16500
17880
|
if (!res.ok) {
|
|
16501
17881
|
const text = await res.text().catch(() => "");
|
|
16502
17882
|
throw new ProviderError(
|
|
@@ -16541,10 +17921,9 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16541
17921
|
cachedInputTokens: usage.cache_read_input_tokens ?? 0,
|
|
16542
17922
|
cachedWriteTokens: usage.cache_creation_input_tokens ?? 0,
|
|
16543
17923
|
cachedOutputTokens: 0,
|
|
16544
|
-
//
|
|
16545
|
-
//
|
|
16546
|
-
|
|
16547
|
-
reasoningTokens: 0
|
|
17924
|
+
// Thinking tokens are billed inside `output_tokens`; newer models also
|
|
17925
|
+
// report the split as `output_tokens_details.thinking_tokens`.
|
|
17926
|
+
reasoningTokens: usage.output_tokens_details?.thinking_tokens ?? 0
|
|
16548
17927
|
};
|
|
16549
17928
|
return {
|
|
16550
17929
|
id: json.id ?? "",
|
|
@@ -16553,6 +17932,7 @@ var AnthropicProvider = class extends BaseProvider {
|
|
|
16553
17932
|
toolCalls,
|
|
16554
17933
|
usage: tokenUsage,
|
|
16555
17934
|
finishReason: mapAnthropicStopReason(json.stop_reason),
|
|
17935
|
+
...typeof json.stop_reason === "string" ? { rawFinishReason: json.stop_reason } : {},
|
|
16556
17936
|
reasoning: reasoningBlocks.length > 0 ? { blocks: reasoningBlocks, summary: summaryParts.join("\n").trim() || void 0 } : void 0,
|
|
16557
17937
|
raw: json
|
|
16558
17938
|
};
|
|
@@ -16598,7 +17978,16 @@ var AzureProvider = class extends OpenAIProvider {
|
|
|
16598
17978
|
provider: "openai",
|
|
16599
17979
|
apiKey: config.apiKey,
|
|
16600
17980
|
defaultModel: config.defaultModel ?? config.deploymentName ?? "gpt-4o",
|
|
16601
|
-
defaultHeaders: config.defaultHeaders
|
|
17981
|
+
defaultHeaders: config.defaultHeaders,
|
|
17982
|
+
retry: config.retry,
|
|
17983
|
+
fetch: config.fetch,
|
|
17984
|
+
timeoutMs: config.timeoutMs,
|
|
17985
|
+
onModelRuleLearned: config.onModelRuleLearned,
|
|
17986
|
+
maxTokensParam: config.maxTokensParam,
|
|
17987
|
+
api: config.api,
|
|
17988
|
+
responsesApi: config.responsesApi,
|
|
17989
|
+
responsesApiModels: config.responsesApiModels,
|
|
17990
|
+
responsesStreaming: config.responsesStreaming
|
|
16602
17991
|
});
|
|
16603
17992
|
this.providerName = "azure";
|
|
16604
17993
|
this.endpoint = config.endpoint.replace(/\/$/, "");
|
|
@@ -16613,16 +18002,17 @@ var AzureProvider = class extends OpenAIProvider {
|
|
|
16613
18002
|
}
|
|
16614
18003
|
const url = `${this.endpoint}/openai/deployments/${deployment}/chat/completions?api-version=${this.apiVersion}`;
|
|
16615
18004
|
const { model: _model, ...bodyWithoutModel } = body;
|
|
16616
|
-
const
|
|
18005
|
+
const payload = JSON.stringify(bodyWithoutModel);
|
|
18006
|
+
const res = await this.doFetchWithRetry(() => this.httpFetch(url, {
|
|
16617
18007
|
method: "POST",
|
|
16618
18008
|
headers: {
|
|
16619
18009
|
"Content-Type": "application/json",
|
|
16620
18010
|
"api-key": this.azureApiKey,
|
|
16621
18011
|
...this.defaultHeaders
|
|
16622
18012
|
},
|
|
16623
|
-
body:
|
|
18013
|
+
body: payload,
|
|
16624
18014
|
signal
|
|
16625
|
-
});
|
|
18015
|
+
}), signal);
|
|
16626
18016
|
if (!res.ok) {
|
|
16627
18017
|
const text = await res.text().catch(() => "");
|
|
16628
18018
|
throw new ProviderError(
|
|
@@ -16634,6 +18024,32 @@ var AzureProvider = class extends OpenAIProvider {
|
|
|
16634
18024
|
}
|
|
16635
18025
|
return res;
|
|
16636
18026
|
}
|
|
18027
|
+
/** Azure embeddings: the deployment named by the request's model (falling back
|
|
18028
|
+
* to the configured deployment) in the path, api-key auth. */
|
|
18029
|
+
async embeddingsFetch(body, signal) {
|
|
18030
|
+
const deployment = body.model || this.deploymentName;
|
|
18031
|
+
if (!deployment) {
|
|
18032
|
+
throw new ProviderError("Azure embeddings require a deployment name or model", this.providerName, 400);
|
|
18033
|
+
}
|
|
18034
|
+
const url = `${this.endpoint}/openai/deployments/${deployment}/embeddings?api-version=${this.apiVersion}`;
|
|
18035
|
+
const { model: _model, ...bodyWithoutModel } = body;
|
|
18036
|
+
const payload = JSON.stringify(bodyWithoutModel);
|
|
18037
|
+
const res = await this.doFetchWithRetry(() => this.httpFetch(url, {
|
|
18038
|
+
method: "POST",
|
|
18039
|
+
headers: {
|
|
18040
|
+
"Content-Type": "application/json",
|
|
18041
|
+
"api-key": this.azureApiKey,
|
|
18042
|
+
...this.defaultHeaders
|
|
18043
|
+
},
|
|
18044
|
+
body: payload,
|
|
18045
|
+
signal
|
|
18046
|
+
}), signal);
|
|
18047
|
+
if (!res.ok) {
|
|
18048
|
+
const text = await res.text().catch(() => "");
|
|
18049
|
+
throw new ProviderError(`Azure OpenAI embeddings API error ${res.status}: ${text}`, this.providerName, res.status, text);
|
|
18050
|
+
}
|
|
18051
|
+
return res;
|
|
18052
|
+
}
|
|
16637
18053
|
/** Azure exposes the Responses API at /openai/responses with api-key auth.
|
|
16638
18054
|
* Reasoning summaries require a preview api-version; callers can override via
|
|
16639
18055
|
* the `apiVersion` config. */
|
|
@@ -16645,7 +18061,7 @@ var AzureProvider = class extends OpenAIProvider {
|
|
|
16645
18061
|
}
|
|
16646
18062
|
const url = `${this.endpoint}/openai/responses?api-version=${this.apiVersion}`;
|
|
16647
18063
|
const payload = JSON.stringify({ ...body, model: deployment });
|
|
16648
|
-
const res = await
|
|
18064
|
+
const res = await this.doFetchWithRetry(() => this.httpFetch(url, {
|
|
16649
18065
|
method: "POST",
|
|
16650
18066
|
headers: {
|
|
16651
18067
|
"Content-Type": "application/json",
|
|
@@ -16654,7 +18070,7 @@ var AzureProvider = class extends OpenAIProvider {
|
|
|
16654
18070
|
},
|
|
16655
18071
|
body: payload,
|
|
16656
18072
|
signal
|
|
16657
|
-
});
|
|
18073
|
+
}), signal);
|
|
16658
18074
|
if (!res.ok) {
|
|
16659
18075
|
const text = await res.text().catch(() => "");
|
|
16660
18076
|
throw new ProviderError(
|
|
@@ -16690,20 +18106,156 @@ var OpenAICompatibleProvider = class extends OpenAIProvider {
|
|
|
16690
18106
|
apiKey: config.apiKey,
|
|
16691
18107
|
baseURL: config.baseURL,
|
|
16692
18108
|
defaultModel: config.defaultModel,
|
|
16693
|
-
defaultHeaders: config.defaultHeaders
|
|
18109
|
+
defaultHeaders: config.defaultHeaders,
|
|
18110
|
+
organization: config.organization,
|
|
18111
|
+
retry: config.retry,
|
|
18112
|
+
fetch: config.fetch,
|
|
18113
|
+
timeoutMs: config.timeoutMs,
|
|
18114
|
+
onModelRuleLearned: config.onModelRuleLearned,
|
|
18115
|
+
maxTokensParam: config.maxTokensParam,
|
|
18116
|
+
api: config.api,
|
|
18117
|
+
// Unlike OpenAI / Azure, "auto" on a compatible server means Chat
|
|
18118
|
+
// Completions (the 0.11 default): the model name is the operator's.
|
|
18119
|
+
// `responsesApiModels` still applies; `responsesApi: "auto"` opts in.
|
|
18120
|
+
_autoMeansChat: true,
|
|
18121
|
+
responsesApi: config.responsesApi,
|
|
18122
|
+
responsesApiModels: config.responsesApiModels,
|
|
18123
|
+
responsesStreaming: config.responsesStreaming
|
|
16694
18124
|
});
|
|
16695
18125
|
this.providerName = "openai-compatible";
|
|
16696
18126
|
}
|
|
16697
18127
|
};
|
|
16698
18128
|
|
|
18129
|
+
// src/providers/utils/eventStream.ts
|
|
18130
|
+
var EventStreamError = class extends Error {
|
|
18131
|
+
constructor(message) {
|
|
18132
|
+
super(message);
|
|
18133
|
+
this.name = "EventStreamError";
|
|
18134
|
+
}
|
|
18135
|
+
};
|
|
18136
|
+
var CRC_TABLE = (() => {
|
|
18137
|
+
const table = new Uint32Array(256);
|
|
18138
|
+
for (let n = 0; n < 256; n++) {
|
|
18139
|
+
let c = n;
|
|
18140
|
+
for (let k = 0; k < 8; k++) c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
|
|
18141
|
+
table[n] = c >>> 0;
|
|
18142
|
+
}
|
|
18143
|
+
return table;
|
|
18144
|
+
})();
|
|
18145
|
+
function crc32(bytes, start = 0, end = bytes.length) {
|
|
18146
|
+
let c = 4294967295;
|
|
18147
|
+
for (let i = start; i < end; i++) c = CRC_TABLE[(c ^ bytes[i]) & 255] ^ c >>> 8;
|
|
18148
|
+
return (c ^ 4294967295) >>> 0;
|
|
18149
|
+
}
|
|
18150
|
+
function decodeFrame(frame) {
|
|
18151
|
+
const view = new DataView(frame.buffer, frame.byteOffset, frame.byteLength);
|
|
18152
|
+
const total = view.getUint32(0);
|
|
18153
|
+
const headersLen = view.getUint32(4);
|
|
18154
|
+
if (total !== frame.byteLength) throw new EventStreamError("event-stream frame length mismatch");
|
|
18155
|
+
if (crc32(frame, 0, 8) !== view.getUint32(8)) throw new EventStreamError("event-stream prelude CRC mismatch");
|
|
18156
|
+
if (crc32(frame, 0, total - 4) !== view.getUint32(total - 4)) throw new EventStreamError("event-stream message CRC mismatch");
|
|
18157
|
+
if (12 + headersLen > total - 4) throw new EventStreamError("event-stream headers overflow frame");
|
|
18158
|
+
const headers = {};
|
|
18159
|
+
const td = new TextDecoder();
|
|
18160
|
+
let o = 12;
|
|
18161
|
+
const headersEnd = 12 + headersLen;
|
|
18162
|
+
while (o < headersEnd) {
|
|
18163
|
+
const nameLen = frame[o++];
|
|
18164
|
+
const name = td.decode(frame.subarray(o, o + nameLen));
|
|
18165
|
+
o += nameLen;
|
|
18166
|
+
const type = frame[o++];
|
|
18167
|
+
switch (type) {
|
|
18168
|
+
case 0:
|
|
18169
|
+
headers[name] = true;
|
|
18170
|
+
break;
|
|
18171
|
+
case 1:
|
|
18172
|
+
headers[name] = false;
|
|
18173
|
+
break;
|
|
18174
|
+
case 2:
|
|
18175
|
+
headers[name] = view.getInt8(o);
|
|
18176
|
+
o += 1;
|
|
18177
|
+
break;
|
|
18178
|
+
case 3:
|
|
18179
|
+
headers[name] = view.getInt16(o);
|
|
18180
|
+
o += 2;
|
|
18181
|
+
break;
|
|
18182
|
+
case 4:
|
|
18183
|
+
headers[name] = view.getInt32(o);
|
|
18184
|
+
o += 4;
|
|
18185
|
+
break;
|
|
18186
|
+
case 5:
|
|
18187
|
+
headers[name] = view.getBigInt64(o);
|
|
18188
|
+
o += 8;
|
|
18189
|
+
break;
|
|
18190
|
+
case 6: {
|
|
18191
|
+
const len = view.getUint16(o);
|
|
18192
|
+
o += 2;
|
|
18193
|
+
headers[name] = frame.slice(o, o + len);
|
|
18194
|
+
o += len;
|
|
18195
|
+
break;
|
|
18196
|
+
}
|
|
18197
|
+
case 7: {
|
|
18198
|
+
const len = view.getUint16(o);
|
|
18199
|
+
o += 2;
|
|
18200
|
+
headers[name] = td.decode(frame.subarray(o, o + len));
|
|
18201
|
+
o += len;
|
|
18202
|
+
break;
|
|
18203
|
+
}
|
|
18204
|
+
case 8:
|
|
18205
|
+
headers[name] = view.getBigInt64(o);
|
|
18206
|
+
o += 8;
|
|
18207
|
+
break;
|
|
18208
|
+
case 9:
|
|
18209
|
+
headers[name] = frame.slice(o, o + 16);
|
|
18210
|
+
o += 16;
|
|
18211
|
+
break;
|
|
18212
|
+
default:
|
|
18213
|
+
throw new EventStreamError(`unknown event-stream header type ${type}`);
|
|
18214
|
+
}
|
|
18215
|
+
}
|
|
18216
|
+
return { headers, payload: frame.slice(headersEnd, total - 4) };
|
|
18217
|
+
}
|
|
18218
|
+
async function* parseEventStream(body, signal) {
|
|
18219
|
+
const reader = body.getReader();
|
|
18220
|
+
let buf = new Uint8Array(0);
|
|
18221
|
+
try {
|
|
18222
|
+
while (true) {
|
|
18223
|
+
if (signal?.aborted) throw abortReason(signal);
|
|
18224
|
+
const { done, value } = await reader.read();
|
|
18225
|
+
if (done) break;
|
|
18226
|
+
if (!value?.length) continue;
|
|
18227
|
+
const merged = new Uint8Array(buf.length + value.length);
|
|
18228
|
+
merged.set(buf, 0);
|
|
18229
|
+
merged.set(value, buf.length);
|
|
18230
|
+
buf = merged;
|
|
18231
|
+
while (buf.length >= 12) {
|
|
18232
|
+
const total = new DataView(buf.buffer, buf.byteOffset, buf.byteLength).getUint32(0);
|
|
18233
|
+
if (total < 16) throw new EventStreamError("invalid event-stream frame length");
|
|
18234
|
+
if (buf.length < total) break;
|
|
18235
|
+
yield decodeFrame(buf.subarray(0, total));
|
|
18236
|
+
buf = buf.subarray(total);
|
|
18237
|
+
}
|
|
18238
|
+
}
|
|
18239
|
+
if (buf.length > 0) throw new EventStreamError("event-stream ended inside a frame");
|
|
18240
|
+
} finally {
|
|
18241
|
+
reader.cancel().catch(() => void 0);
|
|
18242
|
+
try {
|
|
18243
|
+
reader.releaseLock();
|
|
18244
|
+
} catch {
|
|
18245
|
+
}
|
|
18246
|
+
}
|
|
18247
|
+
}
|
|
18248
|
+
|
|
16699
18249
|
// src/providers/bedrock.ts
|
|
16700
18250
|
var BedrockProvider = class extends BaseProvider {
|
|
16701
18251
|
constructor(config) {
|
|
16702
18252
|
super();
|
|
16703
18253
|
this.providerName = "bedrock";
|
|
18254
|
+
this.configureTransport(config);
|
|
16704
18255
|
this.region = config.region;
|
|
16705
18256
|
this.defaultModel = config.defaultModel ?? "anthropic.claude-sonnet-4-20250514-v1:0";
|
|
16706
18257
|
this.defaultHeaders = config.defaultHeaders ?? {};
|
|
18258
|
+
this.thinkingMode = config.thinkingMode ?? "auto";
|
|
16707
18259
|
this.promptCachingEnabled = config.prompt_caching?.enabled === true;
|
|
16708
18260
|
if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
|
|
16709
18261
|
this.credentials = {
|
|
@@ -16720,25 +18272,202 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16720
18272
|
}
|
|
16721
18273
|
async complete(request) {
|
|
16722
18274
|
const modelId = request.model || this.defaultModel;
|
|
16723
|
-
const
|
|
16724
|
-
|
|
16725
|
-
return this.parseResponse(json, modelId);
|
|
18275
|
+
const res = await this.converseFetch(modelId, request, false);
|
|
18276
|
+
return this.parseResponse(await res.json(), modelId);
|
|
16726
18277
|
}
|
|
18278
|
+
/**
|
|
18279
|
+
* Real streaming over ConverseStream. The response is an AWS event-stream
|
|
18280
|
+
* (binary frames); each frame carries one JSON event: messageStart,
|
|
18281
|
+
* contentBlockStart/Delta/Stop (text, toolUse, reasoningContent),
|
|
18282
|
+
* messageStop and, last, metadata (usage). Text, tool-call argument and
|
|
18283
|
+
* reasoning deltas are yielded as they arrive; one closing chunk carries the
|
|
18284
|
+
* finish reason, usage and the signed reasoning blocks.
|
|
18285
|
+
*/
|
|
16727
18286
|
async *completeStream(request) {
|
|
16728
|
-
const
|
|
18287
|
+
const modelId = request.model || this.defaultModel;
|
|
18288
|
+
const res = await this.converseFetch(modelId, request, true);
|
|
18289
|
+
if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
|
|
18290
|
+
const id = res.headers.get("x-amzn-requestid") ?? "";
|
|
18291
|
+
const toolsByIndex = /* @__PURE__ */ new Map();
|
|
18292
|
+
const reasoningByIndex = /* @__PURE__ */ new Map();
|
|
18293
|
+
let finishReason;
|
|
18294
|
+
let rawFinishReason;
|
|
18295
|
+
let toolOrdinal = 0;
|
|
18296
|
+
let usage;
|
|
18297
|
+
for await (const msg of parseEventStream(res.body, request.signal)) {
|
|
18298
|
+
const messageType = String(msg.headers[":message-type"] ?? "event");
|
|
18299
|
+
const eventType = String(msg.headers[":event-type"] ?? msg.headers[":exception-type"] ?? "");
|
|
18300
|
+
let data = {};
|
|
18301
|
+
const text = new TextDecoder().decode(msg.payload);
|
|
18302
|
+
if (text) {
|
|
18303
|
+
try {
|
|
18304
|
+
data = JSON.parse(text);
|
|
18305
|
+
} catch {
|
|
18306
|
+
data = { message: text };
|
|
18307
|
+
}
|
|
18308
|
+
}
|
|
18309
|
+
if (messageType === "exception" || messageType === "error") {
|
|
18310
|
+
const code = String(msg.headers[":exception-type"] ?? msg.headers[":error-code"] ?? eventType);
|
|
18311
|
+
throw new ProviderError(
|
|
18312
|
+
`Bedrock stream error ${code}: ${data.message ?? text}`,
|
|
18313
|
+
this.providerName,
|
|
18314
|
+
bedrockExceptionStatus(code),
|
|
18315
|
+
data
|
|
18316
|
+
);
|
|
18317
|
+
}
|
|
18318
|
+
switch (eventType) {
|
|
18319
|
+
case "contentBlockStart": {
|
|
18320
|
+
const idx = data.contentBlockIndex ?? 0;
|
|
18321
|
+
const tu = data.start?.toolUse;
|
|
18322
|
+
if (tu) {
|
|
18323
|
+
const ordinal = toolOrdinal++;
|
|
18324
|
+
toolsByIndex.set(idx, { id: tu.toolUseId ?? "", name: tu.name ?? "", ordinal });
|
|
18325
|
+
yield { id, model: modelId, delta: { toolCalls: [{ id: tu.toolUseId, name: tu.name, arguments: "", index: ordinal }] } };
|
|
18326
|
+
}
|
|
18327
|
+
break;
|
|
18328
|
+
}
|
|
18329
|
+
case "contentBlockDelta": {
|
|
18330
|
+
const idx = data.contentBlockIndex ?? 0;
|
|
18331
|
+
const d = data.delta ?? {};
|
|
18332
|
+
if (typeof d.text === "string" && d.text) {
|
|
18333
|
+
yield { id, model: modelId, delta: { content: d.text } };
|
|
18334
|
+
} else if (d.toolUse) {
|
|
18335
|
+
const tc = toolsByIndex.get(idx);
|
|
18336
|
+
if (tc && typeof d.toolUse.input === "string" && d.toolUse.input) {
|
|
18337
|
+
yield { id, model: modelId, delta: { toolCalls: [{ id: tc.id, name: tc.name, arguments: d.toolUse.input, index: tc.ordinal }] } };
|
|
18338
|
+
}
|
|
18339
|
+
} else if (d.reasoningContent) {
|
|
18340
|
+
const rc = d.reasoningContent;
|
|
18341
|
+
const blk = reasoningByIndex.get(idx) ?? { type: "thinking", text: "" };
|
|
18342
|
+
if (typeof rc.text === "string" && rc.text) {
|
|
18343
|
+
blk.text = (blk.text ?? "") + rc.text;
|
|
18344
|
+
reasoningByIndex.set(idx, blk);
|
|
18345
|
+
yield { id, model: modelId, delta: { reasoning: { summary: rc.text } } };
|
|
18346
|
+
}
|
|
18347
|
+
if (typeof rc.signature === "string" && rc.signature) {
|
|
18348
|
+
blk.signature = (blk.signature ?? "") + rc.signature;
|
|
18349
|
+
reasoningByIndex.set(idx, blk);
|
|
18350
|
+
}
|
|
18351
|
+
if (rc.redactedContent) {
|
|
18352
|
+
reasoningByIndex.set(idx, { type: "redacted_thinking", data: rc.redactedContent });
|
|
18353
|
+
}
|
|
18354
|
+
}
|
|
18355
|
+
break;
|
|
18356
|
+
}
|
|
18357
|
+
case "messageStop":
|
|
18358
|
+
finishReason = mapBedrockStopReason(data.stopReason);
|
|
18359
|
+
if (typeof data.stopReason === "string") rawFinishReason = data.stopReason;
|
|
18360
|
+
break;
|
|
18361
|
+
case "metadata": {
|
|
18362
|
+
const u = data.usage ?? {};
|
|
18363
|
+
usage = {
|
|
18364
|
+
inputTokens: u.inputTokens ?? 0,
|
|
18365
|
+
outputTokens: u.outputTokens ?? 0,
|
|
18366
|
+
totalTokens: u.totalTokens ?? (u.inputTokens ?? 0) + (u.outputTokens ?? 0),
|
|
18367
|
+
cachedInputTokens: u.cacheReadInputTokens ?? u.cacheReadInputTokenCount ?? 0,
|
|
18368
|
+
cachedWriteTokens: u.cacheWriteInputTokens ?? u.cacheWriteInputTokenCount ?? 0,
|
|
18369
|
+
cachedOutputTokens: 0,
|
|
18370
|
+
reasoningTokens: 0
|
|
18371
|
+
};
|
|
18372
|
+
break;
|
|
18373
|
+
}
|
|
18374
|
+
}
|
|
18375
|
+
}
|
|
18376
|
+
const blocks = [...reasoningByIndex.values()].filter(
|
|
18377
|
+
(b) => b.type === "thinking" && b.signature || b.type === "redacted_thinking" && b.data
|
|
18378
|
+
);
|
|
16729
18379
|
yield {
|
|
16730
|
-
id
|
|
16731
|
-
model:
|
|
16732
|
-
delta: {
|
|
16733
|
-
|
|
16734
|
-
|
|
16735
|
-
|
|
16736
|
-
usage: response.usage,
|
|
16737
|
-
finishReason: response.finishReason
|
|
18380
|
+
id,
|
|
18381
|
+
model: modelId,
|
|
18382
|
+
delta: blocks.length > 0 ? { reasoning: { blocks } } : {},
|
|
18383
|
+
finishReason: finishReason ?? "stop",
|
|
18384
|
+
...rawFinishReason ? { rawFinishReason } : {},
|
|
18385
|
+
usage
|
|
16738
18386
|
};
|
|
16739
18387
|
}
|
|
18388
|
+
// ─── Embeddings ──────────────────────────────────────────────────────────
|
|
18389
|
+
/**
|
|
18390
|
+
* InvokeModel embeddings. Supported families (by model id, inference-profile
|
|
18391
|
+
* prefixes such as `us.` allowed):
|
|
18392
|
+
* - Amazon Titan Text Embeddings (v1, v2): one text per call, `dimensions`
|
|
18393
|
+
* (v2: 256/512/1024) and `normalize` via `extra`.
|
|
18394
|
+
* - Cohere Embed (v3, v4): a batch of texts per call (default 96), `inputType`
|
|
18395
|
+
* maps to `input_type`, `dimensions` to `output_dimension` (v4).
|
|
18396
|
+
*/
|
|
18397
|
+
async embed(request) {
|
|
18398
|
+
const model = requireEmbeddingModel(this.providerName, request.model);
|
|
18399
|
+
const id = model.toLowerCase();
|
|
18400
|
+
const raw = [];
|
|
18401
|
+
let inputTokens = 0;
|
|
18402
|
+
let vectors = [];
|
|
18403
|
+
if (id.includes("titan-embed")) {
|
|
18404
|
+
const results = await mapWithConcurrency(request.input, 4, async (text) => {
|
|
18405
|
+
const body = { inputText: text };
|
|
18406
|
+
if (request.dimensions != null && !id.includes("titan-embed-text-v1")) body.dimensions = request.dimensions;
|
|
18407
|
+
if (request.extra) Object.assign(body, request.extra);
|
|
18408
|
+
const res = await this.invokeModel(model, body, request.signal);
|
|
18409
|
+
const json = await res.json();
|
|
18410
|
+
return { json, tokens: json.inputTextTokenCount ?? Number(res.headers.get("x-amzn-bedrock-input-token-count") ?? 0) };
|
|
18411
|
+
}, request.signal);
|
|
18412
|
+
for (const r of results) {
|
|
18413
|
+
raw.push(r.json);
|
|
18414
|
+
inputTokens += r.tokens || 0;
|
|
18415
|
+
vectors.push(r.json.embedding ?? r.json.embeddingsByType?.float);
|
|
18416
|
+
}
|
|
18417
|
+
} else if (id.includes("cohere.embed")) {
|
|
18418
|
+
for (const batch of chunkArray(request.input, request.batchSize ?? 96)) {
|
|
18419
|
+
const body = {
|
|
18420
|
+
texts: batch,
|
|
18421
|
+
input_type: request.inputType ?? "search_document",
|
|
18422
|
+
embedding_types: ["float"]
|
|
18423
|
+
};
|
|
18424
|
+
if (request.dimensions != null) body.output_dimension = request.dimensions;
|
|
18425
|
+
if (request.extra) Object.assign(body, request.extra);
|
|
18426
|
+
const res = await this.invokeModel(model, body, request.signal);
|
|
18427
|
+
const json = await res.json();
|
|
18428
|
+
raw.push(json);
|
|
18429
|
+
const emb = Array.isArray(json.embeddings) ? json.embeddings : json.embeddings?.float;
|
|
18430
|
+
vectors.push(...emb ?? []);
|
|
18431
|
+
inputTokens += Number(res.headers.get("x-amzn-bedrock-input-token-count") ?? 0) || 0;
|
|
18432
|
+
}
|
|
18433
|
+
} else {
|
|
18434
|
+
throw new ProviderError(
|
|
18435
|
+
`Bedrock embeddings are supported for Amazon Titan and Cohere Embed models, not "${model}"`,
|
|
18436
|
+
this.providerName,
|
|
18437
|
+
400
|
|
18438
|
+
);
|
|
18439
|
+
}
|
|
18440
|
+
assertVectorCount(this.providerName, vectors, request.input.length);
|
|
18441
|
+
return { model, vectors, usage: { inputTokens, totalTokens: inputTokens }, raw };
|
|
18442
|
+
}
|
|
18443
|
+
async invokeModel(modelId, body, signal) {
|
|
18444
|
+
const host = `bedrock-runtime.${this.region}.amazonaws.com`;
|
|
18445
|
+
const url = `https://${host}/model/${encodeURIComponent(modelId)}/invoke`;
|
|
18446
|
+
const bodyStr = JSON.stringify(body);
|
|
18447
|
+
const res = await this.doFetchWithRetry(() => {
|
|
18448
|
+
const headers = signRequest({
|
|
18449
|
+
method: "POST",
|
|
18450
|
+
url,
|
|
18451
|
+
headers: {
|
|
18452
|
+
"Content-Type": "application/json",
|
|
18453
|
+
Accept: "application/json",
|
|
18454
|
+
...this.defaultHeaders
|
|
18455
|
+
},
|
|
18456
|
+
body: bodyStr,
|
|
18457
|
+
region: this.region,
|
|
18458
|
+
service: "bedrock",
|
|
18459
|
+
credentials: this.credentials
|
|
18460
|
+
});
|
|
18461
|
+
return this.httpFetch(url, { method: "POST", headers, body: bodyStr, signal });
|
|
18462
|
+
}, signal);
|
|
18463
|
+
if (!res.ok) {
|
|
18464
|
+
const text = await res.text().catch(() => "");
|
|
18465
|
+
throw new ProviderError(`Bedrock API error ${res.status}: ${text}`, this.providerName, res.status, text);
|
|
18466
|
+
}
|
|
18467
|
+
return res;
|
|
18468
|
+
}
|
|
16740
18469
|
// ─── Internals ───────────────────────────────────────────────────────────
|
|
16741
|
-
buildConverseBody(request) {
|
|
18470
|
+
buildConverseBody(request, downgradeToolChoice = false, overlay) {
|
|
16742
18471
|
const { system, messages } = this.splitSystemMessages(request.messages);
|
|
16743
18472
|
const body = {
|
|
16744
18473
|
messages: this.toBedrockMessages(messages)
|
|
@@ -16762,8 +18491,9 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16762
18491
|
body.toolConfig = {
|
|
16763
18492
|
tools
|
|
16764
18493
|
};
|
|
18494
|
+
const forceOk = !downgradeToolChoice && supportsForcedToolChoice(request.model || this.defaultModel);
|
|
16765
18495
|
if (request.toolChoice != null) {
|
|
16766
|
-
if (request.toolChoice === "auto") {
|
|
18496
|
+
if (request.toolChoice === "auto" || !forceOk && request.toolChoice !== "none") {
|
|
16767
18497
|
body.toolConfig.toolChoice = { auto: {} };
|
|
16768
18498
|
} else if (request.toolChoice === "required") {
|
|
16769
18499
|
body.toolConfig.toolChoice = { any: {} };
|
|
@@ -16773,9 +18503,22 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16773
18503
|
}
|
|
16774
18504
|
}
|
|
16775
18505
|
if (request.extra) {
|
|
16776
|
-
|
|
16777
|
-
|
|
16778
|
-
|
|
18506
|
+
const fields = { ...request.extra.additionalModelRequestFields ?? {} };
|
|
18507
|
+
const topLevel = { ...request.extra.__top ?? {} };
|
|
18508
|
+
for (const [key, value] of Object.entries(request.extra)) {
|
|
18509
|
+
if (key === "additionalModelRequestFields" || key === "__top") continue;
|
|
18510
|
+
if (CONVERSE_TOP_LEVEL_FIELDS.has(key)) body[key] = value;
|
|
18511
|
+
else fields[key] = value;
|
|
18512
|
+
}
|
|
18513
|
+
Object.assign(body, topLevel);
|
|
18514
|
+
if (Object.keys(fields).length > 0) body.additionalModelRequestFields = fields;
|
|
18515
|
+
}
|
|
18516
|
+
const rule = resolveModelRule({ provider: this.providerName, model: request.model || this.defaultModel, patch: overlay });
|
|
18517
|
+
applyBedrockReasoning(body, request.reasoning, { model: request.model || this.defaultModel, mode: this.thinkingMode, rule });
|
|
18518
|
+
if (body.inferenceConfig && rule.dropParams?.length) {
|
|
18519
|
+
for (const p of rule.dropParams) delete body.inferenceConfig[p === "top_p" ? "topP" : p === "max_tokens" ? "maxTokens" : p];
|
|
18520
|
+
}
|
|
18521
|
+
applyDropParams(body, rule);
|
|
16779
18522
|
return body;
|
|
16780
18523
|
}
|
|
16781
18524
|
splitSystemMessages(messages) {
|
|
@@ -16898,9 +18641,35 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16898
18641
|
}
|
|
16899
18642
|
};
|
|
16900
18643
|
}
|
|
16901
|
-
|
|
18644
|
+
/** Sends the Converse call; retries once with toolChoice auto when the
|
|
18645
|
+
* model rejects forced tool use. */
|
|
18646
|
+
converseFetch(modelId, request, stream) {
|
|
18647
|
+
let downgrade = false;
|
|
18648
|
+
return runWithModelAdjustments({
|
|
18649
|
+
provider: this.providerName,
|
|
18650
|
+
model: modelId,
|
|
18651
|
+
endpoint: "converse",
|
|
18652
|
+
callerParams: request.extra ? Object.keys(request.extra) : void 0,
|
|
18653
|
+
onLearned: this.onModelRuleLearned,
|
|
18654
|
+
run: async (overlay, guard) => {
|
|
18655
|
+
for (; ; ) {
|
|
18656
|
+
const body = this.buildConverseBody(request, downgrade, overlay);
|
|
18657
|
+
guard(body);
|
|
18658
|
+
try {
|
|
18659
|
+
return await this.doFetch(modelId, body, request.signal, stream);
|
|
18660
|
+
} catch (err) {
|
|
18661
|
+
const tc = body.toolConfig?.toolChoice;
|
|
18662
|
+
const rejected = err instanceof ProviderError && err.statusCode === 400 && !downgrade && !!tc && !tc.auto && forcedToolChoiceRejected(String(err.responseBody ?? err.message));
|
|
18663
|
+
if (!rejected) throw err;
|
|
18664
|
+
downgrade = true;
|
|
18665
|
+
}
|
|
18666
|
+
}
|
|
18667
|
+
}
|
|
18668
|
+
});
|
|
18669
|
+
}
|
|
18670
|
+
async doFetch(modelId, body, signal, stream) {
|
|
16902
18671
|
const host = `bedrock-runtime.${this.region}.amazonaws.com`;
|
|
16903
|
-
const url = `https://${host}/model/${encodeURIComponent(modelId)}
|
|
18672
|
+
const url = `https://${host}/model/${encodeURIComponent(modelId)}/${stream ? "converse-stream" : "converse"}`;
|
|
16904
18673
|
const bodyStr = JSON.stringify(body);
|
|
16905
18674
|
const res = await this.doFetchWithRetry(() => {
|
|
16906
18675
|
const headers = signRequest({
|
|
@@ -16908,7 +18677,7 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16908
18677
|
url,
|
|
16909
18678
|
headers: {
|
|
16910
18679
|
"Content-Type": "application/json",
|
|
16911
|
-
Accept: "application/json",
|
|
18680
|
+
Accept: stream ? "application/vnd.amazon.eventstream" : "application/json",
|
|
16912
18681
|
...this.defaultHeaders
|
|
16913
18682
|
},
|
|
16914
18683
|
body: bodyStr,
|
|
@@ -16916,7 +18685,7 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16916
18685
|
service: "bedrock",
|
|
16917
18686
|
credentials: this.credentials
|
|
16918
18687
|
});
|
|
16919
|
-
return
|
|
18688
|
+
return this.httpFetch(url, { method: "POST", headers, body: bodyStr, signal });
|
|
16920
18689
|
}, signal);
|
|
16921
18690
|
if (!res.ok) {
|
|
16922
18691
|
const text = await res.text().catch(() => "");
|
|
@@ -16927,7 +18696,7 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16927
18696
|
text
|
|
16928
18697
|
);
|
|
16929
18698
|
}
|
|
16930
|
-
return res
|
|
18699
|
+
return res;
|
|
16931
18700
|
}
|
|
16932
18701
|
parseResponse(json, modelId) {
|
|
16933
18702
|
const output = json.output?.message;
|
|
@@ -16963,8 +18732,8 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16963
18732
|
inputTokens: usage.inputTokens ?? 0,
|
|
16964
18733
|
outputTokens: usage.outputTokens ?? 0,
|
|
16965
18734
|
totalTokens: usage.totalTokens ?? (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0),
|
|
16966
|
-
cachedInputTokens: usage.cacheReadInputTokenCount ?? 0,
|
|
16967
|
-
cachedWriteTokens: usage.cacheWriteInputTokenCount ?? 0,
|
|
18735
|
+
cachedInputTokens: usage.cacheReadInputTokens ?? usage.cacheReadInputTokenCount ?? 0,
|
|
18736
|
+
cachedWriteTokens: usage.cacheWriteInputTokens ?? usage.cacheWriteInputTokenCount ?? 0,
|
|
16968
18737
|
cachedOutputTokens: 0,
|
|
16969
18738
|
// Bedrock bills thinking tokens inside outputTokens; no separate count.
|
|
16970
18739
|
reasoningTokens: 0
|
|
@@ -16976,11 +18745,26 @@ var BedrockProvider = class extends BaseProvider {
|
|
|
16976
18745
|
toolCalls,
|
|
16977
18746
|
usage: tokenUsage,
|
|
16978
18747
|
finishReason: mapBedrockStopReason(json.stopReason),
|
|
18748
|
+
...typeof json.stopReason === "string" ? { rawFinishReason: json.stopReason } : {},
|
|
16979
18749
|
reasoning: reasoningBlocks.length > 0 ? { blocks: reasoningBlocks, summary: summaryParts.join("\n").trim() || void 0 } : void 0,
|
|
16980
18750
|
raw: json
|
|
16981
18751
|
};
|
|
16982
18752
|
}
|
|
16983
18753
|
};
|
|
18754
|
+
var CONVERSE_TOP_LEVEL_FIELDS = /* @__PURE__ */ new Set([
|
|
18755
|
+
"messages",
|
|
18756
|
+
"system",
|
|
18757
|
+
"inferenceConfig",
|
|
18758
|
+
"toolConfig",
|
|
18759
|
+
"guardrailConfig",
|
|
18760
|
+
"additionalModelRequestFields",
|
|
18761
|
+
"additionalModelResponseFieldPaths",
|
|
18762
|
+
"promptVariables",
|
|
18763
|
+
"requestMetadata",
|
|
18764
|
+
"performanceConfig",
|
|
18765
|
+
"serviceTier",
|
|
18766
|
+
"outputConfig"
|
|
18767
|
+
]);
|
|
16984
18768
|
function appendBedrockReasoning(content, blocks) {
|
|
16985
18769
|
if (!blocks?.length) return;
|
|
16986
18770
|
for (const b of blocks) {
|
|
@@ -16995,6 +18779,23 @@ function appendBedrockReasoning(content, blocks) {
|
|
|
16995
18779
|
}
|
|
16996
18780
|
}
|
|
16997
18781
|
}
|
|
18782
|
+
function bedrockExceptionStatus(code) {
|
|
18783
|
+
switch (code) {
|
|
18784
|
+
case "throttlingException":
|
|
18785
|
+
return 429;
|
|
18786
|
+
case "validationException":
|
|
18787
|
+
return 400;
|
|
18788
|
+
case "modelTimeoutException":
|
|
18789
|
+
return 408;
|
|
18790
|
+
case "serviceUnavailableException":
|
|
18791
|
+
return 503;
|
|
18792
|
+
case "internalServerException":
|
|
18793
|
+
case "modelStreamErrorException":
|
|
18794
|
+
return 500;
|
|
18795
|
+
default:
|
|
18796
|
+
return void 0;
|
|
18797
|
+
}
|
|
18798
|
+
}
|
|
16998
18799
|
function mapBedrockStopReason(reason) {
|
|
16999
18800
|
switch (reason) {
|
|
17000
18801
|
case "end_turn":
|
|
@@ -17003,8 +18804,10 @@ function mapBedrockStopReason(reason) {
|
|
|
17003
18804
|
case "tool_use":
|
|
17004
18805
|
return "tool_calls";
|
|
17005
18806
|
case "max_tokens":
|
|
18807
|
+
case "model_context_window_exceeded":
|
|
17006
18808
|
return "length";
|
|
17007
18809
|
case "content_filtered":
|
|
18810
|
+
case "guardrail_intervened":
|
|
17008
18811
|
case "guardrail":
|
|
17009
18812
|
return "content_filter";
|
|
17010
18813
|
default:
|
|
@@ -17034,10 +18837,12 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17034
18837
|
super();
|
|
17035
18838
|
this.providerName = "vertex";
|
|
17036
18839
|
this.tokenExpiry = 0;
|
|
18840
|
+
this.configureTransport(config);
|
|
17037
18841
|
this.projectId = config.projectId;
|
|
17038
18842
|
this.location = config.location ?? "us-central1";
|
|
17039
18843
|
this.defaultModel = config.defaultModel ?? "gemini-2.0-flash";
|
|
17040
18844
|
this.defaultHeaders = config.defaultHeaders ?? {};
|
|
18845
|
+
if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
|
|
17041
18846
|
if (config.accessToken) {
|
|
17042
18847
|
this.accessToken = config.accessToken;
|
|
17043
18848
|
this.tokenExpiry = Date.now() + 36e5;
|
|
@@ -17050,7 +18855,7 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17050
18855
|
const modelId = request.model || this.defaultModel;
|
|
17051
18856
|
const body = this.buildGeminiBody(request);
|
|
17052
18857
|
const url = this.buildUrl(modelId, false);
|
|
17053
|
-
const res = await this.doFetch(url, body, request.signal);
|
|
18858
|
+
const res = await this.doFetch(url, body, request.signal, modelId);
|
|
17054
18859
|
const json = await res.json();
|
|
17055
18860
|
return this.parseResponse(json, modelId);
|
|
17056
18861
|
}
|
|
@@ -17058,8 +18863,9 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17058
18863
|
const modelId = request.model || this.defaultModel;
|
|
17059
18864
|
const body = this.buildGeminiBody(request);
|
|
17060
18865
|
const url = this.buildUrl(modelId, true);
|
|
17061
|
-
const res = await this.doFetch(url, body, request.signal);
|
|
18866
|
+
const res = await this.doFetch(url, body, request.signal, modelId);
|
|
17062
18867
|
if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
|
|
18868
|
+
const counter = { next: 0 };
|
|
17063
18869
|
const contentType = res.headers.get("content-type") ?? "";
|
|
17064
18870
|
if (contentType.includes("text/event-stream")) {
|
|
17065
18871
|
for await (const event of parseSSEStream(res.body, request.signal)) {
|
|
@@ -17070,7 +18876,7 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17070
18876
|
} catch {
|
|
17071
18877
|
continue;
|
|
17072
18878
|
}
|
|
17073
|
-
yield this.parseStreamChunk(chunk, modelId);
|
|
18879
|
+
yield this.parseStreamChunk(chunk, modelId, counter);
|
|
17074
18880
|
}
|
|
17075
18881
|
} else {
|
|
17076
18882
|
const reader = res.body.getReader();
|
|
@@ -17088,7 +18894,7 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17088
18894
|
if (!trimmed || trimmed === "[" || trimmed === "]") continue;
|
|
17089
18895
|
try {
|
|
17090
18896
|
const chunk = JSON.parse(trimmed);
|
|
17091
|
-
yield this.parseStreamChunk(chunk, modelId);
|
|
18897
|
+
yield this.parseStreamChunk(chunk, modelId, counter);
|
|
17092
18898
|
} catch {
|
|
17093
18899
|
buffer = line + "\n" + buffer;
|
|
17094
18900
|
break;
|
|
@@ -17099,7 +18905,7 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17099
18905
|
if (remaining && remaining !== "[" && remaining !== "]") {
|
|
17100
18906
|
try {
|
|
17101
18907
|
const chunk = JSON.parse(remaining);
|
|
17102
|
-
yield this.parseStreamChunk(chunk, modelId);
|
|
18908
|
+
yield this.parseStreamChunk(chunk, modelId, counter);
|
|
17103
18909
|
} catch {
|
|
17104
18910
|
}
|
|
17105
18911
|
}
|
|
@@ -17110,6 +18916,48 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17110
18916
|
}
|
|
17111
18917
|
}
|
|
17112
18918
|
// ─── Internals ───────────────────────────────────────────────────────────
|
|
18919
|
+
/**
|
|
18920
|
+
* Vertex `:predict` embeddings (text-embedding-00x, text-multilingual-embedding,
|
|
18921
|
+
* gemini-embedding-001). `inputType` maps to the task type; `dimensions` to
|
|
18922
|
+
* `outputDimensionality`. gemini-embedding takes one instance per request, the
|
|
18923
|
+
* text-embedding models up to `batchSize` (default 100).
|
|
18924
|
+
*/
|
|
18925
|
+
async embed(request) {
|
|
18926
|
+
const model = requireEmbeddingModel(this.providerName, request.model);
|
|
18927
|
+
const perRequest = request.batchSize ?? (/gemini-embedding/i.test(model) ? 1 : 100);
|
|
18928
|
+
const url = `https://${this.location}-aiplatform.googleapis.com/v1/projects/${this.projectId}/locations/${this.location}/publishers/google/models/${model}:predict`;
|
|
18929
|
+
const taskType = request.inputType ? Object.prototype.hasOwnProperty.call(GEMINI_TASK_TYPES, request.inputType) ? GEMINI_TASK_TYPES[request.inputType] : request.inputType.toUpperCase() : void 0;
|
|
18930
|
+
const vectors = [];
|
|
18931
|
+
const raw = [];
|
|
18932
|
+
let inputTokens = 0;
|
|
18933
|
+
for (const batch of chunkArray(request.input, perRequest)) {
|
|
18934
|
+
const body = {
|
|
18935
|
+
instances: batch.map((content) => ({ content, ...taskType ? { task_type: taskType } : {} }))
|
|
18936
|
+
};
|
|
18937
|
+
const { parameters: extraParameters, ...extraRest } = request.extra ?? {};
|
|
18938
|
+
const parameters = {
|
|
18939
|
+
...request.dimensions != null ? { outputDimensionality: request.dimensions } : {},
|
|
18940
|
+
// Caller-supplied parameters are merged in, not replacing the above (an
|
|
18941
|
+
// explicit extra.parameters.outputDimensionality still wins).
|
|
18942
|
+
...extraParameters && typeof extraParameters === "object" ? extraParameters : {}
|
|
18943
|
+
};
|
|
18944
|
+
if (Object.keys(parameters).length > 0) body.parameters = parameters;
|
|
18945
|
+
Object.assign(body, extraRest);
|
|
18946
|
+
const res = await this.doFetch(url, body, request.signal, model);
|
|
18947
|
+
const json = await res.json();
|
|
18948
|
+
raw.push(json);
|
|
18949
|
+
for (const p of json.predictions ?? []) {
|
|
18950
|
+
const values = p.embeddings?.values;
|
|
18951
|
+
if (!Array.isArray(values)) {
|
|
18952
|
+
throw new ProviderError("Vertex embeddings response has a prediction without an embeddings.values array", this.providerName, void 0, json);
|
|
18953
|
+
}
|
|
18954
|
+
vectors.push(values);
|
|
18955
|
+
inputTokens += p.embeddings?.statistics?.token_count ?? 0;
|
|
18956
|
+
}
|
|
18957
|
+
}
|
|
18958
|
+
assertVectorCount(this.providerName, vectors, request.input.length);
|
|
18959
|
+
return { model, vectors, usage: { inputTokens, totalTokens: inputTokens }, raw };
|
|
18960
|
+
}
|
|
17113
18961
|
buildUrl(modelId, stream) {
|
|
17114
18962
|
const base = `https://${this.location}-aiplatform.googleapis.com/v1`;
|
|
17115
18963
|
const path2 = `projects/${this.projectId}/locations/${this.location}/publishers/google/models/${modelId}`;
|
|
@@ -17207,7 +19055,9 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17207
19055
|
functionCall: {
|
|
17208
19056
|
name: tc.name,
|
|
17209
19057
|
args: safeJsonParse3(tc.arguments)
|
|
17210
|
-
}
|
|
19058
|
+
},
|
|
19059
|
+
// Gemini 3 requires the signature of each functionCall echoed back.
|
|
19060
|
+
...tc.thoughtSignature ? { thoughtSignature: tc.thoughtSignature } : {}
|
|
17211
19061
|
});
|
|
17212
19062
|
}
|
|
17213
19063
|
return { role: "model", parts: parts2 };
|
|
@@ -17304,7 +19154,7 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17304
19154
|
sign.update(signingInput);
|
|
17305
19155
|
const signature = sign.sign(sa.private_key, "base64url");
|
|
17306
19156
|
const jwt = `${signingInput}.${signature}`;
|
|
17307
|
-
const tokenRes = await
|
|
19157
|
+
const tokenRes = await this.httpFetch("https://oauth2.googleapis.com/token", {
|
|
17308
19158
|
method: "POST",
|
|
17309
19159
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
17310
19160
|
body: `grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=${jwt}`
|
|
@@ -17316,20 +19166,38 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17316
19166
|
const tokenJson = await tokenRes.json();
|
|
17317
19167
|
return tokenJson.access_token;
|
|
17318
19168
|
}
|
|
17319
|
-
async doFetch(url, body, signal) {
|
|
19169
|
+
async doFetch(url, body, signal, model = "") {
|
|
17320
19170
|
const token = await this.getAccessToken();
|
|
17321
|
-
const
|
|
17322
|
-
|
|
17323
|
-
|
|
17324
|
-
|
|
17325
|
-
|
|
17326
|
-
|
|
17327
|
-
|
|
17328
|
-
|
|
19171
|
+
const bodyStr = JSON.stringify(body);
|
|
19172
|
+
const res = await this.doFetchWithRetry(
|
|
19173
|
+
() => this.httpFetch(url, {
|
|
19174
|
+
method: "POST",
|
|
19175
|
+
headers: {
|
|
19176
|
+
"Content-Type": "application/json",
|
|
19177
|
+
Authorization: `Bearer ${token}`,
|
|
19178
|
+
...this.defaultHeaders
|
|
19179
|
+
},
|
|
19180
|
+
body: bodyStr,
|
|
19181
|
+
signal
|
|
19182
|
+
}),
|
|
17329
19183
|
signal
|
|
17330
|
-
|
|
19184
|
+
);
|
|
17331
19185
|
if (!res.ok) {
|
|
17332
19186
|
const text = await res.text().catch(() => "");
|
|
19187
|
+
if (res.status === 400) {
|
|
19188
|
+
const parsed = parseModelError(text);
|
|
19189
|
+
throw new ModelRequestError({
|
|
19190
|
+
status: 400,
|
|
19191
|
+
code: parsed?.kind === "unsupported_value" ? "unsupported_value" : parsed?.kind === "unsupported_parameter" ? "unsupported_parameter" : "model_request_invalid",
|
|
19192
|
+
param: parsed?.param,
|
|
19193
|
+
value: parsed?.value,
|
|
19194
|
+
supportedValues: parsed?.supportedValues,
|
|
19195
|
+
provider: this.providerName,
|
|
19196
|
+
model,
|
|
19197
|
+
message: `Vertex AI API error ${res.status}: ${text}`,
|
|
19198
|
+
responseBody: text
|
|
19199
|
+
});
|
|
19200
|
+
}
|
|
17333
19201
|
throw new ProviderError(
|
|
17334
19202
|
`Vertex AI API error ${res.status}: ${text}`,
|
|
17335
19203
|
this.providerName,
|
|
@@ -17357,7 +19225,8 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17357
19225
|
toolCalls.push({
|
|
17358
19226
|
id: `call_${toolCallIdx++}`,
|
|
17359
19227
|
name: part.functionCall.name,
|
|
17360
|
-
arguments: JSON.stringify(part.functionCall.args ?? {})
|
|
19228
|
+
arguments: JSON.stringify(part.functionCall.args ?? {}),
|
|
19229
|
+
...part.thoughtSignature ? { thoughtSignature: part.thoughtSignature } : {}
|
|
17361
19230
|
});
|
|
17362
19231
|
}
|
|
17363
19232
|
}
|
|
@@ -17378,11 +19247,12 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17378
19247
|
toolCalls,
|
|
17379
19248
|
usage: tokenUsage,
|
|
17380
19249
|
finishReason: mapGeminiFinishReason(candidate?.finishReason),
|
|
19250
|
+
...typeof candidate?.finishReason === "string" ? { rawFinishReason: candidate.finishReason } : {},
|
|
17381
19251
|
reasoning: thoughtParts.length > 0 ? { summary: thoughtParts.join("\n").trim() || void 0 } : void 0,
|
|
17382
19252
|
raw: json
|
|
17383
19253
|
};
|
|
17384
19254
|
}
|
|
17385
|
-
parseStreamChunk(chunk, modelId) {
|
|
19255
|
+
parseStreamChunk(chunk, modelId, counter) {
|
|
17386
19256
|
const candidate = chunk.candidates?.[0];
|
|
17387
19257
|
const parts = candidate?.content?.parts ?? [];
|
|
17388
19258
|
const delta = {};
|
|
@@ -17396,9 +19266,12 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17396
19266
|
} else if (part.functionCall) {
|
|
17397
19267
|
if (!delta.toolCalls) delta.toolCalls = [];
|
|
17398
19268
|
delta.toolCalls.push({
|
|
17399
|
-
|
|
19269
|
+
// Unique across the whole stream: the adapter merges chunks by id.
|
|
19270
|
+
id: `call_${counter.next}`,
|
|
19271
|
+
index: counter.next++,
|
|
17400
19272
|
name: part.functionCall.name,
|
|
17401
|
-
arguments: JSON.stringify(part.functionCall.args ?? {})
|
|
19273
|
+
arguments: JSON.stringify(part.functionCall.args ?? {}),
|
|
19274
|
+
...part.thoughtSignature ? { thoughtSignature: part.thoughtSignature } : {}
|
|
17402
19275
|
});
|
|
17403
19276
|
}
|
|
17404
19277
|
}
|
|
@@ -17420,10 +19293,21 @@ var VertexProvider = class extends BaseProvider {
|
|
|
17420
19293
|
model: modelId,
|
|
17421
19294
|
delta,
|
|
17422
19295
|
usage,
|
|
17423
|
-
finishReason: mapGeminiFinishReason(candidate?.finishReason)
|
|
19296
|
+
finishReason: mapGeminiFinishReason(candidate?.finishReason),
|
|
19297
|
+
...typeof candidate?.finishReason === "string" ? { rawFinishReason: candidate.finishReason } : {}
|
|
17424
19298
|
};
|
|
17425
19299
|
}
|
|
17426
19300
|
};
|
|
19301
|
+
var GEMINI_TASK_TYPES = {
|
|
19302
|
+
search_document: "RETRIEVAL_DOCUMENT",
|
|
19303
|
+
search_query: "RETRIEVAL_QUERY",
|
|
19304
|
+
classification: "CLASSIFICATION",
|
|
19305
|
+
clustering: "CLUSTERING",
|
|
19306
|
+
semantic_similarity: "SEMANTIC_SIMILARITY",
|
|
19307
|
+
question_answering: "QUESTION_ANSWERING",
|
|
19308
|
+
fact_verification: "FACT_VERIFICATION",
|
|
19309
|
+
code_retrieval_query: "CODE_RETRIEVAL_QUERY"
|
|
19310
|
+
};
|
|
17427
19311
|
function mapGeminiFinishReason(reason) {
|
|
17428
19312
|
switch (reason) {
|
|
17429
19313
|
case "STOP":
|
|
@@ -17495,6 +19379,9 @@ exports.HOOK_NAMES = HOOK_NAMES;
|
|
|
17495
19379
|
exports.HookTimeoutError = HookTimeoutError;
|
|
17496
19380
|
exports.InMemoryMemoryStore = InMemoryMemoryStore;
|
|
17497
19381
|
exports.JevProvider = JevProvider;
|
|
19382
|
+
exports.MAX_ADJUSTMENTS = MAX_ADJUSTMENTS;
|
|
19383
|
+
exports.MODEL_RULES = MODEL_RULES;
|
|
19384
|
+
exports.ModelRequestError = ModelRequestError;
|
|
17498
19385
|
exports.NativeJsonSchemaStrategy = NativeJsonSchemaStrategy;
|
|
17499
19386
|
exports.OpenAICompatibleProvider = OpenAICompatibleProvider;
|
|
17500
19387
|
exports.OpenAIProvider = OpenAIProvider;
|
|
@@ -17506,7 +19393,10 @@ exports.TOOL_INPUT_DIGEST_KEY = TOOL_INPUT_DIGEST_KEY;
|
|
|
17506
19393
|
exports.ToolBasedStrategy = ToolBasedStrategy;
|
|
17507
19394
|
exports.VertexProvider = VertexProvider;
|
|
17508
19395
|
exports.agentVerdictRule = agentVerdictRule;
|
|
19396
|
+
exports.allowsSampling = allowsSampling;
|
|
17509
19397
|
exports.appendBoundTools = appendBoundTools;
|
|
19398
|
+
exports.applyDropParams = applyDropParams;
|
|
19399
|
+
exports.asModelRequestError = asModelRequestError;
|
|
17510
19400
|
exports.auditLog = auditLog;
|
|
17511
19401
|
exports.azureContentSafety = azureContentSafety;
|
|
17512
19402
|
exports.bedrockGuardrail = bedrockGuardrail;
|
|
@@ -17521,6 +19411,7 @@ exports.canOpenSkill = canOpenSkill;
|
|
|
17521
19411
|
exports.canSpawn = canSpawn;
|
|
17522
19412
|
exports.captureSnapshot = captureSnapshot;
|
|
17523
19413
|
exports.checkpointing = checkpointing;
|
|
19414
|
+
exports.clearLearnedModelRules = clearLearnedModelRules;
|
|
17524
19415
|
exports.codePresenceRule = codePresenceRule;
|
|
17525
19416
|
exports.coerceToolArgs = coerceToolArgs;
|
|
17526
19417
|
exports.cognipeerGuardrail = cognipeerGuardrail;
|
|
@@ -17583,6 +19474,7 @@ exports.detectTextFormat = detectTextFormat;
|
|
|
17583
19474
|
exports.detectVolatileContent = detectVolatileContent;
|
|
17584
19475
|
exports.digestToolInputArguments = digestToolInputArguments;
|
|
17585
19476
|
exports.digestToolInputValue = digestToolInputValue;
|
|
19477
|
+
exports.effortBudget = effortBudget;
|
|
17586
19478
|
exports.emptyUsage = emptyUsage;
|
|
17587
19479
|
exports.evaluateGuardrails = evaluateGuardrails;
|
|
17588
19480
|
exports.extractLatestUserQuery = extractLatestUserQuery;
|
|
@@ -17596,6 +19488,7 @@ exports.fromLangchainTools = fromLangchainTools;
|
|
|
17596
19488
|
exports.fromNativeProvider = fromNativeProvider;
|
|
17597
19489
|
exports.generateSpanId = generateSpanId;
|
|
17598
19490
|
exports.generateTraceId = generateTraceId;
|
|
19491
|
+
exports.getLearnedModelRulePatch = getLearnedModelRulePatch;
|
|
17599
19492
|
exports.getModelCapabilities = getModelCapabilities;
|
|
17600
19493
|
exports.getNestedValue = getNestedValue;
|
|
17601
19494
|
exports.getResolvedSmartConfig = getResolvedSmartConfig;
|
|
@@ -17616,12 +19509,16 @@ exports.jsonSchemaRule = jsonSchemaRule;
|
|
|
17616
19509
|
exports.langfuseDefaultPayload = defaultBuildPayload;
|
|
17617
19510
|
exports.langfuseTracing = langfuseTracing;
|
|
17618
19511
|
exports.languageGuard = languageGuard;
|
|
19512
|
+
exports.listLearnedModelRules = listLearnedModelRules;
|
|
17619
19513
|
exports.loadSkillsFromDisk = loadSkillsFromDisk;
|
|
17620
19514
|
exports.mapConsoleHookVerdict = mapConsoleHookVerdict;
|
|
19515
|
+
exports.mapReasoningEffort = mapReasoningEffort;
|
|
17621
19516
|
exports.mapTextParts = mapTextParts;
|
|
17622
19517
|
exports.mcp = mcp;
|
|
17623
19518
|
exports.mediaKindOf = mediaKindOf;
|
|
17624
19519
|
exports.mediaPolicy = mediaPolicy;
|
|
19520
|
+
exports.mergeRulePatch = mergeRulePatch;
|
|
19521
|
+
exports.modelIdCandidates = modelIdCandidates;
|
|
17625
19522
|
exports.normalizeSmartAgentOptions = normalizeSmartAgentOptions;
|
|
17626
19523
|
exports.normalizeVerdicts = normalizeVerdicts;
|
|
17627
19524
|
exports.openAIModeration = openAIModeration;
|
|
@@ -17629,6 +19526,7 @@ exports.otelTracing = otelTracing;
|
|
|
17629
19526
|
exports.otlpSink = otlpSink;
|
|
17630
19527
|
exports.outputGuard = outputGuard;
|
|
17631
19528
|
exports.parseApprovalDecision = parseApprovalDecision;
|
|
19529
|
+
exports.parseModelError = parseModelError;
|
|
17632
19530
|
exports.parseSkillFrontmatter = parseSkillFrontmatter;
|
|
17633
19531
|
exports.pathSandbox = pathSandbox;
|
|
17634
19532
|
exports.piiRedaction = piiRedaction;
|
|
@@ -17644,11 +19542,13 @@ exports.readMemoryFacts = readMemoryFacts;
|
|
|
17644
19542
|
exports.redactText = redactText;
|
|
17645
19543
|
exports.regexGuardrail = regexGuardrail;
|
|
17646
19544
|
exports.regexRule = regexRule;
|
|
19545
|
+
exports.rememberModelRulePatch = rememberModelRulePatch;
|
|
17647
19546
|
exports.replaceTextContent = replaceTextContent;
|
|
17648
19547
|
exports.resolveAvailableSkills = resolveAvailableSkills;
|
|
17649
19548
|
exports.resolveAvailableSubagents = resolveAvailableSubagents;
|
|
17650
19549
|
exports.resolveInputRetention = resolveInputRetention;
|
|
17651
19550
|
exports.resolveMemoryStore = resolveMemoryStore;
|
|
19551
|
+
exports.resolveModelRule = resolveModelRule;
|
|
17652
19552
|
exports.resolveReasoning = resolveReasoning;
|
|
17653
19553
|
exports.resolveStrategy = resolveStrategy;
|
|
17654
19554
|
exports.resolveSubagentTools = resolveSubagentTools;
|
|
@@ -17659,6 +19559,7 @@ exports.responseCache = responseCache;
|
|
|
17659
19559
|
exports.restoreSnapshot = restoreSnapshot;
|
|
17660
19560
|
exports.restoreToolCalls = restoreToolCalls;
|
|
17661
19561
|
exports.runSmartAgentEvalHarness = runSmartAgentEvalHarness;
|
|
19562
|
+
exports.runWithModelAdjustments = runWithModelAdjustments;
|
|
17662
19563
|
exports.scoreItemsByRelevance = scoreItemsByRelevance;
|
|
17663
19564
|
exports.searchSkills = searchSkills;
|
|
17664
19565
|
exports.seedChildMessages = seedChildMessages;
|
|
@@ -17667,7 +19568,9 @@ exports.sessionMetrics = sessionMetrics;
|
|
|
17667
19568
|
exports.setTokenCounter = setTokenCounter;
|
|
17668
19569
|
exports.startStreamingSession = startStreamingSession;
|
|
17669
19570
|
exports.summarizeObject = summarizeObject;
|
|
19571
|
+
exports.supportsAdaptiveThinking = supportsAdaptiveThinking;
|
|
17670
19572
|
exports.textFromContent = textFromContent;
|
|
19573
|
+
exports.toMessageUsage = toMessageUsage;
|
|
17671
19574
|
exports.toStrictCompatible = toStrictCompatible;
|
|
17672
19575
|
exports.toStrictToolSchema = toStrictToolSchema;
|
|
17673
19576
|
exports.tokenize = tokenize;
|