@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 CHANGED
@@ -105,7 +105,7 @@ import { lookupOrder } from '../tools/db.js';
105
105
 
106
106
  export const supportAgent = agent({
107
107
  name: 'support',
108
- model: 'openai-responses:gpt-5.5',
108
+ model: 'openai-responses:gpt-6-sol',
109
109
  system: 'You are a customer support agent. Use tools to look up order information.',
110
110
  tools: [lookupOrder],
111
111
  });
@@ -206,13 +206,12 @@ import { agent } from '@axlsdk/axl';
206
206
 
207
207
  const researcher = agent({
208
208
  name: 'researcher',
209
- model: 'openai-responses:gpt-5.5',
209
+ model: 'openai-responses:gpt-6-sol',
210
210
  system: 'You are a research assistant.',
211
211
  tools: [calculator],
212
212
  effort: 'high',
213
213
  maxTurns: 10,
214
214
  timeout: '30s',
215
- temperature: 0.7,
216
215
  version: 'v1.2',
217
216
  });
218
217
  ```
@@ -223,8 +222,8 @@ Dynamic model and system prompt selection:
223
222
  const dynamicAgent = agent({
224
223
  model: (ctx) =>
225
224
  ctx.metadata?.tier === 'premium'
226
- ? 'openai-responses:gpt-5.5'
227
- : 'openai-responses:gpt-5-nano',
225
+ ? 'openai-responses:gpt-6-sol'
226
+ : 'openai-responses:gpt-6-luna',
228
227
  system: (ctx) => `You are a ${ctx.metadata?.role ?? 'general'} assistant.`,
229
228
  });
230
229
  ```
@@ -263,7 +262,7 @@ for precedence, nested asks, and provider timing details.
263
262
 
264
263
  ```typescript
265
264
  const router = agent({
266
- model: 'openai-responses:gpt-5-mini',
265
+ model: 'openai-responses:gpt-6-luna',
267
266
  system: 'Route to the right specialist.',
268
267
  handoffs: (ctx) => {
269
268
  const base = [
@@ -298,7 +297,7 @@ The `effort` parameter provides a unified way to control reasoning depth across
298
297
  ```typescript
299
298
  // Simple levels — works on any provider
300
299
  const reasoner = agent({
301
- model: 'anthropic:claude-opus-4-7',
300
+ model: 'anthropic:claude-opus-5-5',
302
301
  system: 'You are a careful analyst.',
303
302
  effort: 'high', // 'none' | 'low' | 'medium' | 'high' | 'xhigh' | 'max'
304
303
  });
@@ -402,8 +401,8 @@ To observe events between `ctx.ask()` calls — e.g., streaming `partial_object`
402
401
  // compiles standalone.
403
402
  const outlineSchema = z.object({ outline: z.array(z.string()) });
404
403
  const draftSchema = z.object({ draft: z.string() });
405
- const planner = agent({ model: 'openai:gpt-4o', system: 'Plan an outline.' });
406
- const writer = agent({ model: 'openai:gpt-4o', system: 'Write a draft.' });
404
+ const planner = agent({ model: 'openai-responses:gpt-6-sol', system: 'Plan an outline.' });
405
+ const writer = agent({ model: 'openai-responses:gpt-6-sol', system: 'Write a draft.' });
407
406
 
408
407
  const wf = workflow({
409
408
  name: 'two-step',
@@ -631,7 +630,7 @@ const containsPII = (text: string) => /\b\d{3}-\d{2}-\d{4}\b/.test(text);
631
630
  const isOffTopic = (text: string) => !text.toLowerCase().includes('support');
632
631
 
633
632
  const safe = agent({
634
- model: 'openai-responses:gpt-5.5',
633
+ model: 'openai-responses:gpt-6-sol',
635
634
  system: 'You are a helpful assistant.',
636
635
  guardrails: {
637
636
  input: async (prompt, ctx) => {
@@ -786,7 +785,7 @@ const session = runtime.session('user-123', {
786
785
  history: {
787
786
  maxMessages: 100,
788
787
  summarize: true,
789
- summaryModel: 'openai-responses:gpt-5-mini',
788
+ summaryModel: 'openai-responses:gpt-6-luna',
790
789
  },
791
790
  persist: true,
792
791
  });
@@ -826,10 +825,10 @@ import {
826
825
  Four native adapters using the `provider:model` URI scheme (plus the OpenAI-compatible presets above):
827
826
 
828
827
  ```
829
- openai-responses:gpt-5.5 # OpenAI Responses API (preferred over Chat Completions)
830
- openai:gpt-5.4 # OpenAI Chat Completions
831
- anthropic:claude-opus-4-8 # Anthropic (supports effort: 'xhigh' and 'max')
832
- google:gemini-3.1-pro-preview # Google Gemini
828
+ openai-responses:gpt-6-sol # OpenAI Responses API (preferred over Chat Completions)
829
+ openai:gpt-6-sol # OpenAI Chat Completions (text; use Responses for tools)
830
+ anthropic:claude-sonnet-5-5 # Anthropic (also claude-haiku-5-5, claude-opus-5-5)
831
+ google:gemini-3.8-flash # Google Gemini
833
832
  ```
834
833
 
835
834
  See [docs/providers.md](../../docs/providers.md) for the full model list including reasoning models.
package/dist/index.cjs CHANGED
@@ -581,7 +581,7 @@ var sharedGuard = typeof installedGuard === "object" && installedGuard !== null
581
581
  var buildPath = typeof __AXL_BUILD_PATH__ === "string" ? __AXL_BUILD_PATH__ : "<source>";
582
582
  var thisCopy = {
583
583
  path: buildPath.startsWith("file:") ? (0, import_node_url.fileURLToPath)(buildPath) : buildPath,
584
- version: true ? "0.25.1" : "unknown"
584
+ version: true ? "0.25.3" : "unknown"
585
585
  };
586
586
  function warnCrossCopy(other, joined) {
587
587
  if (other === thisCopy) return;
@@ -3850,7 +3850,7 @@ var OPENAI_PRICING = {
3850
3850
  "gpt-4.1-mini": [4e-7, 16e-7, 0.25],
3851
3851
  "gpt-4.1-nano": [1e-7, 4e-7, 0.25],
3852
3852
  o3: [2e-6, 8e-6, 0.25],
3853
- "o3-mini": [11e-7, 44e-7, 0.25],
3853
+ "o3-mini": [11e-7, 44e-7, 0.5],
3854
3854
  "o4-mini": [11e-7, 44e-7, 0.25],
3855
3855
  "gpt-5": [125e-8, 1e-5, 0.1],
3856
3856
  "gpt-5-mini": [25e-8, 2e-6, 0.1],
@@ -3873,6 +3873,13 @@ var DIRECT_OPENAI_CATALOG = [
3873
3873
  long: { input: 20 / M, cachedInput: 2 / M, cacheWrite: 25 / M, output: 75 / M },
3874
3874
  contextBoundary: LONG_CONTEXT_BOUNDARY
3875
3875
  },
3876
+ {
3877
+ aliases: ["gpt-6.1-sol"],
3878
+ // Rechecked 2026-10-15 against https://developers.openai.com/api/docs/pricing.
3879
+ short: { input: 2 / M, cachedInput: 0.1 / M, cacheWrite: 2.5 / M, output: 10 / M },
3880
+ long: { input: 4 / M, cachedInput: 0.2 / M, cacheWrite: 5 / M, output: 15 / M },
3881
+ contextBoundary: LONG_CONTEXT_BOUNDARY
3882
+ },
3876
3883
  {
3877
3884
  aliases: ["gpt-6-sol"],
3878
3885
  short: { input: 2 / M, cachedInput: 0.2 / M, cacheWrite: 2.5 / M, output: 10 / M },
@@ -4252,12 +4259,12 @@ var BASE_EFFORTS = ["minimal", "low", "medium", "high"];
4252
4259
  function bothEndpoints(value) {
4253
4260
  return { chat: value, responses: value };
4254
4261
  }
4255
- function gpt6(id, efforts, chatTools) {
4262
+ function gpt6(id, responsesEfforts, chatTools, chatEfforts = responsesEfforts) {
4256
4263
  return {
4257
4264
  id,
4258
4265
  family: "gpt-6",
4259
4266
  reasoning: true,
4260
- efforts: bothEndpoints(efforts),
4267
+ efforts: { chat: chatEfforts, responses: responsesEfforts },
4261
4268
  defaultEffort: "medium",
4262
4269
  // Same policy as GPT-5.x: a portable `temperature` is dropped while
4263
4270
  // reasoning is active (including the active default). A raw
@@ -4285,6 +4292,13 @@ function gpt56(id) {
4285
4292
  var OPENAI_EXACT_MODELS = new Map(
4286
4293
  [
4287
4294
  gpt6("gpt-6-astra", ["low", "medium", "high", "xhigh", "max"], "never"),
4295
+ // Live Chat Completions rejects max; Responses accepts it (2026-10-15).
4296
+ gpt6("gpt-6.1-sol", ["low", "medium", "high", "xhigh", "max"], "never", [
4297
+ "low",
4298
+ "medium",
4299
+ "high",
4300
+ "xhigh"
4301
+ ]),
4288
4302
  gpt6("gpt-6-sol", ["none", "low", "medium", "high", "xhigh", "max"], "effort-none-only"),
4289
4303
  gpt6("gpt-6-luna", ["none", "low", "medium", "high", "xhigh", "max"], "effort-none-only"),
4290
4304
  gpt56("gpt-5.6"),
@@ -4428,15 +4442,15 @@ function validateOpenAIFinalRequestBody(body, endpoint) {
4428
4442
  }
4429
4443
  }
4430
4444
  if (activeReasoning) {
4445
+ 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'.`;
4431
4446
  const forbidden = endpoint === "chat" ? ["temperature", "top_p", "top_logprobs", "logprobs"] : ["temperature", "top_p", "top_logprobs"];
4432
4447
  for (const key of forbidden) {
4433
- if (body[key] !== void 0)
4434
- fail(key, `Remove ${key} or set reasoning effort to 'none' on Sol or Luna.`);
4448
+ if (body[key] !== void 0) fail(key, remediation(key));
4435
4449
  }
4436
4450
  if (endpoint === "responses" && Array.isArray(body.include) && body.include.includes("message.output_text.logprobs")) {
4437
4451
  fail(
4438
4452
  "message.output_text.logprobs",
4439
- "Remove it from include or set reasoning effort to none on Sol or Luna."
4453
+ remediation("message.output_text.logprobs from include")
4440
4454
  );
4441
4455
  }
4442
4456
  }
@@ -4489,8 +4503,8 @@ var OpenAIProvider = class extends OpenAICompatibleProvider {
4489
4503
  constructor(options = {}) {
4490
4504
  super({ profile: OPENAI_PROFILE, ...options });
4491
4505
  }
4492
- /** Report a clamped `effort` — Chat Completions caps `'max'` at `'xhigh'` and
4493
- * rejects `'none'` before gpt-5.1 (clamped to `'minimal'`). */
4506
+ /** Report a clamped `effort` — Chat caps `'max'` at `'xhigh'` on GPT-5.6 and
4507
+ * GPT-6.1 Sol, and maps `'none'` to the model's supported floor. */
4494
4508
  effortResolution(options) {
4495
4509
  return resolveOpenAIEffortResolution(
4496
4510
  options,
@@ -5146,6 +5160,17 @@ var ANTHROPIC_THINKING_BINDING_BETA = "thinking-binding-controls-2026-08-01";
5146
5160
  function isRecord(value) {
5147
5161
  return value !== null && typeof value === "object" && !Array.isArray(value);
5148
5162
  }
5163
+ function isFinalThinkingAdaptive(capability, body) {
5164
+ const thinking = body.thinking;
5165
+ if (thinking === void 0) {
5166
+ return capability.thinking === "adaptive-default-on" || capability.thinking === "adaptive-always-on";
5167
+ }
5168
+ return isRecord(thinking) && thinking.type === "adaptive";
5169
+ }
5170
+ var NATIVE_CLAUDE_EFFORTS = ["low", "medium", "high", "xhigh", "max"];
5171
+ function isNativeClaudeEffort(value) {
5172
+ return NATIVE_CLAUDE_EFFORTS.includes(value);
5173
+ }
5149
5174
  function hasReplayedThinking(body) {
5150
5175
  return Array.isArray(body.messages) && body.messages.some(
5151
5176
  (message) => isRecord(message) && Array.isArray(message.content) && message.content.some(
@@ -5180,11 +5205,40 @@ function hasAnthropicProviderFileImage(messages) {
5180
5205
  );
5181
5206
  }
5182
5207
  var CLAUDE_CAPABILITIES = {
5208
+ // Thinking off is `between_tools` (progress updates between tool calls);
5209
+ // `disabled` is a provider 400. Forced tool choice is a 400.
5210
+ "claude-sonnet-5-5": {
5211
+ thinking: "adaptive-default-on",
5212
+ effortLevels: ["low", "medium", "high", "xhigh", "max"],
5213
+ manualBudget: false,
5214
+ stripTemperature: true,
5215
+ disableAt: "high",
5216
+ offShape: "between_tools",
5217
+ forcedToolChoice: "rejected",
5218
+ defaultOnlySampling: true,
5219
+ strictThinking: true,
5220
+ thinkingBinding: true
5221
+ },
5222
+ // Thinking off is `disabled`, only at effort high or below. Forced tool
5223
+ // choice is accepted (the provider skips thinking for that turn).
5224
+ "claude-haiku-5-5": {
5225
+ thinking: "adaptive-default-on",
5226
+ effortLevels: ["low", "medium", "high", "xhigh", "max"],
5227
+ manualBudget: false,
5228
+ stripTemperature: true,
5229
+ disableAt: "high",
5230
+ defaultOnlySampling: true,
5231
+ strictThinking: true,
5232
+ thinkingBinding: true
5233
+ },
5183
5234
  "claude-opus-5-5": {
5184
5235
  thinking: "adaptive-always-on",
5185
5236
  effortLevels: ["low", "medium", "high", "xhigh", "max"],
5186
5237
  manualBudget: false,
5187
5238
  stripTemperature: true,
5239
+ forcedToolChoice: "rejected",
5240
+ defaultOnlySampling: true,
5241
+ strictThinking: true,
5188
5242
  thinkingBinding: true
5189
5243
  },
5190
5244
  "claude-fable-5-1": {
@@ -5192,6 +5246,9 @@ var CLAUDE_CAPABILITIES = {
5192
5246
  effortLevels: ["low", "medium", "high", "xhigh", "max"],
5193
5247
  manualBudget: false,
5194
5248
  stripTemperature: true,
5249
+ forcedToolChoice: "rejected",
5250
+ defaultOnlySampling: true,
5251
+ strictThinking: true,
5195
5252
  thinkingBinding: true
5196
5253
  },
5197
5254
  "claude-fable-5": {
@@ -5286,6 +5343,15 @@ function resolveClaudeCapability(model) {
5286
5343
  }
5287
5344
  var DEFAULT_CACHE_READ_MULTIPLIER = 0.1;
5288
5345
  var ANTHROPIC_RATES = {
5346
+ // Sonnet 5.5 cache reads are 0.05x ($0.10/MTok): the pricing table, its
5347
+ // footnote, the models overview, and the prompt-caching guide agree
5348
+ // (re-checked 2026-10-07).
5349
+ "claude-sonnet-5-5": { input: 2e-6, output: 1e-5, cacheReadMultiplier: 0.05 },
5350
+ "claude-haiku-5-5": {
5351
+ input: 1e-7,
5352
+ output: 5e-7,
5353
+ longPrompt: { aboveTokens: 1e5, card: { input: 5e-7, output: 25e-7 } }
5354
+ },
5289
5355
  "claude-opus-5-5": { input: 4e-6, output: 2e-5, cacheReadMultiplier: 0.05 },
5290
5356
  "claude-fable-5-1": { input: 1e-5, output: 5e-5, cacheReadMultiplier: 0.025 },
5291
5357
  "claude-fable-5": { input: 1e-5, output: 5e-5 },
@@ -5348,14 +5414,16 @@ function estimateAnthropicCost(model, usage) {
5348
5414
  return void 0;
5349
5415
  }
5350
5416
  const cacheWriteTotal = safeTokenSum(cacheWrite5m, cacheWrite1h);
5351
- if (cacheWriteTotal === void 0 || safeTokenSum(usage.inputTokens, cacheRead, cacheWriteTotal) === void 0) {
5417
+ const promptTokens = cacheWriteTotal === void 0 ? void 0 : safeTokenSum(usage.inputTokens, cacheRead, cacheWriteTotal);
5418
+ if (cacheWriteTotal === void 0 || promptTokens === void 0) {
5352
5419
  return void 0;
5353
5420
  }
5354
5421
  if (usage.aggregateCacheWriteTokens !== void 0 && (!isValidTokenCount(usage.aggregateCacheWriteTokens) || usage.aggregateCacheWriteTokens !== cacheWriteTotal)) {
5355
5422
  return void 0;
5356
5423
  }
5357
- const { input, output } = rate;
5358
- const cacheReadRate = input * (rate.cacheReadMultiplier ?? DEFAULT_CACHE_READ_MULTIPLIER);
5424
+ const card = rate.longPrompt && promptTokens > rate.longPrompt.aboveTokens ? rate.longPrompt.card : rate;
5425
+ const { input, output } = card;
5426
+ const cacheReadRate = input * (card.cacheReadMultiplier ?? DEFAULT_CACHE_READ_MULTIPLIER);
5359
5427
  return usage.inputTokens * input + cacheRead * cacheReadRate + cacheWrite5m * input * 1.25 + cacheWrite1h * input * 2 + usage.outputTokens * output;
5360
5428
  }
5361
5429
  var THINKING_BUDGETS = {
@@ -5417,7 +5485,7 @@ function resolveClaudeThinking(model, resolved) {
5417
5485
  };
5418
5486
  }
5419
5487
  return {
5420
- thinking: { type: "disabled" },
5488
+ thinking: { type: capability.offShape ?? "disabled" },
5421
5489
  outputConfig: activeEffort ? { effort: activeEffort } : void 0,
5422
5490
  stripTemperature: true
5423
5491
  };
@@ -5823,50 +5891,106 @@ var AnthropicProvider = class {
5823
5891
  ...betas.length > 0 ? { "anthropic-beta": betas.join(",") } : {}
5824
5892
  };
5825
5893
  }
5894
+ /**
5895
+ * Whether the final body needs the binding beta header. Runs after
5896
+ * `validateAndBindFinalBody`, which has already injected `block_binding`
5897
+ * wherever it applies, so the header follows the final body rather than
5898
+ * re-deriving the injection rule.
5899
+ */
5826
5900
  requiresBindingBeta(body) {
5901
+ const capability = resolveClaudeCapability(String(body.model));
5827
5902
  const thinking = body.thinking;
5828
- return resolveClaudeCapability(String(body.model))?.thinkingBinding === true && (hasReplayedThinking(body) || isRecord(thinking) && thinking.block_binding !== void 0);
5903
+ return capability?.thinkingBinding === true && isRecord(thinking) && thinking.type === "adaptive" && thinking.block_binding !== void 0;
5829
5904
  }
5905
+ /**
5906
+ * Validate the final body (after `providerOptions`) against the effective
5907
+ * model's capability, then inject `block_binding` where it applies. Every
5908
+ * rule is gated on its own capability field and is a no-op when unset, so a
5909
+ * model only gets the guards its provider contract calls for.
5910
+ */
5830
5911
  validateAndBindFinalBody(body) {
5831
5912
  const model = typeof body.model === "string" ? body.model : "";
5832
- if (resolveClaudeCapability(model)?.thinkingBinding !== true) return;
5913
+ const capability = resolveClaudeCapability(model);
5914
+ if (!capability) return;
5833
5915
  const reject = (option, remediation) => {
5834
5916
  throw new UnsupportedModelOptionError({ provider: this.name, model, option, remediation });
5835
5917
  };
5836
- const toolChoice = body.tool_choice;
5837
- if (isRecord(toolChoice) && (toolChoice.type === "any" || toolChoice.type === "tool")) {
5838
- reject("forced tool choice", "Use toolChoice: 'auto' or 'none' on this model.");
5839
- }
5840
- if (body.thinking !== void 0 && (!isRecord(body.thinking) || body.thinking.type !== "adaptive" || body.thinking.budget_tokens !== void 0)) {
5841
- reject(
5842
- "manual or disabled thinking",
5843
- "Use thinking: { type: 'adaptive' } and output_config.effort."
5844
- );
5845
- }
5846
- const outputConfig = body.output_config;
5847
- if (outputConfig !== void 0 && (!isRecord(outputConfig) || outputConfig.effort !== void 0 && !["low", "medium", "high", "xhigh", "max"].includes(String(outputConfig.effort)))) {
5848
- reject("output_config.effort", "Use low, medium, high, xhigh, or max effort.");
5849
- }
5850
- if (body.temperature !== void 0 && body.temperature !== 1) {
5851
- reject("temperature", "Omit temperature or use the default value 1.");
5852
- }
5853
- if (body.top_p !== void 0 && (typeof body.top_p !== "number" || body.top_p < 0.99 || body.top_p > 1)) {
5854
- reject("top_p", "Omit top_p or use a value from 0.99 to 1.");
5918
+ if (capability.forcedToolChoice === "rejected") {
5919
+ const toolChoice = body.tool_choice;
5920
+ if (isRecord(toolChoice) && (toolChoice.type === "any" || toolChoice.type === "tool")) {
5921
+ reject("forced tool choice", "Use toolChoice: 'auto' or 'none' on this model.");
5922
+ }
5923
+ }
5924
+ if (capability.strictThinking) {
5925
+ const offShape = capability.thinking === "adaptive-always-on" ? void 0 : capability.offShape ?? "disabled";
5926
+ const thinking = body.thinking;
5927
+ const outputConfig = body.output_config;
5928
+ const effort = isRecord(outputConfig) ? outputConfig.effort : void 0;
5929
+ if (thinking !== void 0 && offShape === void 0) {
5930
+ if (!isRecord(thinking) || thinking.type !== "adaptive" || thinking.budget_tokens !== void 0) {
5931
+ reject(
5932
+ "manual or disabled thinking",
5933
+ "Use thinking: { type: 'adaptive' } and output_config.effort."
5934
+ );
5935
+ }
5936
+ } else if (thinking !== void 0) {
5937
+ if (!isRecord(thinking) || thinking.type !== "adaptive" && thinking.type !== offShape) {
5938
+ reject(
5939
+ "thinking.type",
5940
+ `Use thinking: { type: 'adaptive' }, or { type: '${offShape}' } to turn thinking off.`
5941
+ );
5942
+ }
5943
+ const record = thinking;
5944
+ if (record.type === "adaptive" && record.budget_tokens !== void 0) {
5945
+ reject("thinking.budget_tokens", "Use output_config.effort instead of budget_tokens.");
5946
+ }
5947
+ if (record.type === offShape) {
5948
+ const extra = Object.keys(record).filter((key) => key !== "type");
5949
+ if (extra.length > 0) {
5950
+ reject(
5951
+ `thinking.${offShape}.${extra[0]}`,
5952
+ `Send thinking: { type: '${offShape}' } with no other fields.`
5953
+ );
5954
+ }
5955
+ }
5956
+ }
5957
+ if (outputConfig !== void 0 && (!isRecord(outputConfig) || effort !== void 0 && !isNativeClaudeEffort(effort))) {
5958
+ reject("output_config.effort", "Use low, medium, high, xhigh, or max effort.");
5959
+ }
5960
+ if (offShape !== void 0 && isRecord(thinking) && thinking.type === offShape && effort !== void 0 && capability.disableAt && !isEffortAtOrBelow(effort, capability.disableAt)) {
5961
+ reject(
5962
+ "output_config.effort",
5963
+ `Thinking can be turned off only at effort '${capability.disableAt}' or below; lower the effort or use adaptive thinking.`
5964
+ );
5965
+ }
5855
5966
  }
5856
- if (body.top_k !== void 0) {
5857
- reject("top_k", "Omit top_k on this model.");
5967
+ if (capability.defaultOnlySampling) {
5968
+ if (body.temperature !== void 0 && body.temperature !== 1) {
5969
+ reject("temperature", "Omit temperature or use the default value 1.");
5970
+ }
5971
+ if (body.top_p !== void 0 && body.top_p !== 0.99) {
5972
+ reject("top_p", "Omit top_p or use the default value 0.99.");
5973
+ }
5974
+ if (body.temperature !== void 0 && body.top_p !== void 0) {
5975
+ reject("temperature and top_p", "Send at most one of temperature and top_p.");
5976
+ }
5977
+ if (body.top_k !== void 0) {
5978
+ reject("top_k", "Omit top_k on this model.");
5979
+ }
5858
5980
  }
5859
- const replayed = hasReplayedThinking(body);
5860
- if (!replayed) return;
5861
- const thinking = isRecord(body.thinking) ? body.thinking : { type: "adaptive" };
5862
- const binding = thinking.block_binding;
5863
- if (binding !== void 0 && (!isRecord(binding) || binding.prefix_mismatch_behavior !== "error" && binding.prefix_mismatch_behavior !== "drop_block")) {
5864
- reject("thinking.block_binding", "Use prefix_mismatch_behavior: 'error' or 'drop_block'.");
5981
+ if (capability.thinkingBinding === true && isFinalThinkingAdaptive(capability, body)) {
5982
+ const thinking = isRecord(body.thinking) ? body.thinking : { type: "adaptive" };
5983
+ const binding = thinking.block_binding;
5984
+ if (binding !== void 0 && (!isRecord(binding) || binding.prefix_mismatch_behavior !== "error" && binding.prefix_mismatch_behavior !== "drop_block")) {
5985
+ reject("thinking.block_binding", "Use prefix_mismatch_behavior: 'error' or 'drop_block'.");
5986
+ }
5987
+ if (hasReplayedThinking(body)) {
5988
+ body.thinking = {
5989
+ ...thinking,
5990
+ block_binding: binding ?? { prefix_mismatch_behavior: "drop_block" }
5991
+ };
5992
+ }
5865
5993
  }
5866
- body.thinking = {
5867
- ...thinking,
5868
- block_binding: binding ?? { prefix_mismatch_behavior: "drop_block" }
5869
- };
5870
5994
  }
5871
5995
  /** Extract a human-readable message from an API error response body. */
5872
5996
  extractErrorMessage(body, status) {