@axlsdk/axl 0.25.1 → 0.25.3
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 +14 -15
- package/dist/index.cjs +170 -46
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -4
- package/dist/index.d.ts +16 -4
- package/dist/index.js +170 -46
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -7378,8 +7378,8 @@ type DirectOpenAIPricingContext = {
|
|
|
7378
7378
|
};
|
|
7379
7379
|
};
|
|
7380
7380
|
/**
|
|
7381
|
-
* Estimate OpenAI call cost from token usage
|
|
7382
|
-
*
|
|
7381
|
+
* Estimate OpenAI call cost from token usage using exact catalog IDs only.
|
|
7382
|
+
* Explicitly listed snapshots (e.g. `gpt-4o-2024-05-13`) have their own rows.
|
|
7383
7383
|
*
|
|
7384
7384
|
* Returns `undefined` when the model is not in the table — callers must treat
|
|
7385
7385
|
* that as "unknown cost", never as free (a silent `0` would break
|
|
@@ -7409,8 +7409,8 @@ declare class OpenAIProvider extends OpenAICompatibleProvider {
|
|
|
7409
7409
|
dangerouslyAllowInsecureHttp?: boolean;
|
|
7410
7410
|
rateLimit?: RateLimitConfig;
|
|
7411
7411
|
});
|
|
7412
|
-
/** Report a clamped `effort` — Chat
|
|
7413
|
-
*
|
|
7412
|
+
/** Report a clamped `effort` — Chat caps `'max'` at `'xhigh'` on GPT-5.6 and
|
|
7413
|
+
* GPT-6.1 Sol, and maps `'none'` to the model's supported floor. */
|
|
7414
7414
|
effortResolution(options: Pick<ChatOptions, 'model' | 'effort' | 'thinkingBudget' | 'includeThoughts' | 'providerOptions'>): EffortResolution | undefined;
|
|
7415
7415
|
protected validateFinalRequestBody(body: Record<string, unknown>): void;
|
|
7416
7416
|
protected computeCost(model: string, usage: ProviderResponse['usage'], _reportedCost: number | undefined, context?: DirectOpenAIPricingContext): number | undefined;
|
|
@@ -7534,7 +7534,19 @@ declare class AnthropicProvider implements Provider {
|
|
|
7534
7534
|
chat(messages: ChatMessage[], options: ChatOptions): Promise<ProviderResponse>;
|
|
7535
7535
|
stream(messages: ChatMessage[], options: ChatOptions): AsyncGenerator<StreamChunk>;
|
|
7536
7536
|
private buildHeaders;
|
|
7537
|
+
/**
|
|
7538
|
+
* Whether the final body needs the binding beta header. Runs after
|
|
7539
|
+
* `validateAndBindFinalBody`, which has already injected `block_binding`
|
|
7540
|
+
* wherever it applies, so the header follows the final body rather than
|
|
7541
|
+
* re-deriving the injection rule.
|
|
7542
|
+
*/
|
|
7537
7543
|
private requiresBindingBeta;
|
|
7544
|
+
/**
|
|
7545
|
+
* Validate the final body (after `providerOptions`) against the effective
|
|
7546
|
+
* model's capability, then inject `block_binding` where it applies. Every
|
|
7547
|
+
* rule is gated on its own capability field and is a no-op when unset, so a
|
|
7548
|
+
* model only gets the guards its provider contract calls for.
|
|
7549
|
+
*/
|
|
7538
7550
|
private validateAndBindFinalBody;
|
|
7539
7551
|
/** Extract a human-readable message from an API error response body. */
|
|
7540
7552
|
private extractErrorMessage;
|
package/dist/index.d.ts
CHANGED
|
@@ -7378,8 +7378,8 @@ type DirectOpenAIPricingContext = {
|
|
|
7378
7378
|
};
|
|
7379
7379
|
};
|
|
7380
7380
|
/**
|
|
7381
|
-
* Estimate OpenAI call cost from token usage
|
|
7382
|
-
*
|
|
7381
|
+
* Estimate OpenAI call cost from token usage using exact catalog IDs only.
|
|
7382
|
+
* Explicitly listed snapshots (e.g. `gpt-4o-2024-05-13`) have their own rows.
|
|
7383
7383
|
*
|
|
7384
7384
|
* Returns `undefined` when the model is not in the table — callers must treat
|
|
7385
7385
|
* that as "unknown cost", never as free (a silent `0` would break
|
|
@@ -7409,8 +7409,8 @@ declare class OpenAIProvider extends OpenAICompatibleProvider {
|
|
|
7409
7409
|
dangerouslyAllowInsecureHttp?: boolean;
|
|
7410
7410
|
rateLimit?: RateLimitConfig;
|
|
7411
7411
|
});
|
|
7412
|
-
/** Report a clamped `effort` — Chat
|
|
7413
|
-
*
|
|
7412
|
+
/** Report a clamped `effort` — Chat caps `'max'` at `'xhigh'` on GPT-5.6 and
|
|
7413
|
+
* GPT-6.1 Sol, and maps `'none'` to the model's supported floor. */
|
|
7414
7414
|
effortResolution(options: Pick<ChatOptions, 'model' | 'effort' | 'thinkingBudget' | 'includeThoughts' | 'providerOptions'>): EffortResolution | undefined;
|
|
7415
7415
|
protected validateFinalRequestBody(body: Record<string, unknown>): void;
|
|
7416
7416
|
protected computeCost(model: string, usage: ProviderResponse['usage'], _reportedCost: number | undefined, context?: DirectOpenAIPricingContext): number | undefined;
|
|
@@ -7534,7 +7534,19 @@ declare class AnthropicProvider implements Provider {
|
|
|
7534
7534
|
chat(messages: ChatMessage[], options: ChatOptions): Promise<ProviderResponse>;
|
|
7535
7535
|
stream(messages: ChatMessage[], options: ChatOptions): AsyncGenerator<StreamChunk>;
|
|
7536
7536
|
private buildHeaders;
|
|
7537
|
+
/**
|
|
7538
|
+
* Whether the final body needs the binding beta header. Runs after
|
|
7539
|
+
* `validateAndBindFinalBody`, which has already injected `block_binding`
|
|
7540
|
+
* wherever it applies, so the header follows the final body rather than
|
|
7541
|
+
* re-deriving the injection rule.
|
|
7542
|
+
*/
|
|
7537
7543
|
private requiresBindingBeta;
|
|
7544
|
+
/**
|
|
7545
|
+
* Validate the final body (after `providerOptions`) against the effective
|
|
7546
|
+
* model's capability, then inject `block_binding` where it applies. Every
|
|
7547
|
+
* rule is gated on its own capability field and is a no-op when unset, so a
|
|
7548
|
+
* model only gets the guards its provider contract calls for.
|
|
7549
|
+
*/
|
|
7538
7550
|
private validateAndBindFinalBody;
|
|
7539
7551
|
/** Extract a human-readable message from an API error response body. */
|
|
7540
7552
|
private extractErrorMessage;
|
package/dist/index.js
CHANGED
|
@@ -348,7 +348,7 @@ var sharedGuard = typeof installedGuard === "object" && installedGuard !== null
|
|
|
348
348
|
var buildPath = typeof __AXL_BUILD_PATH__ === "string" ? __AXL_BUILD_PATH__ : "<source>";
|
|
349
349
|
var thisCopy = {
|
|
350
350
|
path: buildPath.startsWith("file:") ? fileURLToPath(buildPath) : buildPath,
|
|
351
|
-
version: true ? "0.25.
|
|
351
|
+
version: true ? "0.25.3" : "unknown"
|
|
352
352
|
};
|
|
353
353
|
function warnCrossCopy(other, joined) {
|
|
354
354
|
if (other === thisCopy) return;
|
|
@@ -3617,7 +3617,7 @@ var OPENAI_PRICING = {
|
|
|
3617
3617
|
"gpt-4.1-mini": [4e-7, 16e-7, 0.25],
|
|
3618
3618
|
"gpt-4.1-nano": [1e-7, 4e-7, 0.25],
|
|
3619
3619
|
o3: [2e-6, 8e-6, 0.25],
|
|
3620
|
-
"o3-mini": [11e-7, 44e-7, 0.
|
|
3620
|
+
"o3-mini": [11e-7, 44e-7, 0.5],
|
|
3621
3621
|
"o4-mini": [11e-7, 44e-7, 0.25],
|
|
3622
3622
|
"gpt-5": [125e-8, 1e-5, 0.1],
|
|
3623
3623
|
"gpt-5-mini": [25e-8, 2e-6, 0.1],
|
|
@@ -3640,6 +3640,13 @@ var DIRECT_OPENAI_CATALOG = [
|
|
|
3640
3640
|
long: { input: 20 / M, cachedInput: 2 / M, cacheWrite: 25 / M, output: 75 / M },
|
|
3641
3641
|
contextBoundary: LONG_CONTEXT_BOUNDARY
|
|
3642
3642
|
},
|
|
3643
|
+
{
|
|
3644
|
+
aliases: ["gpt-6.1-sol"],
|
|
3645
|
+
// Rechecked 2026-10-15 against https://developers.openai.com/api/docs/pricing.
|
|
3646
|
+
short: { input: 2 / M, cachedInput: 0.1 / M, cacheWrite: 2.5 / M, output: 10 / M },
|
|
3647
|
+
long: { input: 4 / M, cachedInput: 0.2 / M, cacheWrite: 5 / M, output: 15 / M },
|
|
3648
|
+
contextBoundary: LONG_CONTEXT_BOUNDARY
|
|
3649
|
+
},
|
|
3643
3650
|
{
|
|
3644
3651
|
aliases: ["gpt-6-sol"],
|
|
3645
3652
|
short: { input: 2 / M, cachedInput: 0.2 / M, cacheWrite: 2.5 / M, output: 10 / M },
|
|
@@ -4019,12 +4026,12 @@ var BASE_EFFORTS = ["minimal", "low", "medium", "high"];
|
|
|
4019
4026
|
function bothEndpoints(value) {
|
|
4020
4027
|
return { chat: value, responses: value };
|
|
4021
4028
|
}
|
|
4022
|
-
function gpt6(id,
|
|
4029
|
+
function gpt6(id, responsesEfforts, chatTools, chatEfforts = responsesEfforts) {
|
|
4023
4030
|
return {
|
|
4024
4031
|
id,
|
|
4025
4032
|
family: "gpt-6",
|
|
4026
4033
|
reasoning: true,
|
|
4027
|
-
efforts:
|
|
4034
|
+
efforts: { chat: chatEfforts, responses: responsesEfforts },
|
|
4028
4035
|
defaultEffort: "medium",
|
|
4029
4036
|
// Same policy as GPT-5.x: a portable `temperature` is dropped while
|
|
4030
4037
|
// reasoning is active (including the active default). A raw
|
|
@@ -4052,6 +4059,13 @@ function gpt56(id) {
|
|
|
4052
4059
|
var OPENAI_EXACT_MODELS = new Map(
|
|
4053
4060
|
[
|
|
4054
4061
|
gpt6("gpt-6-astra", ["low", "medium", "high", "xhigh", "max"], "never"),
|
|
4062
|
+
// Live Chat Completions rejects max; Responses accepts it (2026-10-15).
|
|
4063
|
+
gpt6("gpt-6.1-sol", ["low", "medium", "high", "xhigh", "max"], "never", [
|
|
4064
|
+
"low",
|
|
4065
|
+
"medium",
|
|
4066
|
+
"high",
|
|
4067
|
+
"xhigh"
|
|
4068
|
+
]),
|
|
4055
4069
|
gpt6("gpt-6-sol", ["none", "low", "medium", "high", "xhigh", "max"], "effort-none-only"),
|
|
4056
4070
|
gpt6("gpt-6-luna", ["none", "low", "medium", "high", "xhigh", "max"], "effort-none-only"),
|
|
4057
4071
|
gpt56("gpt-5.6"),
|
|
@@ -4195,15 +4209,15 @@ function validateOpenAIFinalRequestBody(body, endpoint) {
|
|
|
4195
4209
|
}
|
|
4196
4210
|
}
|
|
4197
4211
|
if (activeReasoning) {
|
|
4212
|
+
const remediation = (key) => descriptor.efforts[endpoint].includes("none") ? `Remove ${key} or set reasoning effort to 'none'.` : `Remove ${key}; ${model} does not support reasoning effort 'none'.`;
|
|
4198
4213
|
const forbidden = endpoint === "chat" ? ["temperature", "top_p", "top_logprobs", "logprobs"] : ["temperature", "top_p", "top_logprobs"];
|
|
4199
4214
|
for (const key of forbidden) {
|
|
4200
|
-
if (body[key] !== void 0)
|
|
4201
|
-
fail(key, `Remove ${key} or set reasoning effort to 'none' on Sol or Luna.`);
|
|
4215
|
+
if (body[key] !== void 0) fail(key, remediation(key));
|
|
4202
4216
|
}
|
|
4203
4217
|
if (endpoint === "responses" && Array.isArray(body.include) && body.include.includes("message.output_text.logprobs")) {
|
|
4204
4218
|
fail(
|
|
4205
4219
|
"message.output_text.logprobs",
|
|
4206
|
-
"
|
|
4220
|
+
remediation("message.output_text.logprobs from include")
|
|
4207
4221
|
);
|
|
4208
4222
|
}
|
|
4209
4223
|
}
|
|
@@ -4256,8 +4270,8 @@ var OpenAIProvider = class extends OpenAICompatibleProvider {
|
|
|
4256
4270
|
constructor(options = {}) {
|
|
4257
4271
|
super({ profile: OPENAI_PROFILE, ...options });
|
|
4258
4272
|
}
|
|
4259
|
-
/** Report a clamped `effort` — Chat
|
|
4260
|
-
*
|
|
4273
|
+
/** Report a clamped `effort` — Chat caps `'max'` at `'xhigh'` on GPT-5.6 and
|
|
4274
|
+
* GPT-6.1 Sol, and maps `'none'` to the model's supported floor. */
|
|
4261
4275
|
effortResolution(options) {
|
|
4262
4276
|
return resolveOpenAIEffortResolution(
|
|
4263
4277
|
options,
|
|
@@ -4913,6 +4927,17 @@ var ANTHROPIC_THINKING_BINDING_BETA = "thinking-binding-controls-2026-08-01";
|
|
|
4913
4927
|
function isRecord(value) {
|
|
4914
4928
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
4915
4929
|
}
|
|
4930
|
+
function isFinalThinkingAdaptive(capability, body) {
|
|
4931
|
+
const thinking = body.thinking;
|
|
4932
|
+
if (thinking === void 0) {
|
|
4933
|
+
return capability.thinking === "adaptive-default-on" || capability.thinking === "adaptive-always-on";
|
|
4934
|
+
}
|
|
4935
|
+
return isRecord(thinking) && thinking.type === "adaptive";
|
|
4936
|
+
}
|
|
4937
|
+
var NATIVE_CLAUDE_EFFORTS = ["low", "medium", "high", "xhigh", "max"];
|
|
4938
|
+
function isNativeClaudeEffort(value) {
|
|
4939
|
+
return NATIVE_CLAUDE_EFFORTS.includes(value);
|
|
4940
|
+
}
|
|
4916
4941
|
function hasReplayedThinking(body) {
|
|
4917
4942
|
return Array.isArray(body.messages) && body.messages.some(
|
|
4918
4943
|
(message) => isRecord(message) && Array.isArray(message.content) && message.content.some(
|
|
@@ -4947,11 +4972,40 @@ function hasAnthropicProviderFileImage(messages) {
|
|
|
4947
4972
|
);
|
|
4948
4973
|
}
|
|
4949
4974
|
var CLAUDE_CAPABILITIES = {
|
|
4975
|
+
// Thinking off is `between_tools` (progress updates between tool calls);
|
|
4976
|
+
// `disabled` is a provider 400. Forced tool choice is a 400.
|
|
4977
|
+
"claude-sonnet-5-5": {
|
|
4978
|
+
thinking: "adaptive-default-on",
|
|
4979
|
+
effortLevels: ["low", "medium", "high", "xhigh", "max"],
|
|
4980
|
+
manualBudget: false,
|
|
4981
|
+
stripTemperature: true,
|
|
4982
|
+
disableAt: "high",
|
|
4983
|
+
offShape: "between_tools",
|
|
4984
|
+
forcedToolChoice: "rejected",
|
|
4985
|
+
defaultOnlySampling: true,
|
|
4986
|
+
strictThinking: true,
|
|
4987
|
+
thinkingBinding: true
|
|
4988
|
+
},
|
|
4989
|
+
// Thinking off is `disabled`, only at effort high or below. Forced tool
|
|
4990
|
+
// choice is accepted (the provider skips thinking for that turn).
|
|
4991
|
+
"claude-haiku-5-5": {
|
|
4992
|
+
thinking: "adaptive-default-on",
|
|
4993
|
+
effortLevels: ["low", "medium", "high", "xhigh", "max"],
|
|
4994
|
+
manualBudget: false,
|
|
4995
|
+
stripTemperature: true,
|
|
4996
|
+
disableAt: "high",
|
|
4997
|
+
defaultOnlySampling: true,
|
|
4998
|
+
strictThinking: true,
|
|
4999
|
+
thinkingBinding: true
|
|
5000
|
+
},
|
|
4950
5001
|
"claude-opus-5-5": {
|
|
4951
5002
|
thinking: "adaptive-always-on",
|
|
4952
5003
|
effortLevels: ["low", "medium", "high", "xhigh", "max"],
|
|
4953
5004
|
manualBudget: false,
|
|
4954
5005
|
stripTemperature: true,
|
|
5006
|
+
forcedToolChoice: "rejected",
|
|
5007
|
+
defaultOnlySampling: true,
|
|
5008
|
+
strictThinking: true,
|
|
4955
5009
|
thinkingBinding: true
|
|
4956
5010
|
},
|
|
4957
5011
|
"claude-fable-5-1": {
|
|
@@ -4959,6 +5013,9 @@ var CLAUDE_CAPABILITIES = {
|
|
|
4959
5013
|
effortLevels: ["low", "medium", "high", "xhigh", "max"],
|
|
4960
5014
|
manualBudget: false,
|
|
4961
5015
|
stripTemperature: true,
|
|
5016
|
+
forcedToolChoice: "rejected",
|
|
5017
|
+
defaultOnlySampling: true,
|
|
5018
|
+
strictThinking: true,
|
|
4962
5019
|
thinkingBinding: true
|
|
4963
5020
|
},
|
|
4964
5021
|
"claude-fable-5": {
|
|
@@ -5053,6 +5110,15 @@ function resolveClaudeCapability(model) {
|
|
|
5053
5110
|
}
|
|
5054
5111
|
var DEFAULT_CACHE_READ_MULTIPLIER = 0.1;
|
|
5055
5112
|
var ANTHROPIC_RATES = {
|
|
5113
|
+
// Sonnet 5.5 cache reads are 0.05x ($0.10/MTok): the pricing table, its
|
|
5114
|
+
// footnote, the models overview, and the prompt-caching guide agree
|
|
5115
|
+
// (re-checked 2026-10-07).
|
|
5116
|
+
"claude-sonnet-5-5": { input: 2e-6, output: 1e-5, cacheReadMultiplier: 0.05 },
|
|
5117
|
+
"claude-haiku-5-5": {
|
|
5118
|
+
input: 1e-7,
|
|
5119
|
+
output: 5e-7,
|
|
5120
|
+
longPrompt: { aboveTokens: 1e5, card: { input: 5e-7, output: 25e-7 } }
|
|
5121
|
+
},
|
|
5056
5122
|
"claude-opus-5-5": { input: 4e-6, output: 2e-5, cacheReadMultiplier: 0.05 },
|
|
5057
5123
|
"claude-fable-5-1": { input: 1e-5, output: 5e-5, cacheReadMultiplier: 0.025 },
|
|
5058
5124
|
"claude-fable-5": { input: 1e-5, output: 5e-5 },
|
|
@@ -5115,14 +5181,16 @@ function estimateAnthropicCost(model, usage) {
|
|
|
5115
5181
|
return void 0;
|
|
5116
5182
|
}
|
|
5117
5183
|
const cacheWriteTotal = safeTokenSum(cacheWrite5m, cacheWrite1h);
|
|
5118
|
-
|
|
5184
|
+
const promptTokens = cacheWriteTotal === void 0 ? void 0 : safeTokenSum(usage.inputTokens, cacheRead, cacheWriteTotal);
|
|
5185
|
+
if (cacheWriteTotal === void 0 || promptTokens === void 0) {
|
|
5119
5186
|
return void 0;
|
|
5120
5187
|
}
|
|
5121
5188
|
if (usage.aggregateCacheWriteTokens !== void 0 && (!isValidTokenCount(usage.aggregateCacheWriteTokens) || usage.aggregateCacheWriteTokens !== cacheWriteTotal)) {
|
|
5122
5189
|
return void 0;
|
|
5123
5190
|
}
|
|
5124
|
-
const
|
|
5125
|
-
const
|
|
5191
|
+
const card = rate.longPrompt && promptTokens > rate.longPrompt.aboveTokens ? rate.longPrompt.card : rate;
|
|
5192
|
+
const { input, output } = card;
|
|
5193
|
+
const cacheReadRate = input * (card.cacheReadMultiplier ?? DEFAULT_CACHE_READ_MULTIPLIER);
|
|
5126
5194
|
return usage.inputTokens * input + cacheRead * cacheReadRate + cacheWrite5m * input * 1.25 + cacheWrite1h * input * 2 + usage.outputTokens * output;
|
|
5127
5195
|
}
|
|
5128
5196
|
var THINKING_BUDGETS = {
|
|
@@ -5184,7 +5252,7 @@ function resolveClaudeThinking(model, resolved) {
|
|
|
5184
5252
|
};
|
|
5185
5253
|
}
|
|
5186
5254
|
return {
|
|
5187
|
-
thinking: { type: "disabled" },
|
|
5255
|
+
thinking: { type: capability.offShape ?? "disabled" },
|
|
5188
5256
|
outputConfig: activeEffort ? { effort: activeEffort } : void 0,
|
|
5189
5257
|
stripTemperature: true
|
|
5190
5258
|
};
|
|
@@ -5590,50 +5658,106 @@ var AnthropicProvider = class {
|
|
|
5590
5658
|
...betas.length > 0 ? { "anthropic-beta": betas.join(",") } : {}
|
|
5591
5659
|
};
|
|
5592
5660
|
}
|
|
5661
|
+
/**
|
|
5662
|
+
* Whether the final body needs the binding beta header. Runs after
|
|
5663
|
+
* `validateAndBindFinalBody`, which has already injected `block_binding`
|
|
5664
|
+
* wherever it applies, so the header follows the final body rather than
|
|
5665
|
+
* re-deriving the injection rule.
|
|
5666
|
+
*/
|
|
5593
5667
|
requiresBindingBeta(body) {
|
|
5668
|
+
const capability = resolveClaudeCapability(String(body.model));
|
|
5594
5669
|
const thinking = body.thinking;
|
|
5595
|
-
return
|
|
5670
|
+
return capability?.thinkingBinding === true && isRecord(thinking) && thinking.type === "adaptive" && thinking.block_binding !== void 0;
|
|
5596
5671
|
}
|
|
5672
|
+
/**
|
|
5673
|
+
* Validate the final body (after `providerOptions`) against the effective
|
|
5674
|
+
* model's capability, then inject `block_binding` where it applies. Every
|
|
5675
|
+
* rule is gated on its own capability field and is a no-op when unset, so a
|
|
5676
|
+
* model only gets the guards its provider contract calls for.
|
|
5677
|
+
*/
|
|
5597
5678
|
validateAndBindFinalBody(body) {
|
|
5598
5679
|
const model = typeof body.model === "string" ? body.model : "";
|
|
5599
|
-
|
|
5680
|
+
const capability = resolveClaudeCapability(model);
|
|
5681
|
+
if (!capability) return;
|
|
5600
5682
|
const reject = (option, remediation) => {
|
|
5601
5683
|
throw new UnsupportedModelOptionError({ provider: this.name, model, option, remediation });
|
|
5602
5684
|
};
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5608
|
-
|
|
5609
|
-
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5685
|
+
if (capability.forcedToolChoice === "rejected") {
|
|
5686
|
+
const toolChoice = body.tool_choice;
|
|
5687
|
+
if (isRecord(toolChoice) && (toolChoice.type === "any" || toolChoice.type === "tool")) {
|
|
5688
|
+
reject("forced tool choice", "Use toolChoice: 'auto' or 'none' on this model.");
|
|
5689
|
+
}
|
|
5690
|
+
}
|
|
5691
|
+
if (capability.strictThinking) {
|
|
5692
|
+
const offShape = capability.thinking === "adaptive-always-on" ? void 0 : capability.offShape ?? "disabled";
|
|
5693
|
+
const thinking = body.thinking;
|
|
5694
|
+
const outputConfig = body.output_config;
|
|
5695
|
+
const effort = isRecord(outputConfig) ? outputConfig.effort : void 0;
|
|
5696
|
+
if (thinking !== void 0 && offShape === void 0) {
|
|
5697
|
+
if (!isRecord(thinking) || thinking.type !== "adaptive" || thinking.budget_tokens !== void 0) {
|
|
5698
|
+
reject(
|
|
5699
|
+
"manual or disabled thinking",
|
|
5700
|
+
"Use thinking: { type: 'adaptive' } and output_config.effort."
|
|
5701
|
+
);
|
|
5702
|
+
}
|
|
5703
|
+
} else if (thinking !== void 0) {
|
|
5704
|
+
if (!isRecord(thinking) || thinking.type !== "adaptive" && thinking.type !== offShape) {
|
|
5705
|
+
reject(
|
|
5706
|
+
"thinking.type",
|
|
5707
|
+
`Use thinking: { type: 'adaptive' }, or { type: '${offShape}' } to turn thinking off.`
|
|
5708
|
+
);
|
|
5709
|
+
}
|
|
5710
|
+
const record = thinking;
|
|
5711
|
+
if (record.type === "adaptive" && record.budget_tokens !== void 0) {
|
|
5712
|
+
reject("thinking.budget_tokens", "Use output_config.effort instead of budget_tokens.");
|
|
5713
|
+
}
|
|
5714
|
+
if (record.type === offShape) {
|
|
5715
|
+
const extra = Object.keys(record).filter((key) => key !== "type");
|
|
5716
|
+
if (extra.length > 0) {
|
|
5717
|
+
reject(
|
|
5718
|
+
`thinking.${offShape}.${extra[0]}`,
|
|
5719
|
+
`Send thinking: { type: '${offShape}' } with no other fields.`
|
|
5720
|
+
);
|
|
5721
|
+
}
|
|
5722
|
+
}
|
|
5723
|
+
}
|
|
5724
|
+
if (outputConfig !== void 0 && (!isRecord(outputConfig) || effort !== void 0 && !isNativeClaudeEffort(effort))) {
|
|
5725
|
+
reject("output_config.effort", "Use low, medium, high, xhigh, or max effort.");
|
|
5726
|
+
}
|
|
5727
|
+
if (offShape !== void 0 && isRecord(thinking) && thinking.type === offShape && effort !== void 0 && capability.disableAt && !isEffortAtOrBelow(effort, capability.disableAt)) {
|
|
5728
|
+
reject(
|
|
5729
|
+
"output_config.effort",
|
|
5730
|
+
`Thinking can be turned off only at effort '${capability.disableAt}' or below; lower the effort or use adaptive thinking.`
|
|
5731
|
+
);
|
|
5732
|
+
}
|
|
5622
5733
|
}
|
|
5623
|
-
if (
|
|
5624
|
-
|
|
5734
|
+
if (capability.defaultOnlySampling) {
|
|
5735
|
+
if (body.temperature !== void 0 && body.temperature !== 1) {
|
|
5736
|
+
reject("temperature", "Omit temperature or use the default value 1.");
|
|
5737
|
+
}
|
|
5738
|
+
if (body.top_p !== void 0 && body.top_p !== 0.99) {
|
|
5739
|
+
reject("top_p", "Omit top_p or use the default value 0.99.");
|
|
5740
|
+
}
|
|
5741
|
+
if (body.temperature !== void 0 && body.top_p !== void 0) {
|
|
5742
|
+
reject("temperature and top_p", "Send at most one of temperature and top_p.");
|
|
5743
|
+
}
|
|
5744
|
+
if (body.top_k !== void 0) {
|
|
5745
|
+
reject("top_k", "Omit top_k on this model.");
|
|
5746
|
+
}
|
|
5625
5747
|
}
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5748
|
+
if (capability.thinkingBinding === true && isFinalThinkingAdaptive(capability, body)) {
|
|
5749
|
+
const thinking = isRecord(body.thinking) ? body.thinking : { type: "adaptive" };
|
|
5750
|
+
const binding = thinking.block_binding;
|
|
5751
|
+
if (binding !== void 0 && (!isRecord(binding) || binding.prefix_mismatch_behavior !== "error" && binding.prefix_mismatch_behavior !== "drop_block")) {
|
|
5752
|
+
reject("thinking.block_binding", "Use prefix_mismatch_behavior: 'error' or 'drop_block'.");
|
|
5753
|
+
}
|
|
5754
|
+
if (hasReplayedThinking(body)) {
|
|
5755
|
+
body.thinking = {
|
|
5756
|
+
...thinking,
|
|
5757
|
+
block_binding: binding ?? { prefix_mismatch_behavior: "drop_block" }
|
|
5758
|
+
};
|
|
5759
|
+
}
|
|
5632
5760
|
}
|
|
5633
|
-
body.thinking = {
|
|
5634
|
-
...thinking,
|
|
5635
|
-
block_binding: binding ?? { prefix_mismatch_behavior: "drop_block" }
|
|
5636
|
-
};
|
|
5637
5761
|
}
|
|
5638
5762
|
/** Extract a human-readable message from an API error response body. */
|
|
5639
5763
|
extractErrorMessage(body, status) {
|