@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.mjs CHANGED
@@ -5095,10 +5095,10 @@ function createToolsNode(initialTools, opts) {
5095
5095
  const toolCallId = tc.id || `${tc.name}_${toolCount + 1}`;
5096
5096
  const validatedArgs = validateToolArgs(tool, args);
5097
5097
  if (!validatedArgs.ok && resolved.toolResponses.schemaValidation === "strict") {
5098
- const errorMessage = `Tool argument validation failed for ${tc.name}: ${validatedArgs.message}`;
5099
- push({ role: "tool", content: errorMessage, tool_call_id: toolCallId, name: tc.name });
5100
- markToolFailure(errorMessage, tc.name, toolCallId);
5101
- onEvent?.({ type: "tool_call", phase: "error", name: tc.name, id: tc.id, args, error: { message: errorMessage } });
5098
+ const errorMessage2 = `Tool argument validation failed for ${tc.name}: ${validatedArgs.message}`;
5099
+ push({ role: "tool", content: errorMessage2, tool_call_id: toolCallId, name: tc.name });
5100
+ markToolFailure(errorMessage2, tc.name, toolCallId);
5101
+ onEvent?.({ type: "tool_call", phase: "error", name: tc.name, id: tc.id, args, error: { message: errorMessage2 } });
5102
5102
  toolCount += 1;
5103
5103
  return { status: "error" };
5104
5104
  }
@@ -6109,7 +6109,7 @@ var LEVEL_DEFAULTS = {
6109
6109
  };
6110
6110
  var VALID_LEVELS = ["minimal", "low", "medium", "high"];
6111
6111
  var VALID_CADENCES = ["off", "every_turn", "after_tool", "on_branch", "initial_then_after_tool"];
6112
- var VALID_EFFORTS = ["none", "minimal", "low", "medium", "high"];
6112
+ var VALID_EFFORTS = ["none", "minimal", "low", "medium", "high", "xhigh", "max"];
6113
6113
  function validateReasoningConfig(input) {
6114
6114
  if (!input) return;
6115
6115
  if (input.level !== void 0 && !VALID_LEVELS.includes(input.level)) {
@@ -11579,6 +11579,7 @@ var BaseProvider = class {
11579
11579
  /** Applies the transport options shared by every provider config. */
11580
11580
  configureTransport(config) {
11581
11581
  this.fetchImpl = config.fetch;
11582
+ this.onModelRuleLearned = config.onModelRuleLearned;
11582
11583
  this.timeoutMs = typeof config.timeoutMs === "number" && config.timeoutMs > 0 ? config.timeoutMs : void 0;
11583
11584
  }
11584
11585
  /**
@@ -15246,32 +15247,805 @@ function languageGuard(config) {
15246
15247
  // src/index.ts
15247
15248
  init_content();
15248
15249
 
15250
+ // src/models/model-rules.json
15251
+ var model_rules_default = {
15252
+ version: 1,
15253
+ effortLadder: [
15254
+ "none",
15255
+ "minimal",
15256
+ "low",
15257
+ "medium",
15258
+ "high",
15259
+ "xhigh",
15260
+ "max"
15261
+ ],
15262
+ budgets: {
15263
+ minimal: 1024,
15264
+ low: 2048,
15265
+ medium: 8192,
15266
+ high: 16384,
15267
+ xhigh: 24576,
15268
+ max: 32768
15269
+ },
15270
+ geminiBudgets: {
15271
+ minimal: 512,
15272
+ low: 1024,
15273
+ medium: 4096,
15274
+ high: 12e3,
15275
+ xhigh: 24576,
15276
+ max: 24576
15277
+ },
15278
+ rules: [
15279
+ {
15280
+ id: "openai-chat-models",
15281
+ family: "openai",
15282
+ match: "^(?:chatgpt|gpt-[\\d.]+[a-z0-9.-]*?-chat)",
15283
+ reasoning: {
15284
+ style: "none",
15285
+ efforts: [],
15286
+ off: null
15287
+ },
15288
+ sampling: {
15289
+ temperature: "any",
15290
+ topP: true,
15291
+ topK: true,
15292
+ penalties: true,
15293
+ logprobs: true
15294
+ },
15295
+ maxTokensParam: "max_completion_tokens",
15296
+ chatTools: {
15297
+ reasoning: "any"
15298
+ },
15299
+ source: "docs",
15300
+ note: "Chat-tuned *-chat variants are not reasoning models: ordinary sampling, no reasoning field."
15301
+ },
15302
+ {
15303
+ id: "openai-gpt-6-plus",
15304
+ family: "openai",
15305
+ match: "^gpt-?(?:[6-9]|(?!35(?!\\d))[1-9]\\d+)(?:[.-]|$)",
15306
+ reasoning: {
15307
+ style: "effort",
15308
+ efforts: [
15309
+ "none",
15310
+ "low",
15311
+ "medium",
15312
+ "high",
15313
+ "xhigh"
15314
+ ],
15315
+ off: "none",
15316
+ responsesEfforts: [
15317
+ "none",
15318
+ "low",
15319
+ "medium",
15320
+ "high",
15321
+ "xhigh",
15322
+ "max"
15323
+ ]
15324
+ },
15325
+ sampling: {
15326
+ temperature: "default-only",
15327
+ topP: false,
15328
+ topK: false,
15329
+ penalties: false,
15330
+ logprobs: false
15331
+ },
15332
+ maxTokensParam: "max_completion_tokens",
15333
+ chatTools: {
15334
+ reasoning: "force-none"
15335
+ },
15336
+ source: "verified-2026-10-14",
15337
+ 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."
15338
+ },
15339
+ {
15340
+ id: "openai-gpt-5x",
15341
+ family: "openai",
15342
+ match: "^gpt-?5\\.[1-9]",
15343
+ reasoning: {
15344
+ style: "effort",
15345
+ efforts: [
15346
+ "none",
15347
+ "low",
15348
+ "medium",
15349
+ "high",
15350
+ "xhigh"
15351
+ ],
15352
+ off: "none",
15353
+ responsesEfforts: [
15354
+ "none",
15355
+ "low",
15356
+ "medium",
15357
+ "high",
15358
+ "xhigh",
15359
+ "max"
15360
+ ]
15361
+ },
15362
+ sampling: {
15363
+ temperature: "default-only",
15364
+ topP: false,
15365
+ topK: false,
15366
+ penalties: false,
15367
+ logprobs: false
15368
+ },
15369
+ maxTokensParam: "max_completion_tokens",
15370
+ chatTools: {
15371
+ reasoning: "force-none"
15372
+ },
15373
+ source: "verified-2026-10-14",
15374
+ 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."
15375
+ },
15376
+ {
15377
+ id: "openai-gpt-5-base",
15378
+ family: "openai",
15379
+ match: "^gpt-?5(?![.\\d])",
15380
+ reasoning: {
15381
+ style: "effort",
15382
+ efforts: [
15383
+ "minimal",
15384
+ "low",
15385
+ "medium",
15386
+ "high"
15387
+ ],
15388
+ off: null
15389
+ },
15390
+ sampling: {
15391
+ temperature: "default-only",
15392
+ topP: false,
15393
+ topK: false,
15394
+ penalties: false,
15395
+ logprobs: false
15396
+ },
15397
+ maxTokensParam: "max_completion_tokens",
15398
+ chatTools: {
15399
+ reasoning: "any"
15400
+ },
15401
+ source: "docs",
15402
+ note: "gpt-5, -mini, -nano, -codex: minimal/low/medium/high, reasoning cannot be turned off (none maps to minimal)."
15403
+ },
15404
+ {
15405
+ id: "openai-o-series",
15406
+ family: "openai",
15407
+ match: "^o[1-9]\\d?(?![a-z0-9])",
15408
+ reasoning: {
15409
+ style: "effort",
15410
+ efforts: [
15411
+ "low",
15412
+ "medium",
15413
+ "high"
15414
+ ],
15415
+ off: null
15416
+ },
15417
+ sampling: {
15418
+ temperature: "default-only",
15419
+ topP: false,
15420
+ topK: false,
15421
+ penalties: false,
15422
+ logprobs: false
15423
+ },
15424
+ maxTokensParam: "max_completion_tokens",
15425
+ chatTools: {
15426
+ reasoning: "any"
15427
+ },
15428
+ source: "docs",
15429
+ note: "o1/o3/o4 family: low/medium/high, no sampling overrides."
15430
+ },
15431
+ {
15432
+ id: "openai-gpt-oss",
15433
+ family: "openai",
15434
+ match: "^gpt-?oss",
15435
+ reasoning: {
15436
+ style: "effort",
15437
+ efforts: [
15438
+ "low",
15439
+ "medium",
15440
+ "high"
15441
+ ],
15442
+ off: null
15443
+ },
15444
+ sampling: {
15445
+ temperature: "any",
15446
+ topP: true,
15447
+ topK: true,
15448
+ penalties: true,
15449
+ logprobs: true
15450
+ },
15451
+ maxTokensParam: "max_tokens",
15452
+ chatTools: {
15453
+ reasoning: "any"
15454
+ },
15455
+ source: "docs",
15456
+ note: "Open-weight gpt-oss: low/medium/high; sampling and max_tokens behave like an ordinary chat model."
15457
+ },
15458
+ {
15459
+ id: "openai-legacy-gpt",
15460
+ family: "openai",
15461
+ match: "^(?:gpt-?(?:[0-4]|35)(?![0-9])|text-|davinci|babbage)",
15462
+ reasoning: {
15463
+ style: "none",
15464
+ efforts: [],
15465
+ off: null
15466
+ },
15467
+ sampling: {
15468
+ temperature: "any",
15469
+ topP: true,
15470
+ topK: true,
15471
+ penalties: true,
15472
+ logprobs: true
15473
+ },
15474
+ maxTokensParam: "max_tokens",
15475
+ chatTools: {
15476
+ reasoning: "any"
15477
+ },
15478
+ source: "docs",
15479
+ note: "gpt-4o, gpt-4.1, gpt-3.5 and older: no reasoning, ordinary sampling."
15480
+ },
15481
+ {
15482
+ id: "openai-compatible-toggle",
15483
+ family: "openai",
15484
+ match: "^(?:deepseek-(?:r\\d|reasoner)|qwq|qwen-?3)",
15485
+ reasoning: {
15486
+ style: "toggle",
15487
+ efforts: [
15488
+ "none",
15489
+ "minimal",
15490
+ "low",
15491
+ "medium",
15492
+ "high",
15493
+ "xhigh",
15494
+ "max"
15495
+ ],
15496
+ off: "none"
15497
+ },
15498
+ sampling: {
15499
+ temperature: "any",
15500
+ topP: true,
15501
+ topK: true,
15502
+ penalties: true,
15503
+ logprobs: true
15504
+ },
15505
+ maxTokensParam: "max_tokens",
15506
+ chatTools: {
15507
+ reasoning: "any"
15508
+ },
15509
+ source: "docs",
15510
+ 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)."
15511
+ },
15512
+ {
15513
+ id: "openai-default",
15514
+ family: "openai",
15515
+ match: ".*",
15516
+ reasoning: {
15517
+ style: "effort",
15518
+ efforts: [
15519
+ "none",
15520
+ "minimal",
15521
+ "low",
15522
+ "medium",
15523
+ "high",
15524
+ "xhigh",
15525
+ "max"
15526
+ ],
15527
+ off: "none"
15528
+ },
15529
+ sampling: {
15530
+ temperature: "any",
15531
+ topP: true,
15532
+ topK: true,
15533
+ penalties: true,
15534
+ logprobs: true
15535
+ },
15536
+ maxTokensParam: "max_tokens",
15537
+ chatTools: {
15538
+ reasoning: "any"
15539
+ },
15540
+ source: "docs",
15541
+ note: "Permissive default for unknown OpenAI-wire models: pass what the caller asked; the provider learns from 400s."
15542
+ },
15543
+ {
15544
+ id: "claude-haiku-5",
15545
+ family: "anthropic",
15546
+ match: "^claude-(?:haiku-5|5(?:-\\d+)?-haiku)(?!\\d)",
15547
+ reasoning: {
15548
+ style: "adaptive",
15549
+ efforts: [
15550
+ "low",
15551
+ "medium",
15552
+ "high",
15553
+ "xhigh",
15554
+ "max"
15555
+ ],
15556
+ off: "disabled"
15557
+ },
15558
+ sampling: {
15559
+ temperature: "unsupported",
15560
+ topP: false,
15561
+ topK: false,
15562
+ penalties: false,
15563
+ logprobs: false
15564
+ },
15565
+ maxTokensParam: "max_tokens",
15566
+ chatTools: {
15567
+ reasoning: "any"
15568
+ },
15569
+ source: "verified-2026-10-14",
15570
+ 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."
15571
+ },
15572
+ {
15573
+ id: "claude-sonnet-5",
15574
+ family: "anthropic",
15575
+ match: "^claude-(?:sonnet-5|5(?:-\\d+)?-sonnet)(?!\\d)",
15576
+ reasoning: {
15577
+ style: "adaptive",
15578
+ efforts: [
15579
+ "low",
15580
+ "medium",
15581
+ "high",
15582
+ "xhigh",
15583
+ "max"
15584
+ ],
15585
+ off: "between_tools"
15586
+ },
15587
+ sampling: {
15588
+ temperature: "unsupported",
15589
+ topP: false,
15590
+ topK: false,
15591
+ penalties: false,
15592
+ logprobs: false
15593
+ },
15594
+ maxTokensParam: "max_tokens",
15595
+ chatTools: {
15596
+ reasoning: "any"
15597
+ },
15598
+ source: "verified-2026-10-14",
15599
+ note: "Claude Sonnet 5.x: adaptive + output_config.effort. thinking:{type:disabled} is rejected; off = thinking:{type:between_tools}. Sampling params are rejected."
15600
+ },
15601
+ {
15602
+ id: "claude-opus-5",
15603
+ family: "anthropic",
15604
+ match: "^claude-(?:opus-5|5(?:-\\d+)?-opus)(?!\\d)",
15605
+ reasoning: {
15606
+ style: "adaptive",
15607
+ efforts: [
15608
+ "low",
15609
+ "medium",
15610
+ "high",
15611
+ "xhigh",
15612
+ "max"
15613
+ ],
15614
+ off: null
15615
+ },
15616
+ sampling: {
15617
+ temperature: "unsupported",
15618
+ topP: false,
15619
+ topK: false,
15620
+ penalties: false,
15621
+ logprobs: false
15622
+ },
15623
+ maxTokensParam: "max_tokens",
15624
+ chatTools: {
15625
+ reasoning: "any"
15626
+ },
15627
+ source: "verified-2026-10-14",
15628
+ note: "Claude Opus 5.x: adaptive + output_config.effort; thinking cannot be turned off (none maps to the lowest effort). Sampling params are rejected."
15629
+ },
15630
+ {
15631
+ id: "claude-fable",
15632
+ family: "anthropic",
15633
+ match: "^claude-fable",
15634
+ reasoning: {
15635
+ style: "adaptive",
15636
+ efforts: [
15637
+ "low",
15638
+ "medium",
15639
+ "high",
15640
+ "xhigh",
15641
+ "max"
15642
+ ],
15643
+ off: null
15644
+ },
15645
+ sampling: {
15646
+ temperature: "unsupported",
15647
+ topP: false,
15648
+ topK: false,
15649
+ penalties: false,
15650
+ logprobs: false
15651
+ },
15652
+ maxTokensParam: "max_tokens",
15653
+ chatTools: {
15654
+ reasoning: "any"
15655
+ },
15656
+ source: "docs",
15657
+ note: "Claude Fable line: treated like the 5.x adaptive models."
15658
+ },
15659
+ {
15660
+ id: "claude-4-7",
15661
+ family: "anthropic",
15662
+ match: "^claude-(?:(?:opus|sonnet|haiku)-4[-.]7|4[-.]7-(?:opus|sonnet|haiku))(?!\\d)",
15663
+ reasoning: {
15664
+ style: "adaptive",
15665
+ efforts: [
15666
+ "low",
15667
+ "medium",
15668
+ "high",
15669
+ "xhigh",
15670
+ "max"
15671
+ ],
15672
+ off: "disabled"
15673
+ },
15674
+ sampling: {
15675
+ temperature: "thinking-requires-1",
15676
+ topP: true,
15677
+ topK: true,
15678
+ penalties: true,
15679
+ logprobs: true
15680
+ },
15681
+ maxTokensParam: "max_tokens",
15682
+ chatTools: {
15683
+ reasoning: "any"
15684
+ },
15685
+ source: "docs",
15686
+ note: "Claude 4.7: adaptive thinking, low/medium/high/xhigh/max."
15687
+ },
15688
+ {
15689
+ id: "claude-4-6",
15690
+ family: "anthropic",
15691
+ match: "^claude-(?:(?:opus|sonnet|haiku)-4[-.]6|4[-.]6-(?:opus|sonnet|haiku))(?!\\d)",
15692
+ reasoning: {
15693
+ style: "adaptive",
15694
+ efforts: [
15695
+ "low",
15696
+ "medium",
15697
+ "high",
15698
+ "max"
15699
+ ],
15700
+ off: "disabled"
15701
+ },
15702
+ sampling: {
15703
+ temperature: "thinking-requires-1",
15704
+ topP: true,
15705
+ topK: true,
15706
+ penalties: true,
15707
+ logprobs: true
15708
+ },
15709
+ maxTokensParam: "max_tokens",
15710
+ chatTools: {
15711
+ reasoning: "any"
15712
+ },
15713
+ source: "docs",
15714
+ note: "Claude 4.6: adaptive thinking, low/medium/high/max (no xhigh)."
15715
+ },
15716
+ {
15717
+ id: "claude-legacy-budget",
15718
+ family: "anthropic",
15719
+ match: "^claude-(?:3|4-|(?:opus|sonnet|haiku)-4)",
15720
+ reasoning: {
15721
+ style: "budget",
15722
+ efforts: [
15723
+ "none",
15724
+ "minimal",
15725
+ "low",
15726
+ "medium",
15727
+ "high",
15728
+ "xhigh",
15729
+ "max"
15730
+ ],
15731
+ off: null
15732
+ },
15733
+ sampling: {
15734
+ temperature: "thinking-requires-1",
15735
+ topP: true,
15736
+ topK: true,
15737
+ penalties: true,
15738
+ logprobs: true
15739
+ },
15740
+ maxTokensParam: "max_tokens",
15741
+ chatTools: {
15742
+ reasoning: "any"
15743
+ },
15744
+ source: "docs",
15745
+ 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."
15746
+ },
15747
+ {
15748
+ id: "anthropic-default",
15749
+ family: "anthropic",
15750
+ match: ".*",
15751
+ reasoning: {
15752
+ style: "budget",
15753
+ efforts: [
15754
+ "none",
15755
+ "minimal",
15756
+ "low",
15757
+ "medium",
15758
+ "high",
15759
+ "xhigh",
15760
+ "max"
15761
+ ],
15762
+ off: null
15763
+ },
15764
+ sampling: {
15765
+ temperature: "thinking-requires-1",
15766
+ topP: true,
15767
+ topK: true,
15768
+ penalties: true,
15769
+ logprobs: true
15770
+ },
15771
+ maxTokensParam: "max_tokens",
15772
+ chatTools: {
15773
+ reasoning: "any"
15774
+ },
15775
+ source: "docs",
15776
+ 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."
15777
+ },
15778
+ {
15779
+ id: "gemini-budget",
15780
+ family: "gemini",
15781
+ match: "^gemini",
15782
+ reasoning: {
15783
+ style: "budget",
15784
+ efforts: [
15785
+ "none",
15786
+ "minimal",
15787
+ "low",
15788
+ "medium",
15789
+ "high",
15790
+ "xhigh",
15791
+ "max"
15792
+ ],
15793
+ off: "none"
15794
+ },
15795
+ sampling: {
15796
+ temperature: "any",
15797
+ topP: true,
15798
+ topK: true,
15799
+ penalties: true,
15800
+ logprobs: true
15801
+ },
15802
+ maxTokensParam: "max_tokens",
15803
+ chatTools: {
15804
+ reasoning: "any"
15805
+ },
15806
+ source: "docs",
15807
+ note: "Gemini 2.5-style thinkingBudget; effort maps to a token budget, none = budget 0."
15808
+ },
15809
+ {
15810
+ id: "gemini-default",
15811
+ family: "gemini",
15812
+ match: ".*",
15813
+ reasoning: {
15814
+ style: "budget",
15815
+ efforts: [
15816
+ "none",
15817
+ "minimal",
15818
+ "low",
15819
+ "medium",
15820
+ "high",
15821
+ "xhigh",
15822
+ "max"
15823
+ ],
15824
+ off: "none"
15825
+ },
15826
+ sampling: {
15827
+ temperature: "any",
15828
+ topP: true,
15829
+ topK: true,
15830
+ penalties: true,
15831
+ logprobs: true
15832
+ },
15833
+ maxTokensParam: "max_tokens",
15834
+ chatTools: {
15835
+ reasoning: "any"
15836
+ },
15837
+ source: "docs",
15838
+ note: "Permissive default for unknown Gemini-wire models."
15839
+ },
15840
+ {
15841
+ id: "other-default",
15842
+ family: "other",
15843
+ match: ".*",
15844
+ reasoning: {
15845
+ style: "effort",
15846
+ efforts: [
15847
+ "none",
15848
+ "minimal",
15849
+ "low",
15850
+ "medium",
15851
+ "high",
15852
+ "xhigh",
15853
+ "max"
15854
+ ],
15855
+ off: "none"
15856
+ },
15857
+ sampling: {
15858
+ temperature: "any",
15859
+ topP: true,
15860
+ topK: true,
15861
+ penalties: true,
15862
+ logprobs: true
15863
+ },
15864
+ maxTokensParam: "max_tokens",
15865
+ chatTools: {
15866
+ reasoning: "any"
15867
+ },
15868
+ source: "docs",
15869
+ note: "Permissive default for model families the SDK has no rules for."
15870
+ }
15871
+ ]
15872
+ };
15873
+
15874
+ // src/models/rules.ts
15875
+ var MODEL_RULES = model_rules_default;
15876
+ var LADDER = MODEL_RULES.effortLadder;
15877
+ var compiled = /* @__PURE__ */ new Map();
15878
+ function regexFor(rule) {
15879
+ let re = compiled.get(rule.id);
15880
+ if (!re) {
15881
+ re = new RegExp(rule.match, "i");
15882
+ compiled.set(rule.id, re);
15883
+ }
15884
+ return re;
15885
+ }
15886
+ var GATEWAY_PREFIX = /^(?:(?:global|us|eu|apac|jp|au|ca|us-gov)\.)?(?:(?:openai|anthropic|google|meta|amazon|deepseek|qwen|mistral|cohere|ai21)\.)?/;
15887
+ function modelIdCandidates(model) {
15888
+ if (!model) return [];
15889
+ const lower = String(model).trim().toLowerCase();
15890
+ const last = lower.split("/").pop() ?? lower;
15891
+ const out = [];
15892
+ for (const id of [lower, last]) {
15893
+ for (const c of [id, id.replace(GATEWAY_PREFIX, "")]) {
15894
+ if (c && !out.includes(c)) out.push(c);
15895
+ }
15896
+ }
15897
+ return out;
15898
+ }
15899
+ var OPENAI_WIRE = /* @__PURE__ */ new Set(["openai", "azure", "openai-compatible", "together", "openrouter", "groq", "fireworks", "ollama", "vllm", "litellm", "mistral", "deepseek", "xai", "jev"]);
15900
+ function familiesFor(provider) {
15901
+ const p = (provider ?? "").toLowerCase();
15902
+ if (OPENAI_WIRE.has(p)) return ["openai"];
15903
+ if (p === "anthropic") return ["anthropic"];
15904
+ if (p === "bedrock") return ["anthropic", "openai", "other"];
15905
+ if (p === "vertex" || p === "gemini" || p === "google") return ["gemini", "anthropic"];
15906
+ return ["openai", "anthropic", "gemini", "other"];
15907
+ }
15908
+ function matchRule(family, ids, allowDefault) {
15909
+ for (const rule of MODEL_RULES.rules) {
15910
+ if (rule.family !== family) continue;
15911
+ if (rule.match === ".*") {
15912
+ if (allowDefault) return rule;
15913
+ continue;
15914
+ }
15915
+ const re = regexFor(rule);
15916
+ if (ids.some((id) => re.test(id))) return rule;
15917
+ }
15918
+ return void 0;
15919
+ }
15920
+ function mergeRulePatch(base, patch) {
15921
+ if (!patch) return base;
15922
+ const out = { ...base };
15923
+ if (patch.reasoning) out.reasoning = { ...base.reasoning ?? {}, ...patch.reasoning };
15924
+ if (patch.sampling) out.sampling = { ...base.sampling ?? {}, ...patch.sampling };
15925
+ if (patch.chatTools) out.chatTools = { ...base.chatTools ?? {}, ...patch.chatTools };
15926
+ if (patch.maxTokensParam) out.maxTokensParam = patch.maxTokensParam;
15927
+ if (patch.dropParams) out.dropParams = [.../* @__PURE__ */ new Set([...base.dropParams ?? [], ...patch.dropParams])];
15928
+ return out;
15929
+ }
15930
+ var LEARNED_MAX = 500;
15931
+ var learned = /* @__PURE__ */ new Map();
15932
+ function learnedKey(provider, model, scope) {
15933
+ return `${(provider ?? "").toLowerCase()}@${scope ?? ""}::${(model ?? "").trim().toLowerCase()}`;
15934
+ }
15935
+ function rememberModelRulePatch(provider, model, patch, scope) {
15936
+ const key = learnedKey(provider, model, scope);
15937
+ const merged = mergeRulePatch(learned.get(key)?.patch ?? {}, patch);
15938
+ learned.delete(key);
15939
+ learned.set(key, { provider: provider.toLowerCase(), model: model.trim().toLowerCase(), scope, patch: merged });
15940
+ if (learned.size > LEARNED_MAX) learned.delete(learned.keys().next().value);
15941
+ }
15942
+ function getLearnedModelRulePatch(provider, model, scope) {
15943
+ return learned.get(learnedKey(provider, model, scope))?.patch;
15944
+ }
15945
+ function listLearnedModelRules() {
15946
+ return [...learned.values()].map((e) => ({ ...e }));
15947
+ }
15948
+ function clearLearnedModelRules() {
15949
+ learned.clear();
15950
+ }
15951
+ function resolveModelRule(opts) {
15952
+ const families = familiesFor(opts.provider);
15953
+ const ids = modelIdCandidates(opts.model);
15954
+ let rule;
15955
+ for (const family of families) {
15956
+ rule = matchRule(family, ids, false);
15957
+ if (rule) break;
15958
+ }
15959
+ let isDefault = false;
15960
+ if (!rule) {
15961
+ isDefault = true;
15962
+ rule = matchRule(families[0], ids, true) ?? MODEL_RULES.rules[MODEL_RULES.rules.length - 1];
15963
+ }
15964
+ let effective = rule;
15965
+ const known = opts.model ? learned.get(learnedKey(opts.provider, opts.model, opts.scope))?.patch : void 0;
15966
+ if (known) effective = mergeRulePatch(effective, known);
15967
+ if (opts.patch) effective = mergeRulePatch(effective, opts.patch);
15968
+ return { ...effective, matchedRuleId: rule.id, isDefault, learned: !!known };
15969
+ }
15970
+ function mapReasoningEffort(rule, effort, endpoint = "chat") {
15971
+ const efforts = endpoint === "responses" && rule.reasoning.responsesEfforts || rule.reasoning.efforts;
15972
+ if (rule.reasoning.style === "none" || efforts.length === 0) return { mapped: true };
15973
+ const supported = LADDER.filter((e) => efforts.includes(e));
15974
+ if (supported.includes(effort)) return { effort, mapped: false };
15975
+ if (effort === "none") {
15976
+ const off = rule.reasoning.off;
15977
+ if (off && off !== "none") return { off, mapped: true };
15978
+ const lowest = supported.find((e) => e !== "none");
15979
+ return lowest ? { effort: lowest, mapped: true } : { mapped: true };
15980
+ }
15981
+ const at = LADDER.indexOf(effort);
15982
+ if (at < 0) return { mapped: true };
15983
+ for (let i = at - 1; i >= 1; i--) if (supported.includes(LADDER[i])) return { effort: LADDER[i], mapped: true };
15984
+ for (let i = at + 1; i < LADDER.length; i++) if (supported.includes(LADDER[i])) return { effort: LADDER[i], mapped: true };
15985
+ return supported.includes("none") ? { effort: "none", mapped: true } : { mapped: true };
15986
+ }
15987
+ function allowsSampling(rule, field, value, thinkingOn = false) {
15988
+ const s = rule.sampling;
15989
+ switch (field) {
15990
+ case "temperature":
15991
+ switch (s.temperature) {
15992
+ case "any":
15993
+ return true;
15994
+ case "unsupported":
15995
+ return false;
15996
+ // The default is what the server applies anyway, so it is never sent.
15997
+ case "default-only":
15998
+ return false;
15999
+ case "thinking-requires-1":
16000
+ return !thinkingOn || value === 1;
16001
+ }
16002
+ return true;
16003
+ // Anthropic's thinking restriction covers top_p / top_k as well as temperature.
16004
+ case "topP":
16005
+ return s.topP && !(thinkingOn && s.temperature === "thinking-requires-1");
16006
+ case "topK":
16007
+ return s.topK && !(thinkingOn && s.temperature === "thinking-requires-1");
16008
+ case "presencePenalty":
16009
+ case "frequencyPenalty":
16010
+ return s.penalties;
16011
+ case "logprobs":
16012
+ return s.logprobs;
16013
+ }
16014
+ }
16015
+ function applyDropParams(body, rule) {
16016
+ for (const p of rule.dropParams ?? []) {
16017
+ const dot = p.indexOf(".");
16018
+ if (dot < 0) delete body[p];
16019
+ else if (body[p.slice(0, dot)] && typeof body[p.slice(0, dot)] === "object") delete body[p.slice(0, dot)][p.slice(dot + 1)];
16020
+ }
16021
+ }
16022
+ function effortBudget(effort, table = "anthropic") {
16023
+ if (effort === "none") return 0;
16024
+ return (table === "gemini" ? MODEL_RULES.geminiBudgets : MODEL_RULES.budgets)[effort] ?? 0;
16025
+ }
16026
+
15249
16027
  // src/providers/utils/reasoning.ts
15250
16028
  var ANTHROPIC_EFFORT_BUDGET = {
15251
16029
  // 0 = off. `applyAnthropicReasoning` bails on a falsy budget and emits no
15252
16030
  // thinking block, which on Anthropic IS off — thinking there is opt-in.
15253
16031
  none: 0,
15254
- minimal: 1024,
15255
- low: 2048,
15256
- medium: 8192,
15257
- high: 16384
16032
+ ...MODEL_RULES.budgets
15258
16033
  };
15259
16034
  var GEMINI_EFFORT_BUDGET = {
15260
16035
  // 0 is Gemini's own documented spelling for "do not think", and unlike
15261
16036
  // Anthropic it has to be SENT — hence `applyGeminiReasoning` testing for null
15262
16037
  // rather than falsiness.
15263
16038
  none: 0,
15264
- minimal: 512,
15265
- low: 1024,
15266
- medium: 4096,
15267
- high: 12e3
16039
+ ...MODEL_RULES.geminiBudgets
15268
16040
  };
15269
16041
  var THINKING_OUTPUT_RESERVE = 1024;
15270
16042
  var MIN_THINKING_BUDGET = 1024;
15271
16043
  var THINKING_MIN_MAX_TOKENS = 4096;
15272
- function applyOpenAIReasoning(body, reasoning, mode = "legacy_effort") {
16044
+ function applyOpenAIReasoning(body, reasoning, mode = "legacy_effort", model, rule) {
15273
16045
  if (!reasoning) return;
15274
- const effort = normalizeEffort(reasoning.effort);
16046
+ const requested = normalizeEffort(reasoning.effort);
16047
+ const r = rule ?? resolveModelRule({ provider: "openai", model: model ?? body.model });
16048
+ const effort = requested && mapReasoningEffort(r, requested, mode === "responses" ? "responses" : "chat").effort;
15275
16049
  if (mode === "responses") {
15276
16050
  const obj = {};
15277
16051
  if (effort) obj.effort = effort;
@@ -15285,48 +16059,54 @@ function applyOpenAIReasoning(body, reasoning, mode = "legacy_effort") {
15285
16059
  }
15286
16060
  function supportsAdaptiveThinking(model) {
15287
16061
  if (typeof model !== "string") return false;
15288
- const id = model.toLowerCase();
15289
- const at = id.indexOf("claude-");
15290
- if (at < 0) return false;
15291
- for (const tok of id.slice(at + 7).split("-")) {
15292
- if (tok === "fable") return true;
15293
- const m = /^(\d+)(?:@|$)/.exec(tok);
15294
- if (m) {
15295
- if (m[1].length <= 2) return Number(m[1]) >= 5;
15296
- return false;
15297
- }
15298
- }
15299
- return false;
16062
+ return resolveModelRule({ provider: "anthropic", model }).reasoning.style === "adaptive";
15300
16063
  }
15301
- function resolveThinkingForm(model, mode) {
16064
+ function resolveThinkingForm(model, mode, rule) {
15302
16065
  if (mode === "adaptive" || mode === "budget") return mode;
16066
+ if (rule) return rule.reasoning.style === "adaptive" ? "adaptive" : "budget";
15303
16067
  return supportsAdaptiveThinking(model) ? "adaptive" : "budget";
15304
16068
  }
15305
- function applyAdaptiveThinking(_body, reasoning, setThinking, setOutputConfig) {
15306
- const requested = normalizeEffort(reasoning.effort);
15307
- if (requested === "none") return false;
15308
- let effort;
15309
- if (requested) effort = requested === "minimal" ? "low" : requested;
15310
- else if (typeof reasoning.budgetTokens === "number" && reasoning.budgetTokens > 0) {
15311
- effort = reasoning.budgetTokens <= ANTHROPIC_EFFORT_BUDGET.low ? "low" : reasoning.budgetTokens <= ANTHROPIC_EFFORT_BUDGET.medium ? "medium" : "high";
16069
+ function enforceAnthropicSampling(target, rule, thinkingOn, bedrock = false) {
16070
+ const fields = bedrock ? [["temperature", "temperature"], ["topP", "topP"]] : [["temperature", "temperature"], ["top_p", "topP"], ["top_k", "topK"]];
16071
+ for (const [key, field] of fields) {
16072
+ if (key in target && !allowsSampling(rule, field, target[key], thinkingOn)) delete target[key];
16073
+ }
16074
+ }
16075
+ function applyAdaptiveThinking(reasoning, rule, setThinking, setOutputConfig) {
16076
+ let requested = normalizeEffort(reasoning.effort);
16077
+ if (!requested && typeof reasoning.budgetTokens === "number" && reasoning.budgetTokens > 0) {
16078
+ requested = reasoning.budgetTokens <= ANTHROPIC_EFFORT_BUDGET.low ? "low" : reasoning.budgetTokens <= ANTHROPIC_EFFORT_BUDGET.medium ? "medium" : "high";
15312
16079
  }
15313
- if (!effort) return false;
16080
+ if (!requested) return false;
16081
+ const mapped = mapReasoningEffort(rule, requested);
16082
+ if (mapped.off) {
16083
+ setThinking({ type: mapped.off });
16084
+ return false;
16085
+ }
16086
+ if (!mapped.effort || mapped.effort === "none") return false;
15314
16087
  const thinking = { type: "adaptive" };
15315
16088
  if (reasoning.includeThoughts !== false) thinking.display = "summarized";
15316
16089
  if (reasoning.providerExtras) Object.assign(thinking, reasoning.providerExtras);
15317
- setThinking({ thinking });
15318
- setOutputConfig({ effort });
16090
+ setThinking(thinking);
16091
+ setOutputConfig({ effort: mapped.effort });
15319
16092
  return true;
15320
16093
  }
15321
16094
  function applyAnthropicReasoning(body, reasoning, opts) {
15322
- if (!reasoning) return;
15323
- if (resolveThinkingForm(opts?.model ?? body.model, opts?.mode) === "adaptive") {
15324
- const on = applyAdaptiveThinking(body, reasoning, (extra) => body.thinking = extra.thinking, (o) => body.output_config = { ...body.output_config ?? {}, ...o });
15325
- if (on) stripSamplingParams(body, ["temperature", "top_p", "top_k"]);
16095
+ const rule = opts?.rule ?? resolveModelRule({ provider: "anthropic", model: opts?.model ?? body.model });
16096
+ if (!reasoning) {
16097
+ enforceAnthropicSampling(body, rule, false);
16098
+ return;
16099
+ }
16100
+ if (resolveThinkingForm(opts?.model ?? body.model, opts?.mode, rule) === "adaptive") {
16101
+ const on = applyAdaptiveThinking(reasoning, rule, (t) => body.thinking = t, (o) => body.output_config = { ...body.output_config ?? {}, ...o });
16102
+ enforceAnthropicSampling(body, rule, on);
16103
+ return;
16104
+ }
16105
+ let budget = resolveBudget(reasoning, ANTHROPIC_EFFORT_BUDGET, rule);
16106
+ if (!budget) {
16107
+ enforceAnthropicSampling(body, rule, false);
15326
16108
  return;
15327
16109
  }
15328
- let budget = resolveBudget(reasoning, ANTHROPIC_EFFORT_BUDGET);
15329
- if (!budget) return;
15330
16110
  const currentMax = typeof body.max_tokens === "number" ? body.max_tokens : 0;
15331
16111
  const requiredMax = Math.max(THINKING_MIN_MAX_TOKENS, budget + THINKING_OUTPUT_RESERVE);
15332
16112
  if (currentMax < requiredMax) {
@@ -15336,18 +16116,25 @@ function applyAnthropicReasoning(body, reasoning, opts) {
15336
16116
  const thinking = { type: "enabled", budget_tokens: budget };
15337
16117
  if (reasoning.providerExtras) Object.assign(thinking, reasoning.providerExtras);
15338
16118
  body.thinking = thinking;
15339
- stripSamplingParams(body, ["temperature", "top_p", "top_k"]);
16119
+ enforceAnthropicSampling(body, rule, true);
15340
16120
  }
15341
16121
  function applyBedrockReasoning(body, reasoning, opts) {
15342
- if (!reasoning) return;
15343
- if (resolveThinkingForm(opts?.model ?? body.modelId, opts?.mode) === "adaptive") {
16122
+ const rule = opts?.rule ?? resolveModelRule({ provider: "bedrock", model: opts?.model ?? body.modelId });
16123
+ if (!reasoning) {
16124
+ if (body.inferenceConfig) enforceAnthropicSampling(body.inferenceConfig, rule, false, true);
16125
+ return;
16126
+ }
16127
+ if (resolveThinkingForm(opts?.model ?? body.modelId, opts?.mode, rule) === "adaptive") {
15344
16128
  const fields = () => body.additionalModelRequestFields ?? (body.additionalModelRequestFields = {});
15345
- const on = applyAdaptiveThinking(body, reasoning, (extra2) => fields().thinking = extra2.thinking, (o) => fields().output_config = { ...fields().output_config ?? {}, ...o });
15346
- if (on && body.inferenceConfig) stripSamplingParams(body.inferenceConfig, ["temperature", "topP"]);
16129
+ const on = applyAdaptiveThinking(reasoning, rule, (t) => fields().thinking = t, (o) => fields().output_config = { ...fields().output_config ?? {}, ...o });
16130
+ if (body.inferenceConfig) enforceAnthropicSampling(body.inferenceConfig, rule, on, true);
16131
+ return;
16132
+ }
16133
+ let budget = resolveBudget(reasoning, ANTHROPIC_EFFORT_BUDGET, rule);
16134
+ if (!budget) {
16135
+ if (body.inferenceConfig) enforceAnthropicSampling(body.inferenceConfig, rule, false, true);
15347
16136
  return;
15348
16137
  }
15349
- let budget = resolveBudget(reasoning, ANTHROPIC_EFFORT_BUDGET);
15350
- if (!budget) return;
15351
16138
  const inference = body.inferenceConfig ?? (body.inferenceConfig = {});
15352
16139
  const currentMax = typeof inference.maxTokens === "number" ? inference.maxTokens : 0;
15353
16140
  const requiredMax = Math.max(THINKING_MIN_MAX_TOKENS, budget + THINKING_OUTPUT_RESERVE);
@@ -15359,7 +16146,7 @@ function applyBedrockReasoning(body, reasoning, opts) {
15359
16146
  const thinking = { type: "enabled", budget_tokens: budget };
15360
16147
  if (reasoning.providerExtras) Object.assign(thinking, reasoning.providerExtras);
15361
16148
  extra.thinking = thinking;
15362
- stripSamplingParams(inference, ["temperature", "topP"]);
16149
+ enforceAnthropicSampling(inference, rule, true, true);
15363
16150
  }
15364
16151
  function applyGeminiReasoning(generationConfig, reasoning) {
15365
16152
  if (!reasoning) return;
@@ -15371,11 +16158,6 @@ function applyGeminiReasoning(generationConfig, reasoning) {
15371
16158
  if (reasoning.providerExtras) Object.assign(thinkingConfig, reasoning.providerExtras);
15372
16159
  generationConfig.thinkingConfig = thinkingConfig;
15373
16160
  }
15374
- function stripSamplingParams(target, keys) {
15375
- for (const k of keys) {
15376
- if (k in target) delete target[k];
15377
- }
15378
- }
15379
16161
  function clampBudget(budget, maxTokens) {
15380
16162
  if (typeof maxTokens !== "number" || maxTokens <= 0) return budget;
15381
16163
  const ceiling = maxTokens - THINKING_OUTPUT_RESERVE;
@@ -15384,16 +16166,17 @@ function clampBudget(budget, maxTokens) {
15384
16166
  }
15385
16167
  function normalizeEffort(effort) {
15386
16168
  if (!effort) return void 0;
15387
- const allowed = ["none", "minimal", "low", "medium", "high"];
16169
+ const allowed = ["none", "minimal", "low", "medium", "high", "xhigh", "max"];
15388
16170
  return allowed.includes(effort) ? effort : void 0;
15389
16171
  }
15390
- function resolveBudget(reasoning, effortBudget) {
16172
+ function resolveBudget(reasoning, effortBudget2, rule) {
15391
16173
  const effort = normalizeEffort(reasoning.effort);
15392
16174
  if (effort === "none") return 0;
15393
16175
  if (typeof reasoning.budgetTokens === "number" && reasoning.budgetTokens > 0) {
15394
16176
  return Math.floor(reasoning.budgetTokens);
15395
16177
  }
15396
- if (effort && effortBudget[effort]) return effortBudget[effort];
16178
+ const mapped = effort && rule ? mapReasoningEffort(rule, effort).effort : effort;
16179
+ if (mapped && effortBudget2[mapped]) return effortBudget2[mapped];
15397
16180
  return void 0;
15398
16181
  }
15399
16182
 
@@ -15464,6 +16247,211 @@ function parseSSEBlock(block) {
15464
16247
  return { event, data: dataLines.join("\n"), id, retry };
15465
16248
  }
15466
16249
 
16250
+ // src/models/errors.ts
16251
+ var ModelRequestError = class extends ProviderError {
16252
+ constructor(init) {
16253
+ super(init.message, init.provider, init.status ?? 400, init.responseBody);
16254
+ this.status = init.status ?? 400;
16255
+ this.code = init.code;
16256
+ this.param = init.param;
16257
+ this.value = init.value;
16258
+ this.supportedValues = init.supportedValues;
16259
+ this.model = init.model;
16260
+ }
16261
+ };
16262
+
16263
+ // src/models/adjust.ts
16264
+ var MAX_ADJUSTMENTS = 3;
16265
+ var Q = "['\"`]";
16266
+ function errorMessage(text) {
16267
+ try {
16268
+ const j = JSON.parse(text);
16269
+ const e = j?.error ?? j;
16270
+ const message = typeof e?.message === "string" ? e.message : typeof j?.message === "string" ? j.message : text;
16271
+ return { message, param: typeof e?.param === "string" ? e.param : void 0, code: typeof e?.code === "string" ? e.code : void 0 };
16272
+ } catch {
16273
+ return { message: text };
16274
+ }
16275
+ }
16276
+ function quotedList(s) {
16277
+ const quoted = [...s.matchAll(new RegExp(`${Q}([^'"\`]+)${Q}`, "g"))].map((m) => m[1]);
16278
+ if (quoted.length > 0) return quoted;
16279
+ return s.split(/[,\s]+/).map((x) => x.replace(/[.\s]+$/, "")).filter(Boolean);
16280
+ }
16281
+ function parseModelError(text) {
16282
+ const { message, param: errParam } = errorMessage(String(text ?? ""));
16283
+ const m = message.toLowerCase();
16284
+ if (m.includes("function tools with reasoning_effort") && m.includes("not supported")) {
16285
+ return { kind: "chat_tools_effort", message };
16286
+ }
16287
+ if (m.includes("between_tools") && m.includes("thinking")) return { kind: "thinking_off_between_tools", message };
16288
+ if (m.includes("thinking.type.enabled") && m.includes("not supported")) return { kind: "thinking_enabled_unsupported", message };
16289
+ if (m.includes("thinking.type.adaptive") && m.includes("not supported")) return { kind: "thinking_adaptive_unsupported", message };
16290
+ if (m.includes("thinking.type.disabled") && m.includes("not supported")) return { kind: "thinking_disabled_unsupported", message };
16291
+ 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);
16292
+ if (tt) return { kind: "temperature_thinking", param: tt[1].toLowerCase(), message };
16293
+ const dep = new RegExp(`${Q}([\\w.]+)${Q}\\s+is deprecated for this model`, "i").exec(message);
16294
+ if (dep) return { kind: "unsupported_parameter", param: dep[1], message };
16295
+ const rename = new RegExp(`use ${Q}(max_completion_tokens|max_tokens)${Q} instead`, "i").exec(message);
16296
+ if (rename) return { kind: "max_tokens_rename", renameTo: rename[1].toLowerCase(), param: rename[1].toLowerCase() === "max_tokens" ? "max_completion_tokens" : "max_tokens", message };
16297
+ const val = new RegExp(`unsupported value:?\\s*${Q}?([\\w.]+)${Q}?\\s+does not support\\s+(${Q}[^'"\`]*${Q}|[^\\s]+)`, "i").exec(message);
16298
+ if (val) {
16299
+ const param = val[1];
16300
+ const value = val[2].replace(/^['"`]|['"`]$/g, "");
16301
+ if (m.includes("only the default") && m.includes("value is supported")) return { kind: "default_only", param, value, message };
16302
+ const sup = /supported values? (?:are|is):?\s*([^\n]*)/i.exec(message);
16303
+ return { kind: "unsupported_value", param, value, supportedValues: sup ? quotedList(sup[1]) : void 0, message };
16304
+ }
16305
+ if (m.includes("only the default") && m.includes("value is supported")) {
16306
+ return { kind: "default_only", param: errParam ?? "temperature", message };
16307
+ }
16308
+ const prm = new RegExp(`unsupported parameter:?\\s*${Q}?([\\w.]+)${Q}?`, "i").exec(message);
16309
+ if (prm) return { kind: "unsupported_parameter", param: prm[1], message };
16310
+ return void 0;
16311
+ }
16312
+ var normParam = (p) => p.toLowerCase().replace(/[-\s]/g, "_");
16313
+ var LADDER2 = new Set(MODEL_RULES.effortLadder);
16314
+ function patchFromParsedError(parsed, endpoint = "chat") {
16315
+ const param = parsed.param ? normParam(parsed.param) : "";
16316
+ switch (parsed.kind) {
16317
+ case "chat_tools_effort":
16318
+ return { patch: { chatTools: { reasoning: "force-none" } }, adjustment: "chat-tools:force-effort-none" };
16319
+ case "max_tokens_rename":
16320
+ return { patch: { maxTokensParam: parsed.renameTo }, adjustment: `${parsed.param}->${parsed.renameTo}` };
16321
+ case "thinking_enabled_unsupported":
16322
+ return { patch: { reasoning: { style: "adaptive" } }, adjustment: "thinking:adaptive" };
16323
+ case "thinking_adaptive_unsupported":
16324
+ return { patch: { reasoning: { style: "budget" } }, adjustment: "thinking:budget" };
16325
+ case "thinking_off_between_tools":
16326
+ return { patch: { reasoning: { off: "between_tools" } }, adjustment: "thinking-off:between_tools" };
16327
+ case "thinking_disabled_unsupported":
16328
+ return { patch: { reasoning: { off: null } }, adjustment: "thinking-off:none" };
16329
+ case "temperature_thinking":
16330
+ return { patch: { sampling: { temperature: "unsupported" } }, adjustment: "drop:temperature" };
16331
+ case "default_only":
16332
+ if (param === "temperature") return { patch: { sampling: { temperature: "default-only" } }, adjustment: "temperature:default-only" };
16333
+ return { patch: { dropParams: [parsed.param ?? param] }, adjustment: `drop:${parsed.param ?? param}` };
16334
+ case "unsupported_value": {
16335
+ if (/^(reasoning_effort|reasoning\.effort|effort|output_config\.effort)$/.test(param)) {
16336
+ const list = (parsed.supportedValues ?? []).map((v) => v.toLowerCase()).filter((v) => LADDER2.has(v));
16337
+ if (list.length === 0) return void 0;
16338
+ const reasoning = endpoint === "responses" ? { responsesEfforts: list } : { efforts: list };
16339
+ return { patch: { reasoning }, adjustment: `efforts:${list.join("|")}` };
16340
+ }
16341
+ return paramDropPatch(param, parsed);
16342
+ }
16343
+ case "unsupported_parameter":
16344
+ return paramDropPatch(param, parsed);
16345
+ }
16346
+ }
16347
+ function paramDropPatch(param, parsed) {
16348
+ if (!param) return void 0;
16349
+ const label = `drop:${parsed.param ?? param}`;
16350
+ switch (param) {
16351
+ case "temperature":
16352
+ return { patch: { sampling: { temperature: "unsupported" } }, adjustment: label };
16353
+ case "top_p":
16354
+ return { patch: { sampling: { topP: false } }, adjustment: label };
16355
+ case "top_k":
16356
+ return { patch: { sampling: { topK: false } }, adjustment: label };
16357
+ case "presence_penalty":
16358
+ case "frequency_penalty":
16359
+ return { patch: { sampling: { penalties: false } }, adjustment: label };
16360
+ case "logprobs":
16361
+ case "top_logprobs":
16362
+ return { patch: { sampling: { logprobs: false } }, adjustment: label };
16363
+ case "max_tokens":
16364
+ return { patch: { maxTokensParam: "max_completion_tokens" }, adjustment: "max_tokens->max_completion_tokens" };
16365
+ case "max_completion_tokens":
16366
+ return { patch: { maxTokensParam: "max_tokens" }, adjustment: "max_completion_tokens->max_tokens" };
16367
+ case "reasoning_effort":
16368
+ case "reasoning.effort":
16369
+ case "reasoning":
16370
+ return { patch: { reasoning: { style: "none", efforts: [], responsesEfforts: [] }, dropParams: [param] }, adjustment: label };
16371
+ default:
16372
+ return { patch: { dropParams: [parsed.param ?? param] }, adjustment: label };
16373
+ }
16374
+ }
16375
+ function codeFor(parsed) {
16376
+ if (!parsed) return "model_request_invalid";
16377
+ if (parsed.kind === "unsupported_value" || parsed.kind === "default_only") return "unsupported_value";
16378
+ if (parsed.kind === "unsupported_parameter" || parsed.kind === "max_tokens_rename" || parsed.kind === "temperature_thinking") return "unsupported_parameter";
16379
+ return "model_request_invalid";
16380
+ }
16381
+ function toModelRequestError(err, parsed, provider, model) {
16382
+ return new ModelRequestError({
16383
+ status: err.statusCode ?? 400,
16384
+ code: codeFor(parsed),
16385
+ param: parsed?.param,
16386
+ value: parsed?.value,
16387
+ supportedValues: parsed?.supportedValues,
16388
+ provider: err.provider || provider,
16389
+ model,
16390
+ message: err.message,
16391
+ responseBody: err.responseBody
16392
+ });
16393
+ }
16394
+ var SameRequest = class extends Error {
16395
+ };
16396
+ function withoutCallerParams(step, callerParams) {
16397
+ const drops = step.patch.dropParams;
16398
+ if (!callerParams?.length || !drops) return step;
16399
+ const mine = (p) => callerParams.includes(p.split(".")[0]);
16400
+ if (!drops.some(mine)) return step;
16401
+ const { dropParams: _ignored, ...rest } = step.patch;
16402
+ const kept = drops.filter((p) => !mine(p));
16403
+ const patch = kept.length ? { ...rest, dropParams: kept } : rest;
16404
+ return Object.keys(patch).length ? { ...step, patch } : void 0;
16405
+ }
16406
+ async function runWithModelAdjustments(opts) {
16407
+ let overlay = {};
16408
+ const steps = [];
16409
+ let previous;
16410
+ let lastError;
16411
+ let lastParsed;
16412
+ for (; ; ) {
16413
+ const guard = (body) => {
16414
+ let json;
16415
+ try {
16416
+ json = JSON.stringify(body);
16417
+ } catch {
16418
+ return;
16419
+ }
16420
+ if (previous !== void 0 && json === previous) throw new SameRequest();
16421
+ previous = json;
16422
+ };
16423
+ try {
16424
+ const result = await opts.run(overlay, guard);
16425
+ for (const step of steps) {
16426
+ const s = withoutCallerParams(step, opts.callerParams);
16427
+ if (!s) continue;
16428
+ rememberModelRulePatch(opts.provider, opts.model, s.patch, opts.scope);
16429
+ if (opts.onLearned) {
16430
+ try {
16431
+ opts.onLearned({ provider: opts.provider, model: opts.model, adjustment: s.adjustment, patch: s.patch, reason: s.reason });
16432
+ } catch {
16433
+ }
16434
+ }
16435
+ }
16436
+ return result;
16437
+ } catch (err) {
16438
+ if (err instanceof SameRequest) throw toModelRequestError(lastError, lastParsed, opts.provider, opts.model);
16439
+ if (!(err instanceof ProviderError) || err instanceof ModelRequestError || err.statusCode !== 400) throw err;
16440
+ const parsed = parseModelError(String(err.responseBody ?? err.message));
16441
+ const fix = parsed ? patchFromParsedError(parsed, opts.endpoint) : void 0;
16442
+ lastError = err;
16443
+ lastParsed = parsed;
16444
+ if (!fix || steps.length >= MAX_ADJUSTMENTS) throw toModelRequestError(err, parsed, opts.provider, opts.model);
16445
+ overlay = mergeRulePatch(overlay, fix.patch);
16446
+ steps.push({ ...fix, reason: parsed.message });
16447
+ }
16448
+ }
16449
+ }
16450
+ function asModelRequestError(err, provider, model) {
16451
+ if (!(err instanceof ProviderError) || err instanceof ModelRequestError || err.statusCode !== 400) return err;
16452
+ return toModelRequestError(err, parseModelError(String(err.responseBody ?? err.message)), provider, model);
16453
+ }
16454
+
15467
16455
  // src/providers/utils/media.ts
15468
16456
  var EXTENSION_MIME = {
15469
16457
  jpg: "image/jpeg",
@@ -15764,8 +16752,7 @@ var OpenAIProvider = class extends BaseProvider {
15764
16752
  if (this.useResponsesApi(request)) {
15765
16753
  return this.completeResponses(request);
15766
16754
  }
15767
- const body = this.buildRequestBody(request, false);
15768
- const res = await this.doFetch(body, request.signal);
16755
+ const res = await this.fetchChat(request, false);
15769
16756
  const json = await res.json();
15770
16757
  return this.parseResponse(json);
15771
16758
  }
@@ -15789,8 +16776,7 @@ var OpenAIProvider = class extends BaseProvider {
15789
16776
  };
15790
16777
  return;
15791
16778
  }
15792
- const body = this.buildRequestBody(request, true);
15793
- const res = await this.doFetch(body, request.signal);
16779
+ const res = await this.fetchChat(request, true);
15794
16780
  if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
15795
16781
  let id = "";
15796
16782
  let model = "";
@@ -15894,7 +16880,43 @@ var OpenAIProvider = class extends BaseProvider {
15894
16880
  return res;
15895
16881
  }
15896
16882
  // ─── Internals ───────────────────────────────────────────────────────────
15897
- buildRequestBody(request, stream) {
16883
+ /** Chat Completions call that corrects itself from the provider's own 400s (see models/adjust.ts). */
16884
+ fetchChat(request, stream) {
16885
+ const model = request.model || this.defaultModel;
16886
+ return runWithModelAdjustments({
16887
+ provider: this.providerName,
16888
+ model,
16889
+ endpoint: "chat",
16890
+ scope: this.baseURL,
16891
+ callerParams: request.extra ? Object.keys(request.extra) : void 0,
16892
+ onLearned: this.onModelRuleLearned,
16893
+ run: (overlay, guard) => {
16894
+ const body = this.buildRequestBody(request, stream, overlay);
16895
+ guard(body);
16896
+ return this.doFetch(body, request.signal);
16897
+ }
16898
+ });
16899
+ }
16900
+ /** Same for the Responses API. */
16901
+ fetchResponses(request, adaptExtras, stream = false) {
16902
+ const model = request.model || this.defaultModel;
16903
+ return runWithModelAdjustments({
16904
+ provider: this.providerName,
16905
+ model,
16906
+ endpoint: "responses",
16907
+ scope: this.baseURL,
16908
+ callerParams: request.extra ? Object.keys(request.extra) : void 0,
16909
+ onLearned: this.onModelRuleLearned,
16910
+ run: (overlay, guard) => {
16911
+ const body = this.buildResponsesBody(request, overlay);
16912
+ if (adaptExtras) adaptChatExtrasForResponses(body, request.extra);
16913
+ if (stream) body.stream = true;
16914
+ guard(body);
16915
+ return this.responsesFetch(body, request.signal);
16916
+ }
16917
+ });
16918
+ }
16919
+ buildRequestBody(request, stream, overlay) {
15898
16920
  const body = {
15899
16921
  model: request.model || this.defaultModel,
15900
16922
  messages: request.messages.map((m) => this.toOpenAIMessage(m)),
@@ -15904,20 +16926,20 @@ var OpenAIProvider = class extends BaseProvider {
15904
16926
  body.stream_options = { include_usage: true };
15905
16927
  }
15906
16928
  const modelId = String(body.model);
15907
- const reasoningModel = isReasoningModel(modelId) && !/chat/i.test(modelId);
15908
- if (request.temperature != null && !reasoningModel) body.temperature = request.temperature;
16929
+ const rule = resolveModelRule({ provider: this.providerName, model: modelId, patch: overlay, scope: this.baseURL });
16930
+ if (request.temperature != null && allowsSampling(rule, "temperature", request.temperature)) body.temperature = request.temperature;
15909
16931
  if (request.maxTokens != null) {
15910
- const useCompletionTokens = this.maxTokensParam === "max_completion_tokens" || this.maxTokensParam === "auto" && isReasoningModel(modelId);
15911
- body[useCompletionTokens ? "max_completion_tokens" : "max_tokens"] = request.maxTokens;
16932
+ const param = this.maxTokensParam === "auto" ? rule.maxTokensParam : this.maxTokensParam;
16933
+ body[param] = request.maxTokens;
15912
16934
  }
15913
- if (request.topP != null && !reasoningModel) body.top_p = request.topP;
16935
+ if (request.topP != null && allowsSampling(rule, "topP")) body.top_p = request.topP;
15914
16936
  if (request.stop) body.stop = request.stop;
15915
- if (request.presencePenalty != null) body.presence_penalty = request.presencePenalty;
15916
- if (request.frequencyPenalty != null) body.frequency_penalty = request.frequencyPenalty;
16937
+ if (request.presencePenalty != null && allowsSampling(rule, "presencePenalty")) body.presence_penalty = request.presencePenalty;
16938
+ if (request.frequencyPenalty != null && allowsSampling(rule, "frequencyPenalty")) body.frequency_penalty = request.frequencyPenalty;
15917
16939
  if (request.seed != null) body.seed = request.seed;
15918
16940
  if (request.n != null) body.n = request.n;
15919
- if (request.logprobs != null) body.logprobs = request.logprobs;
15920
- if (request.topLogprobs != null) body.top_logprobs = request.topLogprobs;
16941
+ if (request.logprobs != null && allowsSampling(rule, "logprobs")) body.logprobs = request.logprobs;
16942
+ if (request.topLogprobs != null && allowsSampling(rule, "logprobs")) body.top_logprobs = request.topLogprobs;
15921
16943
  if (request.tools?.length) {
15922
16944
  body.tools = request.tools.map((t) => this.toOpenAITool(t));
15923
16945
  if (request.parallelToolCalls != null) body.parallel_tool_calls = request.parallelToolCalls;
@@ -15946,14 +16968,17 @@ var OpenAIProvider = class extends BaseProvider {
15946
16968
  if (request.extra) {
15947
16969
  Object.assign(body, request.extra);
15948
16970
  }
15949
- applyOpenAIReasoning(body, request.reasoning, "legacy_effort");
16971
+ applyOpenAIReasoning(body, request.reasoning, "legacy_effort", modelId, rule);
16972
+ if (body.tools?.length && rule.chatTools.reasoning === "force-none" && rule.reasoning.style !== "none") {
16973
+ body.reasoning_effort = "none";
16974
+ }
16975
+ applyDropParams(body, rule);
15950
16976
  return body;
15951
16977
  }
15952
16978
  // ─── Responses API (reasoning models) ──────────────────────────────────────
15953
16979
  async completeResponses(request) {
15954
- const body = this.buildResponsesBody(request);
15955
- if (this.apiResponsesNative || this.isResponsesApiModel(request)) adaptChatExtrasForResponses(body, request.extra);
15956
- const res = await this.responsesFetch(body, request.signal);
16980
+ const adapt = this.apiResponsesNative || this.isResponsesApiModel(request);
16981
+ const res = await this.fetchResponses(request, adapt);
15957
16982
  const json = await res.json();
15958
16983
  return this.parseResponsesResponse(json, request.model || this.defaultModel);
15959
16984
  }
@@ -15966,10 +16991,7 @@ var OpenAIProvider = class extends BaseProvider {
15966
16991
  * reads it). */
15967
16992
  async *streamResponses(request) {
15968
16993
  const modelId = request.model || this.defaultModel;
15969
- const body = this.buildResponsesBody(request);
15970
- adaptChatExtrasForResponses(body, request.extra);
15971
- body.stream = true;
15972
- const res = await this.responsesFetch(body, request.signal);
16994
+ const res = await this.fetchResponses(request, true, true);
15973
16995
  if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
15974
16996
  let id = "";
15975
16997
  let model = modelId;
@@ -16058,13 +17080,14 @@ var OpenAIProvider = class extends BaseProvider {
16058
17080
  finishReason: final?.finishReason ?? (calls.size > 0 ? "tool_calls" : "stop")
16059
17081
  };
16060
17082
  }
16061
- buildResponsesBody(request) {
17083
+ buildResponsesBody(request, overlay) {
16062
17084
  const body = {
16063
17085
  model: request.model || this.defaultModel,
16064
17086
  input: request.messages.map((m) => this.toResponsesInput(m))
16065
17087
  };
16066
17088
  if (request.maxTokens != null) body.max_output_tokens = request.maxTokens;
16067
- if (request.topP != null) body.top_p = request.topP;
17089
+ const rule = resolveModelRule({ provider: this.providerName, model: String(body.model), patch: overlay, scope: this.baseURL });
17090
+ if (request.topP != null && allowsSampling(rule, "topP")) body.top_p = request.topP;
16068
17091
  if (request.tools?.length) {
16069
17092
  body.tools = request.tools.map((t) => ({
16070
17093
  type: "function",
@@ -16096,7 +17119,8 @@ var OpenAIProvider = class extends BaseProvider {
16096
17119
  }
16097
17120
  }
16098
17121
  if (request.extra) Object.assign(body, request.extra);
16099
- applyOpenAIReasoning(body, request.reasoning, "responses");
17122
+ applyOpenAIReasoning(body, request.reasoning, "responses", String(body.model), rule);
17123
+ applyDropParams(body, rule);
16100
17124
  return body;
16101
17125
  }
16102
17126
  /** Maps a unified message to a Responses API `input` item. */
@@ -16361,8 +17385,8 @@ function pickProviderFields(top, message, choice) {
16361
17385
  }
16362
17386
  function isReasoningModel(model) {
16363
17387
  if (!model) return false;
16364
- const m = model.toLowerCase();
16365
- return /(^|[/_-])o[0-9]/.test(m) || m.startsWith("o1") || m.startsWith("o3") || m.startsWith("o4") || m.includes("gpt-5") || m.includes("gpt5");
17388
+ const rule = resolveModelRule({ provider: "openai", model });
17389
+ return !rule.isDefault && rule.reasoning.style === "effort" && rule.sampling.temperature !== "any";
16366
17390
  }
16367
17391
  function adaptChatExtrasForResponses(body, extra) {
16368
17392
  const native = extra ?? {};
@@ -16478,12 +17502,6 @@ function normalizeExplicitThinking(body) {
16478
17502
  }
16479
17503
  for (const k of ["temperature", "top_p", "top_k"]) delete body[k];
16480
17504
  }
16481
- function thinkingFormRejected(text) {
16482
- const t = text.toLowerCase();
16483
- if (t.indexOf("thinking.type.enabled") >= 0 && t.indexOf("not supported") >= 0) return "enabled";
16484
- if (t.indexOf("thinking.type.adaptive") >= 0 && t.indexOf("not supported") >= 0 && t.indexOf("thinking.type.enabled") < 0) return "adaptive";
16485
- return void 0;
16486
- }
16487
17505
  var AnthropicProvider = class extends BaseProvider {
16488
17506
  constructor(config) {
16489
17507
  super();
@@ -16634,7 +17652,7 @@ var AnthropicProvider = class extends BaseProvider {
16634
17652
  }
16635
17653
  }
16636
17654
  // ─── Internals ───────────────────────────────────────────────────────────
16637
- buildRequestBody(request, stream, modeOverride, downgradeToolChoice = false) {
17655
+ buildRequestBody(request, stream, overlay, downgradeToolChoice = false) {
16638
17656
  const { system, messages } = this.splitSystemMessages(request.messages);
16639
17657
  const body = {
16640
17658
  model: request.model || this.defaultModel,
@@ -16649,6 +17667,7 @@ var AnthropicProvider = class extends BaseProvider {
16649
17667
  body.system = system;
16650
17668
  }
16651
17669
  }
17670
+ const rule = resolveModelRule({ provider: this.providerName, model: String(body.model), patch: overlay });
16652
17671
  if (request.temperature != null) body.temperature = request.temperature;
16653
17672
  if (request.topP != null) body.top_p = request.topP;
16654
17673
  if (request.stop) body.stop_sequences = request.stop;
@@ -16675,9 +17694,11 @@ var AnthropicProvider = class extends BaseProvider {
16675
17694
  const explicitThinking = request.extra && typeof request.extra === "object" && "thinking" in request.extra;
16676
17695
  if (explicitThinking) {
16677
17696
  normalizeExplicitThinking(body);
17697
+ enforceAnthropicSampling(body, rule, body.thinking?.type === "enabled" || body.thinking?.type === "adaptive");
16678
17698
  } else {
16679
- applyAnthropicReasoning(body, request.reasoning, { model: body.model, mode: modeOverride ?? this.thinkingMode });
17699
+ applyAnthropicReasoning(body, request.reasoning, { model: body.model, mode: this.thinkingMode, rule });
16680
17700
  }
17701
+ applyDropParams(body, rule);
16681
17702
  if (typeof body.max_tokens !== "number" || !(body.max_tokens > 0)) {
16682
17703
  body.max_tokens = DEFAULT_MAX_TOKENS;
16683
17704
  }
@@ -16813,31 +17834,28 @@ var AnthropicProvider = class extends BaseProvider {
16813
17834
  }
16814
17835
  /** Builds and sends the request; retries once with the other thinking form
16815
17836
  * when the upstream rejects the one we picked. */
16816
- async send(request, stream) {
16817
- let mode;
17837
+ send(request, stream) {
16818
17838
  let downgrade = false;
16819
- let flippedThinking = false;
16820
- for (; ; ) {
16821
- const body = this.buildRequestBody(request, stream, mode, downgrade);
16822
- try {
16823
- return await this.doFetch(body, request.signal);
16824
- } catch (err) {
16825
- if (!(err instanceof ProviderError) || err.statusCode !== 400) throw err;
16826
- const text = String(err.responseBody ?? err.message);
16827
- if (!downgrade && body.tool_choice && body.tool_choice.type !== "auto" && forcedToolChoiceRejected(text)) {
16828
- downgrade = true;
16829
- continue;
17839
+ return runWithModelAdjustments({
17840
+ provider: this.providerName,
17841
+ model: request.model || this.defaultModel,
17842
+ endpoint: "messages",
17843
+ callerParams: request.extra ? Object.keys(request.extra) : void 0,
17844
+ onLearned: this.onModelRuleLearned,
17845
+ run: async (overlay, guard) => {
17846
+ for (; ; ) {
17847
+ const body = this.buildRequestBody(request, stream, overlay, downgrade);
17848
+ guard(body);
17849
+ try {
17850
+ return await this.doFetch(body, request.signal);
17851
+ } catch (err) {
17852
+ const rejected = err instanceof ProviderError && err.statusCode === 400 && !downgrade && body.tool_choice && body.tool_choice.type !== "auto" && forcedToolChoiceRejected(String(err.responseBody ?? err.message));
17853
+ if (!rejected) throw err;
17854
+ downgrade = true;
17855
+ }
16830
17856
  }
16831
- const explicit = request.extra && typeof request.extra === "object" && "thinking" in request.extra;
16832
- if (flippedThinking || explicit || !request.reasoning) throw err;
16833
- const wrong = thinkingFormRejected(text);
16834
- if (!wrong) throw err;
16835
- const used = resolveThinkingForm(request.model ?? this.defaultModel, this.thinkingMode);
16836
- if (wrong === "enabled" && used !== "budget" || wrong === "adaptive" && used !== "adaptive") throw err;
16837
- mode = wrong === "enabled" ? "adaptive" : "budget";
16838
- flippedThinking = true;
16839
17857
  }
16840
- }
17858
+ });
16841
17859
  }
16842
17860
  async doFetch(body, signal) {
16843
17861
  const url = `${this.baseURL}/v1/messages`;
@@ -16954,6 +17972,7 @@ var AzureProvider = class extends OpenAIProvider {
16954
17972
  retry: config.retry,
16955
17973
  fetch: config.fetch,
16956
17974
  timeoutMs: config.timeoutMs,
17975
+ onModelRuleLearned: config.onModelRuleLearned,
16957
17976
  maxTokensParam: config.maxTokensParam,
16958
17977
  api: config.api,
16959
17978
  responsesApi: config.responsesApi,
@@ -17082,6 +18101,7 @@ var OpenAICompatibleProvider = class extends OpenAIProvider {
17082
18101
  retry: config.retry,
17083
18102
  fetch: config.fetch,
17084
18103
  timeoutMs: config.timeoutMs,
18104
+ onModelRuleLearned: config.onModelRuleLearned,
17085
18105
  maxTokensParam: config.maxTokensParam,
17086
18106
  api: config.api,
17087
18107
  // Unlike OpenAI / Azure, "auto" on a compatible server means Chat
@@ -17437,7 +18457,7 @@ var BedrockProvider = class extends BaseProvider {
17437
18457
  return res;
17438
18458
  }
17439
18459
  // ─── Internals ───────────────────────────────────────────────────────────
17440
- buildConverseBody(request, downgradeToolChoice = false) {
18460
+ buildConverseBody(request, downgradeToolChoice = false, overlay) {
17441
18461
  const { system, messages } = this.splitSystemMessages(request.messages);
17442
18462
  const body = {
17443
18463
  messages: this.toBedrockMessages(messages)
@@ -17483,7 +18503,12 @@ var BedrockProvider = class extends BaseProvider {
17483
18503
  Object.assign(body, topLevel);
17484
18504
  if (Object.keys(fields).length > 0) body.additionalModelRequestFields = fields;
17485
18505
  }
17486
- applyBedrockReasoning(body, request.reasoning, { model: request.model || this.defaultModel, mode: this.thinkingMode });
18506
+ const rule = resolveModelRule({ provider: this.providerName, model: request.model || this.defaultModel, patch: overlay });
18507
+ applyBedrockReasoning(body, request.reasoning, { model: request.model || this.defaultModel, mode: this.thinkingMode, rule });
18508
+ if (body.inferenceConfig && rule.dropParams?.length) {
18509
+ for (const p of rule.dropParams) delete body.inferenceConfig[p === "top_p" ? "topP" : p === "max_tokens" ? "maxTokens" : p];
18510
+ }
18511
+ applyDropParams(body, rule);
17487
18512
  return body;
17488
18513
  }
17489
18514
  splitSystemMessages(messages) {
@@ -17608,16 +18633,29 @@ var BedrockProvider = class extends BaseProvider {
17608
18633
  }
17609
18634
  /** Sends the Converse call; retries once with toolChoice auto when the
17610
18635
  * model rejects forced tool use. */
17611
- async converseFetch(modelId, request, stream) {
17612
- const body = this.buildConverseBody(request);
17613
- try {
17614
- return await this.doFetch(modelId, body, request.signal, stream);
17615
- } catch (err) {
17616
- const tc = body.toolConfig?.toolChoice;
17617
- if (!(err instanceof ProviderError) || err.statusCode !== 400 || !tc || tc.auto) throw err;
17618
- if (!forcedToolChoiceRejected(String(err.responseBody ?? err.message))) throw err;
17619
- return this.doFetch(modelId, this.buildConverseBody(request, true), request.signal, stream);
17620
- }
18636
+ converseFetch(modelId, request, stream) {
18637
+ let downgrade = false;
18638
+ return runWithModelAdjustments({
18639
+ provider: this.providerName,
18640
+ model: modelId,
18641
+ endpoint: "converse",
18642
+ callerParams: request.extra ? Object.keys(request.extra) : void 0,
18643
+ onLearned: this.onModelRuleLearned,
18644
+ run: async (overlay, guard) => {
18645
+ for (; ; ) {
18646
+ const body = this.buildConverseBody(request, downgrade, overlay);
18647
+ guard(body);
18648
+ try {
18649
+ return await this.doFetch(modelId, body, request.signal, stream);
18650
+ } catch (err) {
18651
+ const tc = body.toolConfig?.toolChoice;
18652
+ const rejected = err instanceof ProviderError && err.statusCode === 400 && !downgrade && !!tc && !tc.auto && forcedToolChoiceRejected(String(err.responseBody ?? err.message));
18653
+ if (!rejected) throw err;
18654
+ downgrade = true;
18655
+ }
18656
+ }
18657
+ }
18658
+ });
17621
18659
  }
17622
18660
  async doFetch(modelId, body, signal, stream) {
17623
18661
  const host = `bedrock-runtime.${this.region}.amazonaws.com`;
@@ -17807,7 +18845,7 @@ var VertexProvider = class extends BaseProvider {
17807
18845
  const modelId = request.model || this.defaultModel;
17808
18846
  const body = this.buildGeminiBody(request);
17809
18847
  const url = this.buildUrl(modelId, false);
17810
- const res = await this.doFetch(url, body, request.signal);
18848
+ const res = await this.doFetch(url, body, request.signal, modelId);
17811
18849
  const json = await res.json();
17812
18850
  return this.parseResponse(json, modelId);
17813
18851
  }
@@ -17815,7 +18853,7 @@ var VertexProvider = class extends BaseProvider {
17815
18853
  const modelId = request.model || this.defaultModel;
17816
18854
  const body = this.buildGeminiBody(request);
17817
18855
  const url = this.buildUrl(modelId, true);
17818
- const res = await this.doFetch(url, body, request.signal);
18856
+ const res = await this.doFetch(url, body, request.signal, modelId);
17819
18857
  if (!res.body) throw new ProviderError("No response body for stream", this.providerName);
17820
18858
  const counter = { next: 0 };
17821
18859
  const contentType = res.headers.get("content-type") ?? "";
@@ -17895,7 +18933,7 @@ var VertexProvider = class extends BaseProvider {
17895
18933
  };
17896
18934
  if (Object.keys(parameters).length > 0) body.parameters = parameters;
17897
18935
  Object.assign(body, extraRest);
17898
- const res = await this.doFetch(url, body, request.signal);
18936
+ const res = await this.doFetch(url, body, request.signal, model);
17899
18937
  const json = await res.json();
17900
18938
  raw.push(json);
17901
18939
  for (const p of json.predictions ?? []) {
@@ -18118,7 +19156,7 @@ var VertexProvider = class extends BaseProvider {
18118
19156
  const tokenJson = await tokenRes.json();
18119
19157
  return tokenJson.access_token;
18120
19158
  }
18121
- async doFetch(url, body, signal) {
19159
+ async doFetch(url, body, signal, model = "") {
18122
19160
  const token = await this.getAccessToken();
18123
19161
  const bodyStr = JSON.stringify(body);
18124
19162
  const res = await this.doFetchWithRetry(
@@ -18136,6 +19174,20 @@ var VertexProvider = class extends BaseProvider {
18136
19174
  );
18137
19175
  if (!res.ok) {
18138
19176
  const text = await res.text().catch(() => "");
19177
+ if (res.status === 400) {
19178
+ const parsed = parseModelError(text);
19179
+ throw new ModelRequestError({
19180
+ status: 400,
19181
+ code: parsed?.kind === "unsupported_value" ? "unsupported_value" : parsed?.kind === "unsupported_parameter" ? "unsupported_parameter" : "model_request_invalid",
19182
+ param: parsed?.param,
19183
+ value: parsed?.value,
19184
+ supportedValues: parsed?.supportedValues,
19185
+ provider: this.providerName,
19186
+ model,
19187
+ message: `Vertex AI API error ${res.status}: ${text}`,
19188
+ responseBody: text
19189
+ });
19190
+ }
18139
19191
  throw new ProviderError(
18140
19192
  `Vertex AI API error ${res.status}: ${text}`,
18141
19193
  this.providerName,
@@ -18294,6 +19346,6 @@ function createProvider(config) {
18294
19346
  }
18295
19347
  }
18296
19348
 
18297
- export { ASK_USER_TOOL_NAME, AnthropicProvider, AzureProvider, BaseProvider, BedrockProvider, CCRStore, CONSOLE_HOOK_MAP, CONTEXT_PILOT_JSON_MARKER_KEY, CONTROL_PLANE_TOOL_NAMES, DEFAULT_MAX_TOOL_INPUT_FIELD_CHARS, DEFAULT_PROFILE_CONFIGS, DEFAULT_SKILL_POLICY, DEFAULT_SUBAGENT_POLICY, DEFAULT_SUBAGENT_TOOL_NAMES, DEFAULT_TOOL_INPUT_DIGEST_HEAD_CHARS, DELEGATION_TOOL_NAMES, DedupTracker, GuardrailPhase, HOOK_CONTRACT_VERSION, HOOK_NAMES, HookTimeoutError, InMemoryMemoryStore, JevProvider, NativeJsonSchemaStrategy, OpenAICompatibleProvider, OpenAIProvider, PREOPEN_TOOL_CALL_PREFIX, ProviderError, SMALL_TIER_SKILL_POLICY, StructuredOutputManager, TOOL_INPUT_DIGEST_KEY, ToolBasedStrategy, VertexProvider, agentVerdictRule, appendBoundTools, auditLog, azureContentSafety, bedrockGuardrail, budgetGuard, buildHandoffTools, buildResponseFormatSection, buildSkillHeaderBlock, buildSubagentCatalogBlock, buildSystemPrompt, buildToolDefinitionsSection, canOpenSkill, canSpawn, captureSnapshot, checkpointing, codePresenceRule, coerceToolArgs, cognipeerGuardrail, cognipeerSink, collectAttachments, collectToolRetentionDeclarations, composeToolSets, compressDiffOutput, compressJsonOutput, compressLogOutput, compressSearchOutput, compressTextOutput, compressToolOutput, contentPartToText, contentToString, conversationHistory, countApproxTokens, countMessagesTokens, createAgent, createAgentNode, createAskUserQuestionTool, createBindSkillToolsTool, createCodeGuardrail, createContextPilotRuntime, createContextSummarizeNode, createContextTools, createDelegateTool, createGetToolResponseTool, createGuardrail, createGuardrailPlugin, createJsonGuardrail, createManageTodoListAliasTool, createManageTodoTool, createOpenSkillTool, createParallelTool, createPluginHost, createProvider, createRegexGuardrail, createResolverNode, createSearchSkillsTool, createSkillRegistryRef, createSkillTools, createSmartAgent, createSpawnTool, createSubagentRegistryRef, createSubagentTools, createTool, createToolLimitFinalizeNode, createToolsNode, customCallbackRule, customGuardrail, customSink, dedupeToolsByName, defaultTokenCounter, defineHook, definePlugin, describeContentPart, detectLanguage, detectTextFormat, detectVolatileContent, digestToolInputArguments, digestToolInputValue, emptyUsage, evaluateGuardrails, extractLatestUserQuery, extractMessageText, fileCheckpointStore, fileSink, findSubagent, formatZodError, fromLangchainModel, fromLangchainTools, fromNativeProvider, generateSpanId, generateTraceId, getModelCapabilities, getNestedValue, getResolvedSmartConfig, getTokenCounter, hasMediaPart, hasToolResponseRecoveryReference, httpGuardrail, httpSink, inMemoryCheckpointStore, inMemoryConversationStore, isHookImplemented, isOpenAIHostedEndpoint, isSmartModel, isValidIban, isValidLuhn, isValidTckn, jsonSchemaRule, defaultBuildPayload as langfuseDefaultPayload, langfuseTracing, languageGuard, loadSkillsFromDisk, mapConsoleHookVerdict, mapTextParts, mcp, mediaKindOf, mediaPolicy, normalizeSmartAgentOptions, normalizeVerdicts, openAIModeration, otelTracing, otlpSink, outputGuard, parseApprovalDecision, parseSkillFrontmatter, pathSandbox, piiRedaction, pluginCapabilities, portkeyGateway, portkeyGuardrail, preopenSkills, preopenToolCallId, prepareStrictToolMenu, promptInjectionGuard, rateLimit, readMemoryFacts, redactText, regexGuardrail, regexRule, replaceTextContent, resolveAvailableSkills, resolveAvailableSubagents, resolveInputRetention, resolveMemoryStore, resolveReasoning, resolveStrategy, resolveSubagentTools, resolveSummarizationRetention, resolveToolApprovalState, resolveUserQuestionState, responseCache, restoreSnapshot, restoreToolCalls, runSmartAgentEvalHarness, scoreItemsByRelevance, searchSkills, seedChildMessages, selectTopIndicesInOrder, sessionMetrics, setTokenCounter, startStreamingSession, summarizeObject, supportsAdaptiveThinking, textFromContent, toMessageUsage, toStrictCompatible, toStrictToolSchema, tokenize, toolPolicy, traceSessionToOtlp, validateReasoningConfig, validateToolArgs, webhookApproval, withTools, withinDepth, writeSummaryFactsToMemory };
19349
+ export { ASK_USER_TOOL_NAME, AnthropicProvider, AzureProvider, BaseProvider, BedrockProvider, CCRStore, CONSOLE_HOOK_MAP, CONTEXT_PILOT_JSON_MARKER_KEY, CONTROL_PLANE_TOOL_NAMES, DEFAULT_MAX_TOOL_INPUT_FIELD_CHARS, DEFAULT_PROFILE_CONFIGS, DEFAULT_SKILL_POLICY, DEFAULT_SUBAGENT_POLICY, DEFAULT_SUBAGENT_TOOL_NAMES, DEFAULT_TOOL_INPUT_DIGEST_HEAD_CHARS, DELEGATION_TOOL_NAMES, DedupTracker, GuardrailPhase, HOOK_CONTRACT_VERSION, HOOK_NAMES, HookTimeoutError, InMemoryMemoryStore, JevProvider, MAX_ADJUSTMENTS, MODEL_RULES, ModelRequestError, NativeJsonSchemaStrategy, OpenAICompatibleProvider, OpenAIProvider, PREOPEN_TOOL_CALL_PREFIX, ProviderError, SMALL_TIER_SKILL_POLICY, StructuredOutputManager, TOOL_INPUT_DIGEST_KEY, ToolBasedStrategy, VertexProvider, agentVerdictRule, allowsSampling, appendBoundTools, applyDropParams, asModelRequestError, auditLog, azureContentSafety, bedrockGuardrail, budgetGuard, buildHandoffTools, buildResponseFormatSection, buildSkillHeaderBlock, buildSubagentCatalogBlock, buildSystemPrompt, buildToolDefinitionsSection, canOpenSkill, canSpawn, captureSnapshot, checkpointing, clearLearnedModelRules, codePresenceRule, coerceToolArgs, cognipeerGuardrail, cognipeerSink, collectAttachments, collectToolRetentionDeclarations, composeToolSets, compressDiffOutput, compressJsonOutput, compressLogOutput, compressSearchOutput, compressTextOutput, compressToolOutput, contentPartToText, contentToString, conversationHistory, countApproxTokens, countMessagesTokens, createAgent, createAgentNode, createAskUserQuestionTool, createBindSkillToolsTool, createCodeGuardrail, createContextPilotRuntime, createContextSummarizeNode, createContextTools, createDelegateTool, createGetToolResponseTool, createGuardrail, createGuardrailPlugin, createJsonGuardrail, createManageTodoListAliasTool, createManageTodoTool, createOpenSkillTool, createParallelTool, createPluginHost, createProvider, createRegexGuardrail, createResolverNode, createSearchSkillsTool, createSkillRegistryRef, createSkillTools, createSmartAgent, createSpawnTool, createSubagentRegistryRef, createSubagentTools, createTool, createToolLimitFinalizeNode, createToolsNode, customCallbackRule, customGuardrail, customSink, dedupeToolsByName, defaultTokenCounter, defineHook, definePlugin, describeContentPart, detectLanguage, detectTextFormat, detectVolatileContent, digestToolInputArguments, digestToolInputValue, effortBudget, emptyUsage, evaluateGuardrails, extractLatestUserQuery, extractMessageText, fileCheckpointStore, fileSink, findSubagent, formatZodError, fromLangchainModel, fromLangchainTools, fromNativeProvider, generateSpanId, generateTraceId, getLearnedModelRulePatch, getModelCapabilities, getNestedValue, getResolvedSmartConfig, getTokenCounter, hasMediaPart, hasToolResponseRecoveryReference, httpGuardrail, httpSink, inMemoryCheckpointStore, inMemoryConversationStore, isHookImplemented, isOpenAIHostedEndpoint, isSmartModel, isValidIban, isValidLuhn, isValidTckn, jsonSchemaRule, defaultBuildPayload as langfuseDefaultPayload, langfuseTracing, languageGuard, listLearnedModelRules, loadSkillsFromDisk, mapConsoleHookVerdict, mapReasoningEffort, mapTextParts, mcp, mediaKindOf, mediaPolicy, mergeRulePatch, modelIdCandidates, normalizeSmartAgentOptions, normalizeVerdicts, openAIModeration, otelTracing, otlpSink, outputGuard, parseApprovalDecision, parseModelError, parseSkillFrontmatter, pathSandbox, piiRedaction, pluginCapabilities, portkeyGateway, portkeyGuardrail, preopenSkills, preopenToolCallId, prepareStrictToolMenu, promptInjectionGuard, rateLimit, readMemoryFacts, redactText, regexGuardrail, regexRule, rememberModelRulePatch, replaceTextContent, resolveAvailableSkills, resolveAvailableSubagents, resolveInputRetention, resolveMemoryStore, resolveModelRule, resolveReasoning, resolveStrategy, resolveSubagentTools, resolveSummarizationRetention, resolveToolApprovalState, resolveUserQuestionState, responseCache, restoreSnapshot, restoreToolCalls, runSmartAgentEvalHarness, runWithModelAdjustments, scoreItemsByRelevance, searchSkills, seedChildMessages, selectTopIndicesInOrder, sessionMetrics, setTokenCounter, startStreamingSession, summarizeObject, supportsAdaptiveThinking, textFromContent, toMessageUsage, toStrictCompatible, toStrictToolSchema, tokenize, toolPolicy, traceSessionToOtlp, validateReasoningConfig, validateToolArgs, webhookApproval, withTools, withinDepth, writeSummaryFactsToMemory };
18298
19350
  //# sourceMappingURL=index.mjs.map
18299
19351
  //# sourceMappingURL=index.mjs.map