@cognipeer/agent-sdk 0.12.0 → 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/dist/index.cjs CHANGED
@@ -5105,10 +5105,10 @@ function createToolsNode(initialTools, opts) {
5105
5105
  const toolCallId = tc.id || `${tc.name}_${toolCount + 1}`;
5106
5106
  const validatedArgs = validateToolArgs(tool, args);
5107
5107
  if (!validatedArgs.ok && resolved.toolResponses.schemaValidation === "strict") {
5108
- const errorMessage = `Tool argument validation failed for ${tc.name}: ${validatedArgs.message}`;
5109
- push({ role: "tool", content: errorMessage, tool_call_id: toolCallId, name: tc.name });
5110
- markToolFailure(errorMessage, tc.name, toolCallId);
5111
- onEvent?.({ type: "tool_call", phase: "error", name: tc.name, id: tc.id, args, error: { message: errorMessage } });
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 } });
5112
5112
  toolCount += 1;
5113
5113
  return { status: "error" };
5114
5114
  }
@@ -6119,7 +6119,7 @@ var LEVEL_DEFAULTS = {
6119
6119
  };
6120
6120
  var VALID_LEVELS = ["minimal", "low", "medium", "high"];
6121
6121
  var VALID_CADENCES = ["off", "every_turn", "after_tool", "on_branch", "initial_then_after_tool"];
6122
- var VALID_EFFORTS = ["none", "minimal", "low", "medium", "high"];
6122
+ var VALID_EFFORTS = ["none", "minimal", "low", "medium", "high", "xhigh", "max"];
6123
6123
  function validateReasoningConfig(input) {
6124
6124
  if (!input) return;
6125
6125
  if (input.level !== void 0 && !VALID_LEVELS.includes(input.level)) {
@@ -11589,6 +11589,7 @@ var BaseProvider = class {
11589
11589
  /** Applies the transport options shared by every provider config. */
11590
11590
  configureTransport(config) {
11591
11591
  this.fetchImpl = config.fetch;
11592
+ this.onModelRuleLearned = config.onModelRuleLearned;
11592
11593
  this.timeoutMs = typeof config.timeoutMs === "number" && config.timeoutMs > 0 ? config.timeoutMs : void 0;
11593
11594
  }
11594
11595
  /**
@@ -15256,32 +15257,805 @@ function languageGuard(config) {
15256
15257
  // src/index.ts
15257
15258
  init_content();
15258
15259
 
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."
15880
+ }
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);
15905
+ }
15906
+ }
15907
+ return out;
15908
+ }
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;
15924
+ }
15925
+ const re = regexFor(rule);
15926
+ if (ids.some((id) => re.test(id))) return rule;
15927
+ }
15928
+ return void 0;
15929
+ }
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
+
15259
16037
  // src/providers/utils/reasoning.ts
15260
16038
  var ANTHROPIC_EFFORT_BUDGET = {
15261
16039
  // 0 = off. `applyAnthropicReasoning` bails on a falsy budget and emits no
15262
16040
  // thinking block, which on Anthropic IS off — thinking there is opt-in.
15263
16041
  none: 0,
15264
- minimal: 1024,
15265
- low: 2048,
15266
- medium: 8192,
15267
- high: 16384
16042
+ ...MODEL_RULES.budgets
15268
16043
  };
15269
16044
  var GEMINI_EFFORT_BUDGET = {
15270
16045
  // 0 is Gemini's own documented spelling for "do not think", and unlike
15271
16046
  // Anthropic it has to be SENT — hence `applyGeminiReasoning` testing for null
15272
16047
  // rather than falsiness.
15273
16048
  none: 0,
15274
- minimal: 512,
15275
- low: 1024,
15276
- medium: 4096,
15277
- high: 12e3
16049
+ ...MODEL_RULES.geminiBudgets
15278
16050
  };
15279
16051
  var THINKING_OUTPUT_RESERVE = 1024;
15280
16052
  var MIN_THINKING_BUDGET = 1024;
15281
16053
  var THINKING_MIN_MAX_TOKENS = 4096;
15282
- function applyOpenAIReasoning(body, reasoning, mode = "legacy_effort") {
16054
+ function applyOpenAIReasoning(body, reasoning, mode = "legacy_effort", model, rule) {
15283
16055
  if (!reasoning) return;
15284
- const effort = normalizeEffort(reasoning.effort);
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;
15285
16059
  if (mode === "responses") {
15286
16060
  const obj = {};
15287
16061
  if (effort) obj.effort = effort;
@@ -15295,48 +16069,54 @@ function applyOpenAIReasoning(body, reasoning, mode = "legacy_effort") {
15295
16069
  }
15296
16070
  function supportsAdaptiveThinking(model) {
15297
16071
  if (typeof model !== "string") return false;
15298
- const id = model.toLowerCase();
15299
- const at = id.indexOf("claude-");
15300
- if (at < 0) return false;
15301
- for (const tok of id.slice(at + 7).split("-")) {
15302
- if (tok === "fable") return true;
15303
- const m = /^(\d+)(?:@|$)/.exec(tok);
15304
- if (m) {
15305
- if (m[1].length <= 2) return Number(m[1]) >= 5;
15306
- return false;
15307
- }
15308
- }
15309
- return false;
16072
+ return resolveModelRule({ provider: "anthropic", model }).reasoning.style === "adaptive";
15310
16073
  }
15311
- function resolveThinkingForm(model, mode) {
16074
+ function resolveThinkingForm(model, mode, rule) {
15312
16075
  if (mode === "adaptive" || mode === "budget") return mode;
16076
+ if (rule) return rule.reasoning.style === "adaptive" ? "adaptive" : "budget";
15313
16077
  return supportsAdaptiveThinking(model) ? "adaptive" : "budget";
15314
16078
  }
15315
- function applyAdaptiveThinking(_body, reasoning, setThinking, setOutputConfig) {
15316
- const requested = normalizeEffort(reasoning.effort);
15317
- if (requested === "none") return false;
15318
- let effort;
15319
- if (requested) effort = requested === "minimal" ? "low" : requested;
15320
- else if (typeof reasoning.budgetTokens === "number" && reasoning.budgetTokens > 0) {
15321
- effort = reasoning.budgetTokens <= ANTHROPIC_EFFORT_BUDGET.low ? "low" : reasoning.budgetTokens <= ANTHROPIC_EFFORT_BUDGET.medium ? "medium" : "high";
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";
15322
16089
  }
15323
- if (!effort) return false;
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;
15324
16097
  const thinking = { type: "adaptive" };
15325
16098
  if (reasoning.includeThoughts !== false) thinking.display = "summarized";
15326
16099
  if (reasoning.providerExtras) Object.assign(thinking, reasoning.providerExtras);
15327
- setThinking({ thinking });
15328
- setOutputConfig({ effort });
16100
+ setThinking(thinking);
16101
+ setOutputConfig({ effort: mapped.effort });
15329
16102
  return true;
15330
16103
  }
15331
16104
  function applyAnthropicReasoning(body, reasoning, opts) {
15332
- if (!reasoning) return;
15333
- if (resolveThinkingForm(opts?.model ?? body.model, opts?.mode) === "adaptive") {
15334
- const on = applyAdaptiveThinking(body, reasoning, (extra) => body.thinking = extra.thinking, (o) => body.output_config = { ...body.output_config ?? {}, ...o });
15335
- if (on) stripSamplingParams(body, ["temperature", "top_p", "top_k"]);
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);
15336
16118
  return;
15337
16119
  }
15338
- let budget = resolveBudget(reasoning, ANTHROPIC_EFFORT_BUDGET);
15339
- if (!budget) return;
15340
16120
  const currentMax = typeof body.max_tokens === "number" ? body.max_tokens : 0;
15341
16121
  const requiredMax = Math.max(THINKING_MIN_MAX_TOKENS, budget + THINKING_OUTPUT_RESERVE);
15342
16122
  if (currentMax < requiredMax) {
@@ -15346,18 +16126,25 @@ function applyAnthropicReasoning(body, reasoning, opts) {
15346
16126
  const thinking = { type: "enabled", budget_tokens: budget };
15347
16127
  if (reasoning.providerExtras) Object.assign(thinking, reasoning.providerExtras);
15348
16128
  body.thinking = thinking;
15349
- stripSamplingParams(body, ["temperature", "top_p", "top_k"]);
16129
+ enforceAnthropicSampling(body, rule, true);
15350
16130
  }
15351
16131
  function applyBedrockReasoning(body, reasoning, opts) {
15352
- if (!reasoning) return;
15353
- if (resolveThinkingForm(opts?.model ?? body.modelId, opts?.mode) === "adaptive") {
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") {
15354
16138
  const fields = () => body.additionalModelRequestFields ?? (body.additionalModelRequestFields = {});
15355
- const on = applyAdaptiveThinking(body, reasoning, (extra2) => fields().thinking = extra2.thinking, (o) => fields().output_config = { ...fields().output_config ?? {}, ...o });
15356
- if (on && body.inferenceConfig) stripSamplingParams(body.inferenceConfig, ["temperature", "topP"]);
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);
15357
16146
  return;
15358
16147
  }
15359
- let budget = resolveBudget(reasoning, ANTHROPIC_EFFORT_BUDGET);
15360
- if (!budget) return;
15361
16148
  const inference = body.inferenceConfig ?? (body.inferenceConfig = {});
15362
16149
  const currentMax = typeof inference.maxTokens === "number" ? inference.maxTokens : 0;
15363
16150
  const requiredMax = Math.max(THINKING_MIN_MAX_TOKENS, budget + THINKING_OUTPUT_RESERVE);
@@ -15369,7 +16156,7 @@ function applyBedrockReasoning(body, reasoning, opts) {
15369
16156
  const thinking = { type: "enabled", budget_tokens: budget };
15370
16157
  if (reasoning.providerExtras) Object.assign(thinking, reasoning.providerExtras);
15371
16158
  extra.thinking = thinking;
15372
- stripSamplingParams(inference, ["temperature", "topP"]);
16159
+ enforceAnthropicSampling(inference, rule, true, true);
15373
16160
  }
15374
16161
  function applyGeminiReasoning(generationConfig, reasoning) {
15375
16162
  if (!reasoning) return;
@@ -15381,11 +16168,6 @@ function applyGeminiReasoning(generationConfig, reasoning) {
15381
16168
  if (reasoning.providerExtras) Object.assign(thinkingConfig, reasoning.providerExtras);
15382
16169
  generationConfig.thinkingConfig = thinkingConfig;
15383
16170
  }
15384
- function stripSamplingParams(target, keys) {
15385
- for (const k of keys) {
15386
- if (k in target) delete target[k];
15387
- }
15388
- }
15389
16171
  function clampBudget(budget, maxTokens) {
15390
16172
  if (typeof maxTokens !== "number" || maxTokens <= 0) return budget;
15391
16173
  const ceiling = maxTokens - THINKING_OUTPUT_RESERVE;
@@ -15394,16 +16176,17 @@ function clampBudget(budget, maxTokens) {
15394
16176
  }
15395
16177
  function normalizeEffort(effort) {
15396
16178
  if (!effort) return void 0;
15397
- const allowed = ["none", "minimal", "low", "medium", "high"];
16179
+ const allowed = ["none", "minimal", "low", "medium", "high", "xhigh", "max"];
15398
16180
  return allowed.includes(effort) ? effort : void 0;
15399
16181
  }
15400
- function resolveBudget(reasoning, effortBudget) {
16182
+ function resolveBudget(reasoning, effortBudget2, rule) {
15401
16183
  const effort = normalizeEffort(reasoning.effort);
15402
16184
  if (effort === "none") return 0;
15403
16185
  if (typeof reasoning.budgetTokens === "number" && reasoning.budgetTokens > 0) {
15404
16186
  return Math.floor(reasoning.budgetTokens);
15405
16187
  }
15406
- if (effort && effortBudget[effort]) return effortBudget[effort];
16188
+ const mapped = effort && rule ? mapReasoningEffort(rule, effort).effort : effort;
16189
+ if (mapped && effortBudget2[mapped]) return effortBudget2[mapped];
15407
16190
  return void 0;
15408
16191
  }
15409
16192
 
@@ -15474,6 +16257,211 @@ function parseSSEBlock(block) {
15474
16257
  return { event, data: dataLines.join("\n"), id, retry };
15475
16258
  }
15476
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
+
15477
16465
  // src/providers/utils/media.ts
15478
16466
  var EXTENSION_MIME = {
15479
16467
  jpg: "image/jpeg",
@@ -15774,8 +16762,7 @@ var OpenAIProvider = class extends BaseProvider {
15774
16762
  if (this.useResponsesApi(request)) {
15775
16763
  return this.completeResponses(request);
15776
16764
  }
15777
- const body = this.buildRequestBody(request, false);
15778
- const res = await this.doFetch(body, request.signal);
16765
+ const res = await this.fetchChat(request, false);
15779
16766
  const json = await res.json();
15780
16767
  return this.parseResponse(json);
15781
16768
  }
@@ -15799,8 +16786,7 @@ var OpenAIProvider = class extends BaseProvider {
15799
16786
  };
15800
16787
  return;
15801
16788
  }
15802
- const body = this.buildRequestBody(request, true);
15803
- const res = await this.doFetch(body, request.signal);
16789
+ const res = await this.fetchChat(request, true);
15804
16790
  if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
15805
16791
  let id = "";
15806
16792
  let model = "";
@@ -15904,7 +16890,43 @@ var OpenAIProvider = class extends BaseProvider {
15904
16890
  return res;
15905
16891
  }
15906
16892
  // ─── Internals ───────────────────────────────────────────────────────────
15907
- buildRequestBody(request, stream) {
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) {
15908
16930
  const body = {
15909
16931
  model: request.model || this.defaultModel,
15910
16932
  messages: request.messages.map((m) => this.toOpenAIMessage(m)),
@@ -15914,20 +16936,20 @@ var OpenAIProvider = class extends BaseProvider {
15914
16936
  body.stream_options = { include_usage: true };
15915
16937
  }
15916
16938
  const modelId = String(body.model);
15917
- const reasoningModel = isReasoningModel(modelId) && !/chat/i.test(modelId);
15918
- if (request.temperature != null && !reasoningModel) body.temperature = request.temperature;
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;
15919
16941
  if (request.maxTokens != null) {
15920
- const useCompletionTokens = this.maxTokensParam === "max_completion_tokens" || this.maxTokensParam === "auto" && isReasoningModel(modelId);
15921
- body[useCompletionTokens ? "max_completion_tokens" : "max_tokens"] = request.maxTokens;
16942
+ const param = this.maxTokensParam === "auto" ? rule.maxTokensParam : this.maxTokensParam;
16943
+ body[param] = request.maxTokens;
15922
16944
  }
15923
- if (request.topP != null && !reasoningModel) body.top_p = request.topP;
16945
+ if (request.topP != null && allowsSampling(rule, "topP")) body.top_p = request.topP;
15924
16946
  if (request.stop) body.stop = request.stop;
15925
- if (request.presencePenalty != null) body.presence_penalty = request.presencePenalty;
15926
- if (request.frequencyPenalty != null) body.frequency_penalty = request.frequencyPenalty;
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;
15927
16949
  if (request.seed != null) body.seed = request.seed;
15928
16950
  if (request.n != null) body.n = request.n;
15929
- if (request.logprobs != null) body.logprobs = request.logprobs;
15930
- if (request.topLogprobs != null) body.top_logprobs = request.topLogprobs;
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;
15931
16953
  if (request.tools?.length) {
15932
16954
  body.tools = request.tools.map((t) => this.toOpenAITool(t));
15933
16955
  if (request.parallelToolCalls != null) body.parallel_tool_calls = request.parallelToolCalls;
@@ -15956,14 +16978,17 @@ var OpenAIProvider = class extends BaseProvider {
15956
16978
  if (request.extra) {
15957
16979
  Object.assign(body, request.extra);
15958
16980
  }
15959
- 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);
15960
16986
  return body;
15961
16987
  }
15962
16988
  // ─── Responses API (reasoning models) ──────────────────────────────────────
15963
16989
  async completeResponses(request) {
15964
- const body = this.buildResponsesBody(request);
15965
- if (this.apiResponsesNative || this.isResponsesApiModel(request)) adaptChatExtrasForResponses(body, request.extra);
15966
- const res = await this.responsesFetch(body, request.signal);
16990
+ const adapt = this.apiResponsesNative || this.isResponsesApiModel(request);
16991
+ const res = await this.fetchResponses(request, adapt);
15967
16992
  const json = await res.json();
15968
16993
  return this.parseResponsesResponse(json, request.model || this.defaultModel);
15969
16994
  }
@@ -15976,10 +17001,7 @@ var OpenAIProvider = class extends BaseProvider {
15976
17001
  * reads it). */
15977
17002
  async *streamResponses(request) {
15978
17003
  const modelId = request.model || this.defaultModel;
15979
- const body = this.buildResponsesBody(request);
15980
- adaptChatExtrasForResponses(body, request.extra);
15981
- body.stream = true;
15982
- const res = await this.responsesFetch(body, request.signal);
17004
+ const res = await this.fetchResponses(request, true, true);
15983
17005
  if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
15984
17006
  let id = "";
15985
17007
  let model = modelId;
@@ -16068,13 +17090,14 @@ var OpenAIProvider = class extends BaseProvider {
16068
17090
  finishReason: final?.finishReason ?? (calls.size > 0 ? "tool_calls" : "stop")
16069
17091
  };
16070
17092
  }
16071
- buildResponsesBody(request) {
17093
+ buildResponsesBody(request, overlay) {
16072
17094
  const body = {
16073
17095
  model: request.model || this.defaultModel,
16074
17096
  input: request.messages.map((m) => this.toResponsesInput(m))
16075
17097
  };
16076
17098
  if (request.maxTokens != null) body.max_output_tokens = request.maxTokens;
16077
- if (request.topP != null) body.top_p = request.topP;
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;
16078
17101
  if (request.tools?.length) {
16079
17102
  body.tools = request.tools.map((t) => ({
16080
17103
  type: "function",
@@ -16106,7 +17129,8 @@ var OpenAIProvider = class extends BaseProvider {
16106
17129
  }
16107
17130
  }
16108
17131
  if (request.extra) Object.assign(body, request.extra);
16109
- applyOpenAIReasoning(body, request.reasoning, "responses");
17132
+ applyOpenAIReasoning(body, request.reasoning, "responses", String(body.model), rule);
17133
+ applyDropParams(body, rule);
16110
17134
  return body;
16111
17135
  }
16112
17136
  /** Maps a unified message to a Responses API `input` item. */
@@ -16371,8 +17395,8 @@ function pickProviderFields(top, message, choice) {
16371
17395
  }
16372
17396
  function isReasoningModel(model) {
16373
17397
  if (!model) return false;
16374
- const m = model.toLowerCase();
16375
- return /(^|[/_-])o[0-9]/.test(m) || m.startsWith("o1") || m.startsWith("o3") || m.startsWith("o4") || m.includes("gpt-5") || m.includes("gpt5");
17398
+ const rule = resolveModelRule({ provider: "openai", model });
17399
+ return !rule.isDefault && rule.reasoning.style === "effort" && rule.sampling.temperature !== "any";
16376
17400
  }
16377
17401
  function adaptChatExtrasForResponses(body, extra) {
16378
17402
  const native = extra ?? {};
@@ -16488,12 +17512,6 @@ function normalizeExplicitThinking(body) {
16488
17512
  }
16489
17513
  for (const k of ["temperature", "top_p", "top_k"]) delete body[k];
16490
17514
  }
16491
- function thinkingFormRejected(text) {
16492
- const t = text.toLowerCase();
16493
- if (t.indexOf("thinking.type.enabled") >= 0 && t.indexOf("not supported") >= 0) return "enabled";
16494
- if (t.indexOf("thinking.type.adaptive") >= 0 && t.indexOf("not supported") >= 0 && t.indexOf("thinking.type.enabled") < 0) return "adaptive";
16495
- return void 0;
16496
- }
16497
17515
  var AnthropicProvider = class extends BaseProvider {
16498
17516
  constructor(config) {
16499
17517
  super();
@@ -16644,7 +17662,7 @@ var AnthropicProvider = class extends BaseProvider {
16644
17662
  }
16645
17663
  }
16646
17664
  // ─── Internals ───────────────────────────────────────────────────────────
16647
- buildRequestBody(request, stream, modeOverride, downgradeToolChoice = false) {
17665
+ buildRequestBody(request, stream, overlay, downgradeToolChoice = false) {
16648
17666
  const { system, messages } = this.splitSystemMessages(request.messages);
16649
17667
  const body = {
16650
17668
  model: request.model || this.defaultModel,
@@ -16659,6 +17677,7 @@ var AnthropicProvider = class extends BaseProvider {
16659
17677
  body.system = system;
16660
17678
  }
16661
17679
  }
17680
+ const rule = resolveModelRule({ provider: this.providerName, model: String(body.model), patch: overlay });
16662
17681
  if (request.temperature != null) body.temperature = request.temperature;
16663
17682
  if (request.topP != null) body.top_p = request.topP;
16664
17683
  if (request.stop) body.stop_sequences = request.stop;
@@ -16685,9 +17704,11 @@ var AnthropicProvider = class extends BaseProvider {
16685
17704
  const explicitThinking = request.extra && typeof request.extra === "object" && "thinking" in request.extra;
16686
17705
  if (explicitThinking) {
16687
17706
  normalizeExplicitThinking(body);
17707
+ enforceAnthropicSampling(body, rule, body.thinking?.type === "enabled" || body.thinking?.type === "adaptive");
16688
17708
  } else {
16689
- applyAnthropicReasoning(body, request.reasoning, { model: body.model, mode: modeOverride ?? this.thinkingMode });
17709
+ applyAnthropicReasoning(body, request.reasoning, { model: body.model, mode: this.thinkingMode, rule });
16690
17710
  }
17711
+ applyDropParams(body, rule);
16691
17712
  if (typeof body.max_tokens !== "number" || !(body.max_tokens > 0)) {
16692
17713
  body.max_tokens = DEFAULT_MAX_TOKENS;
16693
17714
  }
@@ -16823,31 +17844,28 @@ var AnthropicProvider = class extends BaseProvider {
16823
17844
  }
16824
17845
  /** Builds and sends the request; retries once with the other thinking form
16825
17846
  * when the upstream rejects the one we picked. */
16826
- async send(request, stream) {
16827
- let mode;
17847
+ send(request, stream) {
16828
17848
  let downgrade = false;
16829
- let flippedThinking = false;
16830
- for (; ; ) {
16831
- const body = this.buildRequestBody(request, stream, mode, downgrade);
16832
- try {
16833
- return await this.doFetch(body, request.signal);
16834
- } catch (err) {
16835
- if (!(err instanceof ProviderError) || err.statusCode !== 400) throw err;
16836
- const text = String(err.responseBody ?? err.message);
16837
- if (!downgrade && body.tool_choice && body.tool_choice.type !== "auto" && forcedToolChoiceRejected(text)) {
16838
- downgrade = true;
16839
- continue;
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
+ }
16840
17866
  }
16841
- const explicit = request.extra && typeof request.extra === "object" && "thinking" in request.extra;
16842
- if (flippedThinking || explicit || !request.reasoning) throw err;
16843
- const wrong = thinkingFormRejected(text);
16844
- if (!wrong) throw err;
16845
- const used = resolveThinkingForm(request.model ?? this.defaultModel, this.thinkingMode);
16846
- if (wrong === "enabled" && used !== "budget" || wrong === "adaptive" && used !== "adaptive") throw err;
16847
- mode = wrong === "enabled" ? "adaptive" : "budget";
16848
- flippedThinking = true;
16849
17867
  }
16850
- }
17868
+ });
16851
17869
  }
16852
17870
  async doFetch(body, signal) {
16853
17871
  const url = `${this.baseURL}/v1/messages`;
@@ -16964,6 +17982,7 @@ var AzureProvider = class extends OpenAIProvider {
16964
17982
  retry: config.retry,
16965
17983
  fetch: config.fetch,
16966
17984
  timeoutMs: config.timeoutMs,
17985
+ onModelRuleLearned: config.onModelRuleLearned,
16967
17986
  maxTokensParam: config.maxTokensParam,
16968
17987
  api: config.api,
16969
17988
  responsesApi: config.responsesApi,
@@ -17092,6 +18111,7 @@ var OpenAICompatibleProvider = class extends OpenAIProvider {
17092
18111
  retry: config.retry,
17093
18112
  fetch: config.fetch,
17094
18113
  timeoutMs: config.timeoutMs,
18114
+ onModelRuleLearned: config.onModelRuleLearned,
17095
18115
  maxTokensParam: config.maxTokensParam,
17096
18116
  api: config.api,
17097
18117
  // Unlike OpenAI / Azure, "auto" on a compatible server means Chat
@@ -17447,7 +18467,7 @@ var BedrockProvider = class extends BaseProvider {
17447
18467
  return res;
17448
18468
  }
17449
18469
  // ─── Internals ───────────────────────────────────────────────────────────
17450
- buildConverseBody(request, downgradeToolChoice = false) {
18470
+ buildConverseBody(request, downgradeToolChoice = false, overlay) {
17451
18471
  const { system, messages } = this.splitSystemMessages(request.messages);
17452
18472
  const body = {
17453
18473
  messages: this.toBedrockMessages(messages)
@@ -17493,7 +18513,12 @@ var BedrockProvider = class extends BaseProvider {
17493
18513
  Object.assign(body, topLevel);
17494
18514
  if (Object.keys(fields).length > 0) body.additionalModelRequestFields = fields;
17495
18515
  }
17496
- applyBedrockReasoning(body, request.reasoning, { model: request.model || this.defaultModel, mode: this.thinkingMode });
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);
17497
18522
  return body;
17498
18523
  }
17499
18524
  splitSystemMessages(messages) {
@@ -17618,16 +18643,29 @@ var BedrockProvider = class extends BaseProvider {
17618
18643
  }
17619
18644
  /** Sends the Converse call; retries once with toolChoice auto when the
17620
18645
  * model rejects forced tool use. */
17621
- async converseFetch(modelId, request, stream) {
17622
- const body = this.buildConverseBody(request);
17623
- try {
17624
- return await this.doFetch(modelId, body, request.signal, stream);
17625
- } catch (err) {
17626
- const tc = body.toolConfig?.toolChoice;
17627
- if (!(err instanceof ProviderError) || err.statusCode !== 400 || !tc || tc.auto) throw err;
17628
- if (!forcedToolChoiceRejected(String(err.responseBody ?? err.message))) throw err;
17629
- return this.doFetch(modelId, this.buildConverseBody(request, true), request.signal, stream);
17630
- }
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
+ });
17631
18669
  }
17632
18670
  async doFetch(modelId, body, signal, stream) {
17633
18671
  const host = `bedrock-runtime.${this.region}.amazonaws.com`;
@@ -17817,7 +18855,7 @@ var VertexProvider = class extends BaseProvider {
17817
18855
  const modelId = request.model || this.defaultModel;
17818
18856
  const body = this.buildGeminiBody(request);
17819
18857
  const url = this.buildUrl(modelId, false);
17820
- const res = await this.doFetch(url, body, request.signal);
18858
+ const res = await this.doFetch(url, body, request.signal, modelId);
17821
18859
  const json = await res.json();
17822
18860
  return this.parseResponse(json, modelId);
17823
18861
  }
@@ -17825,7 +18863,7 @@ var VertexProvider = class extends BaseProvider {
17825
18863
  const modelId = request.model || this.defaultModel;
17826
18864
  const body = this.buildGeminiBody(request);
17827
18865
  const url = this.buildUrl(modelId, true);
17828
- const res = await this.doFetch(url, body, request.signal);
18866
+ const res = await this.doFetch(url, body, request.signal, modelId);
17829
18867
  if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
17830
18868
  const counter = { next: 0 };
17831
18869
  const contentType = res.headers.get("content-type") ?? "";
@@ -17905,7 +18943,7 @@ var VertexProvider = class extends BaseProvider {
17905
18943
  };
17906
18944
  if (Object.keys(parameters).length > 0) body.parameters = parameters;
17907
18945
  Object.assign(body, extraRest);
17908
- const res = await this.doFetch(url, body, request.signal);
18946
+ const res = await this.doFetch(url, body, request.signal, model);
17909
18947
  const json = await res.json();
17910
18948
  raw.push(json);
17911
18949
  for (const p of json.predictions ?? []) {
@@ -18128,7 +19166,7 @@ var VertexProvider = class extends BaseProvider {
18128
19166
  const tokenJson = await tokenRes.json();
18129
19167
  return tokenJson.access_token;
18130
19168
  }
18131
- async doFetch(url, body, signal) {
19169
+ async doFetch(url, body, signal, model = "") {
18132
19170
  const token = await this.getAccessToken();
18133
19171
  const bodyStr = JSON.stringify(body);
18134
19172
  const res = await this.doFetchWithRetry(
@@ -18146,6 +19184,20 @@ var VertexProvider = class extends BaseProvider {
18146
19184
  );
18147
19185
  if (!res.ok) {
18148
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
+ }
18149
19201
  throw new ProviderError(
18150
19202
  `Vertex AI API error ${res.status}: ${text}`,
18151
19203
  this.providerName,
@@ -18327,6 +19379,9 @@ exports.HOOK_NAMES = HOOK_NAMES;
18327
19379
  exports.HookTimeoutError = HookTimeoutError;
18328
19380
  exports.InMemoryMemoryStore = InMemoryMemoryStore;
18329
19381
  exports.JevProvider = JevProvider;
19382
+ exports.MAX_ADJUSTMENTS = MAX_ADJUSTMENTS;
19383
+ exports.MODEL_RULES = MODEL_RULES;
19384
+ exports.ModelRequestError = ModelRequestError;
18330
19385
  exports.NativeJsonSchemaStrategy = NativeJsonSchemaStrategy;
18331
19386
  exports.OpenAICompatibleProvider = OpenAICompatibleProvider;
18332
19387
  exports.OpenAIProvider = OpenAIProvider;
@@ -18338,7 +19393,10 @@ exports.TOOL_INPUT_DIGEST_KEY = TOOL_INPUT_DIGEST_KEY;
18338
19393
  exports.ToolBasedStrategy = ToolBasedStrategy;
18339
19394
  exports.VertexProvider = VertexProvider;
18340
19395
  exports.agentVerdictRule = agentVerdictRule;
19396
+ exports.allowsSampling = allowsSampling;
18341
19397
  exports.appendBoundTools = appendBoundTools;
19398
+ exports.applyDropParams = applyDropParams;
19399
+ exports.asModelRequestError = asModelRequestError;
18342
19400
  exports.auditLog = auditLog;
18343
19401
  exports.azureContentSafety = azureContentSafety;
18344
19402
  exports.bedrockGuardrail = bedrockGuardrail;
@@ -18353,6 +19411,7 @@ exports.canOpenSkill = canOpenSkill;
18353
19411
  exports.canSpawn = canSpawn;
18354
19412
  exports.captureSnapshot = captureSnapshot;
18355
19413
  exports.checkpointing = checkpointing;
19414
+ exports.clearLearnedModelRules = clearLearnedModelRules;
18356
19415
  exports.codePresenceRule = codePresenceRule;
18357
19416
  exports.coerceToolArgs = coerceToolArgs;
18358
19417
  exports.cognipeerGuardrail = cognipeerGuardrail;
@@ -18415,6 +19474,7 @@ exports.detectTextFormat = detectTextFormat;
18415
19474
  exports.detectVolatileContent = detectVolatileContent;
18416
19475
  exports.digestToolInputArguments = digestToolInputArguments;
18417
19476
  exports.digestToolInputValue = digestToolInputValue;
19477
+ exports.effortBudget = effortBudget;
18418
19478
  exports.emptyUsage = emptyUsage;
18419
19479
  exports.evaluateGuardrails = evaluateGuardrails;
18420
19480
  exports.extractLatestUserQuery = extractLatestUserQuery;
@@ -18428,6 +19488,7 @@ exports.fromLangchainTools = fromLangchainTools;
18428
19488
  exports.fromNativeProvider = fromNativeProvider;
18429
19489
  exports.generateSpanId = generateSpanId;
18430
19490
  exports.generateTraceId = generateTraceId;
19491
+ exports.getLearnedModelRulePatch = getLearnedModelRulePatch;
18431
19492
  exports.getModelCapabilities = getModelCapabilities;
18432
19493
  exports.getNestedValue = getNestedValue;
18433
19494
  exports.getResolvedSmartConfig = getResolvedSmartConfig;
@@ -18448,12 +19509,16 @@ exports.jsonSchemaRule = jsonSchemaRule;
18448
19509
  exports.langfuseDefaultPayload = defaultBuildPayload;
18449
19510
  exports.langfuseTracing = langfuseTracing;
18450
19511
  exports.languageGuard = languageGuard;
19512
+ exports.listLearnedModelRules = listLearnedModelRules;
18451
19513
  exports.loadSkillsFromDisk = loadSkillsFromDisk;
18452
19514
  exports.mapConsoleHookVerdict = mapConsoleHookVerdict;
19515
+ exports.mapReasoningEffort = mapReasoningEffort;
18453
19516
  exports.mapTextParts = mapTextParts;
18454
19517
  exports.mcp = mcp;
18455
19518
  exports.mediaKindOf = mediaKindOf;
18456
19519
  exports.mediaPolicy = mediaPolicy;
19520
+ exports.mergeRulePatch = mergeRulePatch;
19521
+ exports.modelIdCandidates = modelIdCandidates;
18457
19522
  exports.normalizeSmartAgentOptions = normalizeSmartAgentOptions;
18458
19523
  exports.normalizeVerdicts = normalizeVerdicts;
18459
19524
  exports.openAIModeration = openAIModeration;
@@ -18461,6 +19526,7 @@ exports.otelTracing = otelTracing;
18461
19526
  exports.otlpSink = otlpSink;
18462
19527
  exports.outputGuard = outputGuard;
18463
19528
  exports.parseApprovalDecision = parseApprovalDecision;
19529
+ exports.parseModelError = parseModelError;
18464
19530
  exports.parseSkillFrontmatter = parseSkillFrontmatter;
18465
19531
  exports.pathSandbox = pathSandbox;
18466
19532
  exports.piiRedaction = piiRedaction;
@@ -18476,11 +19542,13 @@ exports.readMemoryFacts = readMemoryFacts;
18476
19542
  exports.redactText = redactText;
18477
19543
  exports.regexGuardrail = regexGuardrail;
18478
19544
  exports.regexRule = regexRule;
19545
+ exports.rememberModelRulePatch = rememberModelRulePatch;
18479
19546
  exports.replaceTextContent = replaceTextContent;
18480
19547
  exports.resolveAvailableSkills = resolveAvailableSkills;
18481
19548
  exports.resolveAvailableSubagents = resolveAvailableSubagents;
18482
19549
  exports.resolveInputRetention = resolveInputRetention;
18483
19550
  exports.resolveMemoryStore = resolveMemoryStore;
19551
+ exports.resolveModelRule = resolveModelRule;
18484
19552
  exports.resolveReasoning = resolveReasoning;
18485
19553
  exports.resolveStrategy = resolveStrategy;
18486
19554
  exports.resolveSubagentTools = resolveSubagentTools;
@@ -18491,6 +19559,7 @@ exports.responseCache = responseCache;
18491
19559
  exports.restoreSnapshot = restoreSnapshot;
18492
19560
  exports.restoreToolCalls = restoreToolCalls;
18493
19561
  exports.runSmartAgentEvalHarness = runSmartAgentEvalHarness;
19562
+ exports.runWithModelAdjustments = runWithModelAdjustments;
18494
19563
  exports.scoreItemsByRelevance = scoreItemsByRelevance;
18495
19564
  exports.searchSkills = searchSkills;
18496
19565
  exports.seedChildMessages = seedChildMessages;