@axlsdk/axl 0.25.1 → 0.25.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -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
@@ -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.1" : "unknown"
351
+ version: true ? "0.25.2" : "unknown"
352
352
  };
353
353
  function warnCrossCopy(other, joined) {
354
354
  if (other === thisCopy) return;
@@ -4913,6 +4913,17 @@ var ANTHROPIC_THINKING_BINDING_BETA = "thinking-binding-controls-2026-08-01";
4913
4913
  function isRecord(value) {
4914
4914
  return value !== null && typeof value === "object" && !Array.isArray(value);
4915
4915
  }
4916
+ function isFinalThinkingAdaptive(capability, body) {
4917
+ const thinking = body.thinking;
4918
+ if (thinking === void 0) {
4919
+ return capability.thinking === "adaptive-default-on" || capability.thinking === "adaptive-always-on";
4920
+ }
4921
+ return isRecord(thinking) && thinking.type === "adaptive";
4922
+ }
4923
+ var NATIVE_CLAUDE_EFFORTS = ["low", "medium", "high", "xhigh", "max"];
4924
+ function isNativeClaudeEffort(value) {
4925
+ return NATIVE_CLAUDE_EFFORTS.includes(value);
4926
+ }
4916
4927
  function hasReplayedThinking(body) {
4917
4928
  return Array.isArray(body.messages) && body.messages.some(
4918
4929
  (message) => isRecord(message) && Array.isArray(message.content) && message.content.some(
@@ -4947,11 +4958,40 @@ function hasAnthropicProviderFileImage(messages) {
4947
4958
  );
4948
4959
  }
4949
4960
  var CLAUDE_CAPABILITIES = {
4961
+ // Thinking off is `between_tools` (progress updates between tool calls);
4962
+ // `disabled` is a provider 400. Forced tool choice is a 400.
4963
+ "claude-sonnet-5-5": {
4964
+ thinking: "adaptive-default-on",
4965
+ effortLevels: ["low", "medium", "high", "xhigh", "max"],
4966
+ manualBudget: false,
4967
+ stripTemperature: true,
4968
+ disableAt: "high",
4969
+ offShape: "between_tools",
4970
+ forcedToolChoice: "rejected",
4971
+ defaultOnlySampling: true,
4972
+ strictThinking: true,
4973
+ thinkingBinding: true
4974
+ },
4975
+ // Thinking off is `disabled`, only at effort high or below. Forced tool
4976
+ // choice is accepted (the provider skips thinking for that turn).
4977
+ "claude-haiku-5-5": {
4978
+ thinking: "adaptive-default-on",
4979
+ effortLevels: ["low", "medium", "high", "xhigh", "max"],
4980
+ manualBudget: false,
4981
+ stripTemperature: true,
4982
+ disableAt: "high",
4983
+ defaultOnlySampling: true,
4984
+ strictThinking: true,
4985
+ thinkingBinding: true
4986
+ },
4950
4987
  "claude-opus-5-5": {
4951
4988
  thinking: "adaptive-always-on",
4952
4989
  effortLevels: ["low", "medium", "high", "xhigh", "max"],
4953
4990
  manualBudget: false,
4954
4991
  stripTemperature: true,
4992
+ forcedToolChoice: "rejected",
4993
+ defaultOnlySampling: true,
4994
+ strictThinking: true,
4955
4995
  thinkingBinding: true
4956
4996
  },
4957
4997
  "claude-fable-5-1": {
@@ -4959,6 +4999,9 @@ var CLAUDE_CAPABILITIES = {
4959
4999
  effortLevels: ["low", "medium", "high", "xhigh", "max"],
4960
5000
  manualBudget: false,
4961
5001
  stripTemperature: true,
5002
+ forcedToolChoice: "rejected",
5003
+ defaultOnlySampling: true,
5004
+ strictThinking: true,
4962
5005
  thinkingBinding: true
4963
5006
  },
4964
5007
  "claude-fable-5": {
@@ -5053,6 +5096,15 @@ function resolveClaudeCapability(model) {
5053
5096
  }
5054
5097
  var DEFAULT_CACHE_READ_MULTIPLIER = 0.1;
5055
5098
  var ANTHROPIC_RATES = {
5099
+ // Sonnet 5.5 cache reads are 0.05x ($0.10/MTok): the pricing table, its
5100
+ // footnote, the models overview, and the prompt-caching guide agree
5101
+ // (re-checked 2026-10-07).
5102
+ "claude-sonnet-5-5": { input: 2e-6, output: 1e-5, cacheReadMultiplier: 0.05 },
5103
+ "claude-haiku-5-5": {
5104
+ input: 1e-7,
5105
+ output: 5e-7,
5106
+ longPrompt: { aboveTokens: 1e5, card: { input: 5e-7, output: 25e-7 } }
5107
+ },
5056
5108
  "claude-opus-5-5": { input: 4e-6, output: 2e-5, cacheReadMultiplier: 0.05 },
5057
5109
  "claude-fable-5-1": { input: 1e-5, output: 5e-5, cacheReadMultiplier: 0.025 },
5058
5110
  "claude-fable-5": { input: 1e-5, output: 5e-5 },
@@ -5115,14 +5167,16 @@ function estimateAnthropicCost(model, usage) {
5115
5167
  return void 0;
5116
5168
  }
5117
5169
  const cacheWriteTotal = safeTokenSum(cacheWrite5m, cacheWrite1h);
5118
- if (cacheWriteTotal === void 0 || safeTokenSum(usage.inputTokens, cacheRead, cacheWriteTotal) === void 0) {
5170
+ const promptTokens = cacheWriteTotal === void 0 ? void 0 : safeTokenSum(usage.inputTokens, cacheRead, cacheWriteTotal);
5171
+ if (cacheWriteTotal === void 0 || promptTokens === void 0) {
5119
5172
  return void 0;
5120
5173
  }
5121
5174
  if (usage.aggregateCacheWriteTokens !== void 0 && (!isValidTokenCount(usage.aggregateCacheWriteTokens) || usage.aggregateCacheWriteTokens !== cacheWriteTotal)) {
5122
5175
  return void 0;
5123
5176
  }
5124
- const { input, output } = rate;
5125
- const cacheReadRate = input * (rate.cacheReadMultiplier ?? DEFAULT_CACHE_READ_MULTIPLIER);
5177
+ const card = rate.longPrompt && promptTokens > rate.longPrompt.aboveTokens ? rate.longPrompt.card : rate;
5178
+ const { input, output } = card;
5179
+ const cacheReadRate = input * (card.cacheReadMultiplier ?? DEFAULT_CACHE_READ_MULTIPLIER);
5126
5180
  return usage.inputTokens * input + cacheRead * cacheReadRate + cacheWrite5m * input * 1.25 + cacheWrite1h * input * 2 + usage.outputTokens * output;
5127
5181
  }
5128
5182
  var THINKING_BUDGETS = {
@@ -5184,7 +5238,7 @@ function resolveClaudeThinking(model, resolved) {
5184
5238
  };
5185
5239
  }
5186
5240
  return {
5187
- thinking: { type: "disabled" },
5241
+ thinking: { type: capability.offShape ?? "disabled" },
5188
5242
  outputConfig: activeEffort ? { effort: activeEffort } : void 0,
5189
5243
  stripTemperature: true
5190
5244
  };
@@ -5590,50 +5644,106 @@ var AnthropicProvider = class {
5590
5644
  ...betas.length > 0 ? { "anthropic-beta": betas.join(",") } : {}
5591
5645
  };
5592
5646
  }
5647
+ /**
5648
+ * Whether the final body needs the binding beta header. Runs after
5649
+ * `validateAndBindFinalBody`, which has already injected `block_binding`
5650
+ * wherever it applies, so the header follows the final body rather than
5651
+ * re-deriving the injection rule.
5652
+ */
5593
5653
  requiresBindingBeta(body) {
5654
+ const capability = resolveClaudeCapability(String(body.model));
5594
5655
  const thinking = body.thinking;
5595
- return resolveClaudeCapability(String(body.model))?.thinkingBinding === true && (hasReplayedThinking(body) || isRecord(thinking) && thinking.block_binding !== void 0);
5656
+ return capability?.thinkingBinding === true && isRecord(thinking) && thinking.type === "adaptive" && thinking.block_binding !== void 0;
5596
5657
  }
5658
+ /**
5659
+ * Validate the final body (after `providerOptions`) against the effective
5660
+ * model's capability, then inject `block_binding` where it applies. Every
5661
+ * rule is gated on its own capability field and is a no-op when unset, so a
5662
+ * model only gets the guards its provider contract calls for.
5663
+ */
5597
5664
  validateAndBindFinalBody(body) {
5598
5665
  const model = typeof body.model === "string" ? body.model : "";
5599
- if (resolveClaudeCapability(model)?.thinkingBinding !== true) return;
5666
+ const capability = resolveClaudeCapability(model);
5667
+ if (!capability) return;
5600
5668
  const reject = (option, remediation) => {
5601
5669
  throw new UnsupportedModelOptionError({ provider: this.name, model, option, remediation });
5602
5670
  };
5603
- const toolChoice = body.tool_choice;
5604
- if (isRecord(toolChoice) && (toolChoice.type === "any" || toolChoice.type === "tool")) {
5605
- reject("forced tool choice", "Use toolChoice: 'auto' or 'none' on this model.");
5606
- }
5607
- if (body.thinking !== void 0 && (!isRecord(body.thinking) || body.thinking.type !== "adaptive" || body.thinking.budget_tokens !== void 0)) {
5608
- reject(
5609
- "manual or disabled thinking",
5610
- "Use thinking: { type: 'adaptive' } and output_config.effort."
5611
- );
5612
- }
5613
- const outputConfig = body.output_config;
5614
- if (outputConfig !== void 0 && (!isRecord(outputConfig) || outputConfig.effort !== void 0 && !["low", "medium", "high", "xhigh", "max"].includes(String(outputConfig.effort)))) {
5615
- reject("output_config.effort", "Use low, medium, high, xhigh, or max effort.");
5616
- }
5617
- if (body.temperature !== void 0 && body.temperature !== 1) {
5618
- reject("temperature", "Omit temperature or use the default value 1.");
5619
- }
5620
- if (body.top_p !== void 0 && (typeof body.top_p !== "number" || body.top_p < 0.99 || body.top_p > 1)) {
5621
- reject("top_p", "Omit top_p or use a value from 0.99 to 1.");
5671
+ if (capability.forcedToolChoice === "rejected") {
5672
+ const toolChoice = body.tool_choice;
5673
+ if (isRecord(toolChoice) && (toolChoice.type === "any" || toolChoice.type === "tool")) {
5674
+ reject("forced tool choice", "Use toolChoice: 'auto' or 'none' on this model.");
5675
+ }
5676
+ }
5677
+ if (capability.strictThinking) {
5678
+ const offShape = capability.thinking === "adaptive-always-on" ? void 0 : capability.offShape ?? "disabled";
5679
+ const thinking = body.thinking;
5680
+ const outputConfig = body.output_config;
5681
+ const effort = isRecord(outputConfig) ? outputConfig.effort : void 0;
5682
+ if (thinking !== void 0 && offShape === void 0) {
5683
+ if (!isRecord(thinking) || thinking.type !== "adaptive" || thinking.budget_tokens !== void 0) {
5684
+ reject(
5685
+ "manual or disabled thinking",
5686
+ "Use thinking: { type: 'adaptive' } and output_config.effort."
5687
+ );
5688
+ }
5689
+ } else if (thinking !== void 0) {
5690
+ if (!isRecord(thinking) || thinking.type !== "adaptive" && thinking.type !== offShape) {
5691
+ reject(
5692
+ "thinking.type",
5693
+ `Use thinking: { type: 'adaptive' }, or { type: '${offShape}' } to turn thinking off.`
5694
+ );
5695
+ }
5696
+ const record = thinking;
5697
+ if (record.type === "adaptive" && record.budget_tokens !== void 0) {
5698
+ reject("thinking.budget_tokens", "Use output_config.effort instead of budget_tokens.");
5699
+ }
5700
+ if (record.type === offShape) {
5701
+ const extra = Object.keys(record).filter((key) => key !== "type");
5702
+ if (extra.length > 0) {
5703
+ reject(
5704
+ `thinking.${offShape}.${extra[0]}`,
5705
+ `Send thinking: { type: '${offShape}' } with no other fields.`
5706
+ );
5707
+ }
5708
+ }
5709
+ }
5710
+ if (outputConfig !== void 0 && (!isRecord(outputConfig) || effort !== void 0 && !isNativeClaudeEffort(effort))) {
5711
+ reject("output_config.effort", "Use low, medium, high, xhigh, or max effort.");
5712
+ }
5713
+ if (offShape !== void 0 && isRecord(thinking) && thinking.type === offShape && effort !== void 0 && capability.disableAt && !isEffortAtOrBelow(effort, capability.disableAt)) {
5714
+ reject(
5715
+ "output_config.effort",
5716
+ `Thinking can be turned off only at effort '${capability.disableAt}' or below; lower the effort or use adaptive thinking.`
5717
+ );
5718
+ }
5622
5719
  }
5623
- if (body.top_k !== void 0) {
5624
- reject("top_k", "Omit top_k on this model.");
5720
+ if (capability.defaultOnlySampling) {
5721
+ if (body.temperature !== void 0 && body.temperature !== 1) {
5722
+ reject("temperature", "Omit temperature or use the default value 1.");
5723
+ }
5724
+ if (body.top_p !== void 0 && body.top_p !== 0.99) {
5725
+ reject("top_p", "Omit top_p or use the default value 0.99.");
5726
+ }
5727
+ if (body.temperature !== void 0 && body.top_p !== void 0) {
5728
+ reject("temperature and top_p", "Send at most one of temperature and top_p.");
5729
+ }
5730
+ if (body.top_k !== void 0) {
5731
+ reject("top_k", "Omit top_k on this model.");
5732
+ }
5625
5733
  }
5626
- const replayed = hasReplayedThinking(body);
5627
- if (!replayed) return;
5628
- const thinking = isRecord(body.thinking) ? body.thinking : { type: "adaptive" };
5629
- const binding = thinking.block_binding;
5630
- if (binding !== void 0 && (!isRecord(binding) || binding.prefix_mismatch_behavior !== "error" && binding.prefix_mismatch_behavior !== "drop_block")) {
5631
- reject("thinking.block_binding", "Use prefix_mismatch_behavior: 'error' or 'drop_block'.");
5734
+ if (capability.thinkingBinding === true && isFinalThinkingAdaptive(capability, body)) {
5735
+ const thinking = isRecord(body.thinking) ? body.thinking : { type: "adaptive" };
5736
+ const binding = thinking.block_binding;
5737
+ if (binding !== void 0 && (!isRecord(binding) || binding.prefix_mismatch_behavior !== "error" && binding.prefix_mismatch_behavior !== "drop_block")) {
5738
+ reject("thinking.block_binding", "Use prefix_mismatch_behavior: 'error' or 'drop_block'.");
5739
+ }
5740
+ if (hasReplayedThinking(body)) {
5741
+ body.thinking = {
5742
+ ...thinking,
5743
+ block_binding: binding ?? { prefix_mismatch_behavior: "drop_block" }
5744
+ };
5745
+ }
5632
5746
  }
5633
- body.thinking = {
5634
- ...thinking,
5635
- block_binding: binding ?? { prefix_mismatch_behavior: "drop_block" }
5636
- };
5637
5747
  }
5638
5748
  /** Extract a human-readable message from an API error response body. */
5639
5749
  extractErrorMessage(body, status) {