@combycode/llm-sdk 2.2.1 → 2.3.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.
Files changed (49) hide show
  1. package/CHANGELOG.md +206 -0
  2. package/dist/agent/loop-internals.d.ts +4 -0
  3. package/dist/agent/loop.d.ts +35 -0
  4. package/dist/{llm/providers → catalog}/builtin-tools.d.ts +1 -1
  5. package/dist/{plugins/model-catalog → catalog}/catalog.d.ts +34 -0
  6. package/dist/helpers/client-pool.d.ts +1 -1
  7. package/dist/helpers/client-resolver.d.ts +1 -1
  8. package/dist/helpers/engine.d.ts +12 -1
  9. package/dist/helpers/mcp.d.ts +6 -1
  10. package/dist/helpers/models.d.ts +1 -1
  11. package/dist/helpers/one-shot.d.ts +2 -2
  12. package/dist/helpers/select-model.d.ts +1 -1
  13. package/dist/index.browser.js +1438 -891
  14. package/dist/index.d.ts +4 -4
  15. package/dist/index.js +1438 -891
  16. package/dist/llm/client-config.d.ts +1 -1
  17. package/dist/llm/client-internal.d.ts +11 -0
  18. package/dist/llm/client.d.ts +4 -0
  19. package/dist/llm/providers/_shared/sse.d.ts +19 -0
  20. package/dist/llm/providers/google/files.d.ts +15 -0
  21. package/dist/llm/providers/google/media.d.ts +22 -4
  22. package/dist/llm/providers/google/realtime.d.ts +15 -2
  23. package/dist/llm/providers/openai/media.d.ts +10 -1
  24. package/dist/llm/providers/openai/realtime.d.ts +15 -2
  25. package/dist/llm/server-state.d.ts +1 -1
  26. package/dist/llm/types/options.d.ts +2 -2
  27. package/dist/llm/types/request.d.ts +50 -1
  28. package/dist/plugins/context-measurer/counter/count-api.d.ts +1 -1
  29. package/dist/plugins/context-measurer/counter/heuristic.d.ts +1 -1
  30. package/dist/plugins/context-measurer/counter/hybrid.d.ts +1 -1
  31. package/dist/plugins/context-measurer/measurer.d.ts +1 -1
  32. package/dist/plugins/cost-collector/collector.d.ts +1 -1
  33. package/dist/plugins/cost-collector/cost-collector-internal.d.ts +1 -1
  34. package/dist/plugins/cost-collector/cost-collector-types.d.ts +1 -1
  35. package/dist/plugins/files/registry.d.ts +1 -1
  36. package/dist/plugins/files/strategy.d.ts +1 -1
  37. package/dist/plugins/internal-tools/registry.d.ts +1 -1
  38. package/dist/plugins/internal-tools/runner/types.d.ts +1 -1
  39. package/dist/plugins/mcp/sampling.d.ts +23 -1
  40. package/dist/plugins/media/output.d.ts +1 -1
  41. package/dist/plugins/telemetry/telemetry.d.ts +2 -133
  42. package/dist/plugins/telemetry/types.d.ts +139 -0
  43. package/dist/util/hash.d.ts +8 -0
  44. package/dist/{plugins/media → util}/source-image.d.ts +1 -1
  45. package/dist/wire/inherit.d.ts +47 -0
  46. package/dist/wire/interpreter.d.ts +236 -0
  47. package/dist/wire/registry.d.ts +18 -0
  48. package/dist/wire/transforms.d.ts +22 -0
  49. package/package.json +3 -3
@@ -3325,8 +3325,8 @@ function strictSupport(schema, dialect) {
3325
3325
  return reason ? { ok: false, reason } : { ok: true };
3326
3326
  }
3327
3327
 
3328
- // src/llm/providers/anthropic/catalog.json
3329
- var catalog_default = {
3328
+ // src/catalog/data/anthropic.json
3329
+ var anthropic_default = {
3330
3330
  "anthropic/claude-opus-4": {
3331
3331
  providerModelName: "claude-opus-4-20250514",
3332
3332
  aliases: [
@@ -3383,7 +3383,12 @@ var catalog_default = {
3383
3383
  deprecation: {
3384
3384
  date: "2026-05-14",
3385
3385
  source: "litellm"
3386
- }
3386
+ },
3387
+ wire: {
3388
+ thinking: "budgeted",
3389
+ topK: false
3390
+ },
3391
+ wireSpec: "anthropic/messages@4.0"
3387
3392
  },
3388
3393
  "anthropic/claude-opus-4.1": {
3389
3394
  providerModelName: "claude-opus-4-1-20250805",
@@ -3441,7 +3446,12 @@ var catalog_default = {
3441
3446
  deprecation: {
3442
3447
  date: "2026-08-05",
3443
3448
  source: "litellm"
3444
- }
3449
+ },
3450
+ wire: {
3451
+ thinking: "budgeted",
3452
+ topK: true
3453
+ },
3454
+ wireSpec: "anthropic/messages@4.1"
3445
3455
  },
3446
3456
  "anthropic/claude-opus-4.5": {
3447
3457
  providerModelName: "claude-opus-4-5-20251101",
@@ -3495,7 +3505,12 @@ var catalog_default = {
3495
3505
  family: "claude-opus",
3496
3506
  version: "4.5",
3497
3507
  status: "legacy",
3498
- active: true
3508
+ active: true,
3509
+ wire: {
3510
+ thinking: "budgeted",
3511
+ topK: true
3512
+ },
3513
+ wireSpec: "anthropic/messages@4.1"
3499
3514
  },
3500
3515
  "anthropic/claude-opus-4.6": {
3501
3516
  providerModelName: "claude-opus-4-6",
@@ -3553,7 +3568,12 @@ var catalog_default = {
3553
3568
  family: "claude-opus",
3554
3569
  version: "4.6",
3555
3570
  status: "stable",
3556
- active: true
3571
+ active: true,
3572
+ wire: {
3573
+ thinking: "adaptive",
3574
+ topK: true
3575
+ },
3576
+ wireSpec: "anthropic/messages@4.6"
3557
3577
  },
3558
3578
  "anthropic/claude-opus-4.7": {
3559
3579
  providerModelName: "claude-opus-4-7",
@@ -3611,7 +3631,12 @@ var catalog_default = {
3611
3631
  family: "claude-opus",
3612
3632
  version: "4.7",
3613
3633
  status: "stable",
3614
- active: true
3634
+ active: true,
3635
+ wire: {
3636
+ thinking: "adaptive",
3637
+ topK: false
3638
+ },
3639
+ wireSpec: "anthropic/messages@4.7"
3615
3640
  },
3616
3641
  "anthropic/claude-opus-4.8": {
3617
3642
  providerModelName: "claude-opus-4-8",
@@ -3669,7 +3694,12 @@ var catalog_default = {
3669
3694
  family: "claude-opus",
3670
3695
  version: "4.8",
3671
3696
  status: "stable",
3672
- active: true
3697
+ active: true,
3698
+ wire: {
3699
+ thinking: "adaptive",
3700
+ topK: false
3701
+ },
3702
+ wireSpec: "anthropic/messages@4.7"
3673
3703
  },
3674
3704
  "anthropic/claude-sonnet-4": {
3675
3705
  providerModelName: "claude-sonnet-4-20250514",
@@ -3727,7 +3757,12 @@ var catalog_default = {
3727
3757
  deprecation: {
3728
3758
  date: "2026-05-14",
3729
3759
  source: "litellm"
3730
- }
3760
+ },
3761
+ wire: {
3762
+ thinking: "budgeted",
3763
+ topK: false
3764
+ },
3765
+ wireSpec: "anthropic/messages@4.0"
3731
3766
  },
3732
3767
  "anthropic/claude-sonnet-4.5": {
3733
3768
  providerModelName: "claude-sonnet-4-5-20250929",
@@ -3781,7 +3816,12 @@ var catalog_default = {
3781
3816
  family: "claude-sonnet",
3782
3817
  version: "4.5",
3783
3818
  status: "stable",
3784
- active: true
3819
+ active: true,
3820
+ wire: {
3821
+ thinking: "budgeted",
3822
+ topK: true
3823
+ },
3824
+ wireSpec: "anthropic/messages@4.1"
3785
3825
  },
3786
3826
  "anthropic/claude-sonnet-4.6": {
3787
3827
  providerModelName: "claude-sonnet-4-6",
@@ -3835,7 +3875,12 @@ var catalog_default = {
3835
3875
  family: "claude-sonnet",
3836
3876
  version: "4.6",
3837
3877
  status: "stable",
3838
- active: true
3878
+ active: true,
3879
+ wire: {
3880
+ thinking: "adaptive",
3881
+ topK: true
3882
+ },
3883
+ wireSpec: "anthropic/messages@4.6"
3839
3884
  },
3840
3885
  "anthropic/claude-haiku-4.5": {
3841
3886
  providerModelName: "claude-haiku-4-5-20251001",
@@ -3889,7 +3934,12 @@ var catalog_default = {
3889
3934
  family: "claude-haiku",
3890
3935
  version: "4.5",
3891
3936
  status: "stable",
3892
- active: true
3937
+ active: true,
3938
+ wire: {
3939
+ thinking: "budgeted",
3940
+ topK: true
3941
+ },
3942
+ wireSpec: "anthropic/messages@4.1"
3893
3943
  },
3894
3944
  "anthropic/claude-fable-5": {
3895
3945
  providerModelName: "claude-fable-5",
@@ -3943,7 +3993,12 @@ var catalog_default = {
3943
3993
  family: "claude-fable",
3944
3994
  version: "5",
3945
3995
  status: "stable",
3946
- active: true
3996
+ active: true,
3997
+ wire: {
3998
+ thinking: "adaptive",
3999
+ topK: false
4000
+ },
4001
+ wireSpec: "anthropic/messages@4.7"
3947
4002
  },
3948
4003
  "anthropic/claude-sonnet-5": {
3949
4004
  providerModelName: "claude-sonnet-5",
@@ -3997,7 +4052,12 @@ var catalog_default = {
3997
4052
  family: "claude-sonnet",
3998
4053
  version: "5",
3999
4054
  status: "stable",
4000
- active: true
4055
+ active: true,
4056
+ wire: {
4057
+ thinking: "adaptive",
4058
+ topK: false
4059
+ },
4060
+ wireSpec: "anthropic/messages@4.7"
4001
4061
  },
4002
4062
  "anthropic/claude-mythos-5": {
4003
4063
  providerModelName: "claude-mythos-5",
@@ -4048,7 +4108,12 @@ var catalog_default = {
4048
4108
  version: "5",
4049
4109
  status: "stable",
4050
4110
  active: false,
4051
- availability: "limited"
4111
+ availability: "limited",
4112
+ wire: {
4113
+ thinking: "adaptive",
4114
+ topK: false
4115
+ },
4116
+ wireSpec: "anthropic/messages@4.7"
4052
4117
  },
4053
4118
  "anthropic/claude-opus-5": {
4054
4119
  providerModelName: "claude-opus-5",
@@ -4106,12 +4171,17 @@ var catalog_default = {
4106
4171
  family: "claude-opus",
4107
4172
  version: "5",
4108
4173
  status: "stable",
4109
- active: true
4174
+ active: true,
4175
+ wire: {
4176
+ thinking: "adaptive",
4177
+ topK: false
4178
+ },
4179
+ wireSpec: "anthropic/messages@4.7"
4110
4180
  }
4111
4181
  };
4112
4182
 
4113
- // src/llm/providers/google/catalog.json
4114
- var catalog_default2 = {
4183
+ // src/catalog/data/google.json
4184
+ var google_default = {
4115
4185
  "google/gemini-2.5-pro": {
4116
4186
  providerModelName: "gemini-2.5-pro",
4117
4187
  aliases: [
@@ -4175,7 +4245,11 @@ var catalog_default2 = {
4175
4245
  family: "gemini-pro",
4176
4246
  version: "2.5",
4177
4247
  status: "stable",
4178
- active: true
4248
+ active: true,
4249
+ wire: {
4250
+ thinking: "budget"
4251
+ },
4252
+ wireSpec: "google/generate@2.5"
4179
4253
  },
4180
4254
  "google/gemini-3.1-pro": {
4181
4255
  providerModelName: "gemini-3.1-pro-preview",
@@ -4241,7 +4315,11 @@ var catalog_default2 = {
4241
4315
  family: "gemini-pro",
4242
4316
  version: "3.1",
4243
4317
  status: "preview",
4244
- active: true
4318
+ active: true,
4319
+ wire: {
4320
+ thinking: "level"
4321
+ },
4322
+ wireSpec: "google/generate@3"
4245
4323
  },
4246
4324
  "google/gemini-3.1-pro-customtools": {
4247
4325
  providerModelName: "gemini-3.1-pro-preview-customtools",
@@ -4289,7 +4367,11 @@ var catalog_default2 = {
4289
4367
  family: "gemini-pro",
4290
4368
  version: "3.1",
4291
4369
  status: "preview",
4292
- active: true
4370
+ active: true,
4371
+ wire: {
4372
+ thinking: "level"
4373
+ },
4374
+ wireSpec: "google/generate@3"
4293
4375
  },
4294
4376
  "google/gemini-2.5-flash": {
4295
4377
  providerModelName: "gemini-2.5-flash",
@@ -4358,7 +4440,11 @@ var catalog_default2 = {
4358
4440
  family: "gemini-flash",
4359
4441
  version: "2.5",
4360
4442
  status: "stable",
4361
- active: true
4443
+ active: true,
4444
+ wire: {
4445
+ thinking: "budget"
4446
+ },
4447
+ wireSpec: "google/generate@2.5"
4362
4448
  },
4363
4449
  "google/gemini-3-flash": {
4364
4450
  providerModelName: "gemini-3-flash-preview",
@@ -4427,7 +4513,11 @@ var catalog_default2 = {
4427
4513
  family: "gemini-flash",
4428
4514
  version: "3",
4429
4515
  status: "preview",
4430
- active: true
4516
+ active: true,
4517
+ wire: {
4518
+ thinking: "level"
4519
+ },
4520
+ wireSpec: "google/generate@3"
4431
4521
  },
4432
4522
  "google/gemini-3.5-flash": {
4433
4523
  providerModelName: "gemini-3.5-flash",
@@ -4492,7 +4582,11 @@ var catalog_default2 = {
4492
4582
  family: "gemini-flash",
4493
4583
  version: "3.5",
4494
4584
  status: "stable",
4495
- active: true
4585
+ active: true,
4586
+ wire: {
4587
+ thinking: "level"
4588
+ },
4589
+ wireSpec: "google/generate@3"
4496
4590
  },
4497
4591
  "google/gemini-2.5-flash-lite": {
4498
4592
  providerModelName: "gemini-2.5-flash-lite",
@@ -4561,7 +4655,11 @@ var catalog_default2 = {
4561
4655
  family: "gemini-flash-lite",
4562
4656
  version: "2.5",
4563
4657
  status: "stable",
4564
- active: true
4658
+ active: true,
4659
+ wire: {
4660
+ thinking: "budget"
4661
+ },
4662
+ wireSpec: "google/generate@2.5"
4565
4663
  },
4566
4664
  "google/gemini-3.1-flash-lite": {
4567
4665
  providerModelName: "gemini-3.1-flash-lite",
@@ -4631,7 +4729,11 @@ var catalog_default2 = {
4631
4729
  family: "gemini-flash-lite",
4632
4730
  version: "3.1",
4633
4731
  status: "stable",
4634
- active: true
4732
+ active: true,
4733
+ wire: {
4734
+ thinking: "level"
4735
+ },
4736
+ wireSpec: "google/generate@3"
4635
4737
  },
4636
4738
  "google/gemini-2.5-flash-image": {
4637
4739
  providerModelName: "gemini-2.5-flash-image",
@@ -5531,7 +5633,11 @@ var catalog_default2 = {
5531
5633
  family: "gemma",
5532
5634
  version: "4",
5533
5635
  status: "stable",
5534
- active: true
5636
+ active: true,
5637
+ wire: {
5638
+ thinking: "level"
5639
+ },
5640
+ wireSpec: "google/generate@3"
5535
5641
  },
5536
5642
  "google/gemma-4-31b": {
5537
5643
  providerModelName: "gemma-4-31b-it",
@@ -5578,7 +5684,11 @@ var catalog_default2 = {
5578
5684
  family: "gemma",
5579
5685
  version: "4",
5580
5686
  status: "stable",
5581
- active: true
5687
+ active: true,
5688
+ wire: {
5689
+ thinking: "level"
5690
+ },
5691
+ wireSpec: "google/generate@3"
5582
5692
  },
5583
5693
  "google/imagen-4": {
5584
5694
  providerModelName: "imagen-4.0-generate-001",
@@ -6637,7 +6747,11 @@ var catalog_default2 = {
6637
6747
  family: "gemini-flash",
6638
6748
  version: "3.6",
6639
6749
  status: "stable",
6640
- active: true
6750
+ active: true,
6751
+ wire: {
6752
+ thinking: "level"
6753
+ },
6754
+ wireSpec: "google/generate@3"
6641
6755
  },
6642
6756
  "google/gemini-3.5-flash-lite": {
6643
6757
  providerModelName: "gemini-3.5-flash-lite",
@@ -6703,12 +6817,16 @@ var catalog_default2 = {
6703
6817
  family: "gemini-flash-lite",
6704
6818
  version: "3.5",
6705
6819
  status: "stable",
6706
- active: true
6820
+ active: true,
6821
+ wire: {
6822
+ thinking: "level"
6823
+ },
6824
+ wireSpec: "google/generate@3"
6707
6825
  }
6708
6826
  };
6709
6827
 
6710
- // src/llm/providers/openai/catalog.json
6711
- var catalog_default3 = {
6828
+ // src/catalog/data/openai.json
6829
+ var openai_default = {
6712
6830
  "openai/gpt-3.5-turbo": {
6713
6831
  providerModelName: "gpt-3.5-turbo",
6714
6832
  aliases: [
@@ -6756,7 +6874,8 @@ var catalog_default3 = {
6756
6874
  family: "gpt",
6757
6875
  version: "3.5",
6758
6876
  status: "legacy",
6759
- active: true
6877
+ active: true,
6878
+ wireSpec: "openai/responses"
6760
6879
  },
6761
6880
  "openai/gpt-4": {
6762
6881
  providerModelName: "gpt-4",
@@ -6803,7 +6922,8 @@ var catalog_default3 = {
6803
6922
  family: "gpt",
6804
6923
  version: "4",
6805
6924
  status: "legacy",
6806
- active: true
6925
+ active: true,
6926
+ wireSpec: "openai/responses"
6807
6927
  },
6808
6928
  "openai/gpt-4-turbo": {
6809
6929
  providerModelName: "gpt-4-turbo",
@@ -6851,7 +6971,8 @@ var catalog_default3 = {
6851
6971
  family: "gpt",
6852
6972
  version: "4",
6853
6973
  status: "legacy",
6854
- active: true
6974
+ active: true,
6975
+ wireSpec: "openai/responses"
6855
6976
  },
6856
6977
  "openai/gpt-4.1": {
6857
6978
  providerModelName: "gpt-4.1",
@@ -6900,7 +7021,8 @@ var catalog_default3 = {
6900
7021
  family: "gpt",
6901
7022
  version: "4.1",
6902
7023
  status: "legacy",
6903
- active: true
7024
+ active: true,
7025
+ wireSpec: "openai/responses"
6904
7026
  },
6905
7027
  "openai/gpt-5": {
6906
7028
  providerModelName: "gpt-5",
@@ -6949,7 +7071,8 @@ var catalog_default3 = {
6949
7071
  family: "gpt",
6950
7072
  version: "5",
6951
7073
  status: "legacy",
6952
- active: true
7074
+ active: true,
7075
+ wireSpec: "openai/responses"
6953
7076
  },
6954
7077
  "openai/gpt-5-search": {
6955
7078
  providerModelName: "gpt-5-search-api",
@@ -7047,7 +7170,8 @@ var catalog_default3 = {
7047
7170
  family: "gpt",
7048
7171
  version: "5.1",
7049
7172
  status: "legacy",
7050
- active: true
7173
+ active: true,
7174
+ wireSpec: "openai/responses"
7051
7175
  },
7052
7176
  "openai/gpt-5.2": {
7053
7177
  providerModelName: "gpt-5.2",
@@ -7096,7 +7220,8 @@ var catalog_default3 = {
7096
7220
  family: "gpt",
7097
7221
  version: "5.2",
7098
7222
  status: "stable",
7099
- active: true
7223
+ active: true,
7224
+ wireSpec: "openai/responses"
7100
7225
  },
7101
7226
  "openai/gpt-5.4": {
7102
7227
  providerModelName: "gpt-5.4",
@@ -7162,7 +7287,8 @@ var catalog_default3 = {
7162
7287
  family: "gpt",
7163
7288
  version: "5.4",
7164
7289
  status: "stable",
7165
- active: true
7290
+ active: true,
7291
+ wireSpec: "openai/responses"
7166
7292
  },
7167
7293
  "openai/gpt-5.5": {
7168
7294
  providerModelName: "gpt-5.5",
@@ -7228,7 +7354,8 @@ var catalog_default3 = {
7228
7354
  family: "gpt",
7229
7355
  version: "5.5",
7230
7356
  status: "stable",
7231
- active: true
7357
+ active: true,
7358
+ wireSpec: "openai/responses"
7232
7359
  },
7233
7360
  "openai/gpt-5-chat": {
7234
7361
  providerModelName: "gpt-5-chat-latest",
@@ -7276,7 +7403,8 @@ var catalog_default3 = {
7276
7403
  family: "gpt-chat",
7277
7404
  version: "5",
7278
7405
  status: "legacy",
7279
- active: false
7406
+ active: false,
7407
+ wireSpec: "openai/responses"
7280
7408
  },
7281
7409
  "openai/gpt-5.1-chat": {
7282
7410
  providerModelName: "gpt-5.1-chat-latest",
@@ -7324,7 +7452,8 @@ var catalog_default3 = {
7324
7452
  family: "gpt-chat",
7325
7453
  version: "5.1",
7326
7454
  status: "legacy",
7327
- active: false
7455
+ active: false,
7456
+ wireSpec: "openai/responses"
7328
7457
  },
7329
7458
  "openai/gpt-5.2-chat": {
7330
7459
  providerModelName: "gpt-5.2-chat-latest",
@@ -7376,7 +7505,8 @@ var catalog_default3 = {
7376
7505
  deprecation: {
7377
7506
  shutdownDate: "2026-08-10",
7378
7507
  source: "openrouter"
7379
- }
7508
+ },
7509
+ wireSpec: "openai/responses"
7380
7510
  },
7381
7511
  "openai/gpt-5.3-chat": {
7382
7512
  providerModelName: "gpt-5.3-chat-latest",
@@ -7428,7 +7558,8 @@ var catalog_default3 = {
7428
7558
  deprecation: {
7429
7559
  shutdownDate: "2026-08-10",
7430
7560
  source: "openrouter"
7431
- }
7561
+ },
7562
+ wireSpec: "openai/responses"
7432
7563
  },
7433
7564
  "openai/gpt-5-codex": {
7434
7565
  providerModelName: "gpt-5-codex",
@@ -7766,7 +7897,8 @@ var catalog_default3 = {
7766
7897
  family: "gpt-mini",
7767
7898
  version: "4.1",
7768
7899
  status: "legacy",
7769
- active: true
7900
+ active: true,
7901
+ wireSpec: "openai/responses"
7770
7902
  },
7771
7903
  "openai/gpt-5-mini": {
7772
7904
  providerModelName: "gpt-5-mini",
@@ -7815,7 +7947,8 @@ var catalog_default3 = {
7815
7947
  family: "gpt-mini",
7816
7948
  version: "5",
7817
7949
  status: "legacy",
7818
- active: true
7950
+ active: true,
7951
+ wireSpec: "openai/responses"
7819
7952
  },
7820
7953
  "openai/gpt-5.4-mini": {
7821
7954
  providerModelName: "gpt-5.4-mini",
@@ -7881,7 +8014,8 @@ var catalog_default3 = {
7881
8014
  family: "gpt-mini",
7882
8015
  version: "5.4",
7883
8016
  status: "stable",
7884
- active: true
8017
+ active: true,
8018
+ wireSpec: "openai/responses"
7885
8019
  },
7886
8020
  "openai/gpt-4.1-nano": {
7887
8021
  providerModelName: "gpt-4.1-nano",
@@ -7930,7 +8064,8 @@ var catalog_default3 = {
7930
8064
  family: "gpt-nano",
7931
8065
  version: "4.1",
7932
8066
  status: "legacy",
7933
- active: true
8067
+ active: true,
8068
+ wireSpec: "openai/responses"
7934
8069
  },
7935
8070
  "openai/gpt-5-nano": {
7936
8071
  providerModelName: "gpt-5-nano",
@@ -7979,7 +8114,8 @@ var catalog_default3 = {
7979
8114
  family: "gpt-nano",
7980
8115
  version: "5",
7981
8116
  status: "legacy",
7982
- active: true
8117
+ active: true,
8118
+ wireSpec: "openai/responses"
7983
8119
  },
7984
8120
  "openai/gpt-5.4-nano": {
7985
8121
  providerModelName: "gpt-5.4-nano",
@@ -8040,7 +8176,8 @@ var catalog_default3 = {
8040
8176
  family: "gpt-nano",
8041
8177
  version: "5.4",
8042
8178
  status: "stable",
8043
- active: true
8179
+ active: true,
8180
+ wireSpec: "openai/responses"
8044
8181
  },
8045
8182
  "openai/gpt-5-pro": {
8046
8183
  providerModelName: "gpt-5-pro",
@@ -8087,7 +8224,8 @@ var catalog_default3 = {
8087
8224
  family: "gpt-pro",
8088
8225
  version: "5",
8089
8226
  status: "legacy",
8090
- active: true
8227
+ active: true,
8228
+ wireSpec: "openai/responses"
8091
8229
  },
8092
8230
  "openai/gpt-5.2-pro": {
8093
8231
  providerModelName: "gpt-5.2-pro",
@@ -8134,7 +8272,8 @@ var catalog_default3 = {
8134
8272
  family: "gpt-pro",
8135
8273
  version: "5.2",
8136
8274
  status: "legacy",
8137
- active: true
8275
+ active: true,
8276
+ wireSpec: "openai/responses"
8138
8277
  },
8139
8278
  "openai/gpt-5.4-pro": {
8140
8279
  providerModelName: "gpt-5.4-pro",
@@ -8191,7 +8330,8 @@ var catalog_default3 = {
8191
8330
  family: "gpt-pro",
8192
8331
  version: "5.4",
8193
8332
  status: "stable",
8194
- active: true
8333
+ active: true,
8334
+ wireSpec: "openai/responses"
8195
8335
  },
8196
8336
  "openai/gpt-5.5-pro": {
8197
8337
  providerModelName: "gpt-5.5-pro",
@@ -8248,7 +8388,8 @@ var catalog_default3 = {
8248
8388
  family: "gpt-pro",
8249
8389
  version: "5.5",
8250
8390
  status: "stable",
8251
- active: true
8391
+ active: true,
8392
+ wireSpec: "openai/responses"
8252
8393
  },
8253
8394
  "openai/gpt-4o": {
8254
8395
  providerModelName: "gpt-4o",
@@ -8298,7 +8439,8 @@ var catalog_default3 = {
8298
8439
  ],
8299
8440
  family: "gpt-4o",
8300
8441
  version: "4o",
8301
- active: true
8442
+ active: true,
8443
+ wireSpec: "openai/responses"
8302
8444
  },
8303
8445
  "openai/gpt-4o-mini": {
8304
8446
  providerModelName: "gpt-4o-mini",
@@ -8348,7 +8490,8 @@ var catalog_default3 = {
8348
8490
  ],
8349
8491
  family: "gpt-4o",
8350
8492
  version: "4o",
8351
- active: true
8493
+ active: true,
8494
+ wireSpec: "openai/responses"
8352
8495
  },
8353
8496
  "openai/gpt-4o-search": {
8354
8497
  providerModelName: "gpt-4o-search-preview",
@@ -9292,7 +9435,8 @@ var catalog_default3 = {
9292
9435
  ],
9293
9436
  family: "o-series",
9294
9437
  version: "1",
9295
- active: true
9438
+ active: true,
9439
+ wireSpec: "openai/responses"
9296
9440
  },
9297
9441
  "openai/o1-pro": {
9298
9442
  providerModelName: "o1-pro",
@@ -9338,7 +9482,8 @@ var catalog_default3 = {
9338
9482
  ],
9339
9483
  family: "o-series",
9340
9484
  version: "1",
9341
- active: true
9485
+ active: true,
9486
+ wireSpec: "openai/responses"
9342
9487
  },
9343
9488
  "openai/o3": {
9344
9489
  providerModelName: "o3",
@@ -9386,7 +9531,8 @@ var catalog_default3 = {
9386
9531
  ],
9387
9532
  family: "o-series",
9388
9533
  version: "3",
9389
- active: true
9534
+ active: true,
9535
+ wireSpec: "openai/responses"
9390
9536
  },
9391
9537
  "openai/o3-mini": {
9392
9538
  providerModelName: "o3-mini",
@@ -9433,7 +9579,8 @@ var catalog_default3 = {
9433
9579
  ],
9434
9580
  family: "o-series",
9435
9581
  version: "3",
9436
- active: true
9582
+ active: true,
9583
+ wireSpec: "openai/responses"
9437
9584
  },
9438
9585
  "openai/o3-pro": {
9439
9586
  providerModelName: "o3-pro",
@@ -9479,7 +9626,8 @@ var catalog_default3 = {
9479
9626
  ],
9480
9627
  family: "o-series",
9481
9628
  version: "3",
9482
- active: true
9629
+ active: true,
9630
+ wireSpec: "openai/responses"
9483
9631
  },
9484
9632
  "openai/o4-mini": {
9485
9633
  providerModelName: "o4-mini",
@@ -9534,7 +9682,8 @@ var catalog_default3 = {
9534
9682
  ],
9535
9683
  family: "o-series",
9536
9684
  version: "4",
9537
- active: true
9685
+ active: true,
9686
+ wireSpec: "openai/responses"
9538
9687
  },
9539
9688
  "openai/sora-2": {
9540
9689
  providerModelName: "sora-2",
@@ -10459,7 +10608,8 @@ var catalog_default3 = {
10459
10608
  family: "gpt-sol",
10460
10609
  version: "5.6",
10461
10610
  status: "stable",
10462
- active: true
10611
+ active: true,
10612
+ wireSpec: "openai/responses"
10463
10613
  },
10464
10614
  "openai/gpt-5.6-terra": {
10465
10615
  providerModelName: "gpt-5.6-terra",
@@ -10525,7 +10675,8 @@ var catalog_default3 = {
10525
10675
  family: "gpt-terra",
10526
10676
  version: "5.6",
10527
10677
  status: "stable",
10528
- active: true
10678
+ active: true,
10679
+ wireSpec: "openai/responses"
10529
10680
  },
10530
10681
  "openai/gpt-5.6-luna": {
10531
10682
  providerModelName: "gpt-5.6-luna",
@@ -10591,12 +10742,13 @@ var catalog_default3 = {
10591
10742
  family: "gpt-luna",
10592
10743
  version: "5.6",
10593
10744
  status: "stable",
10594
- active: true
10745
+ active: true,
10746
+ wireSpec: "openai/responses"
10595
10747
  }
10596
10748
  };
10597
10749
 
10598
- // src/llm/providers/openrouter/catalog.json
10599
- var catalog_default4 = {
10750
+ // src/catalog/data/openrouter.json
10751
+ var openrouter_default = {
10600
10752
  "openrouter/auto": {
10601
10753
  providerModelName: "openrouter/auto",
10602
10754
  aliases: [
@@ -11130,7 +11282,8 @@ var catalog_default4 = {
11130
11282
  family: "claude-fable",
11131
11283
  version: "5",
11132
11284
  status: "stable",
11133
- active: true
11285
+ active: true,
11286
+ wireSpec: "openai/chat-completions"
11134
11287
  },
11135
11288
  "openrouter/claude-opus-4": {
11136
11289
  providerModelName: "anthropic/claude-opus-4",
@@ -11177,7 +11330,8 @@ var catalog_default4 = {
11177
11330
  family: "claude-opus",
11178
11331
  version: "4",
11179
11332
  status: "legacy",
11180
- active: true
11333
+ active: true,
11334
+ wireSpec: "openai/chat-completions"
11181
11335
  },
11182
11336
  "openrouter/claude-opus-4.1": {
11183
11337
  providerModelName: "anthropic/claude-opus-4.1",
@@ -11224,7 +11378,8 @@ var catalog_default4 = {
11224
11378
  family: "claude-opus",
11225
11379
  version: "4.1",
11226
11380
  status: "legacy",
11227
- active: true
11381
+ active: true,
11382
+ wireSpec: "openai/chat-completions"
11228
11383
  },
11229
11384
  "openrouter/claude-opus-4.5": {
11230
11385
  providerModelName: "anthropic/claude-opus-4.5",
@@ -11271,7 +11426,8 @@ var catalog_default4 = {
11271
11426
  family: "claude-opus",
11272
11427
  version: "4.5",
11273
11428
  status: "legacy",
11274
- active: true
11429
+ active: true,
11430
+ wireSpec: "openai/chat-completions"
11275
11431
  },
11276
11432
  "openrouter/claude-opus-4.6": {
11277
11433
  providerModelName: "anthropic/claude-opus-4.6",
@@ -11318,7 +11474,8 @@ var catalog_default4 = {
11318
11474
  family: "claude-opus",
11319
11475
  version: "4.6",
11320
11476
  status: "stable",
11321
- active: true
11477
+ active: true,
11478
+ wireSpec: "openai/chat-completions"
11322
11479
  },
11323
11480
  "openrouter/claude-opus-4.6-fast": {
11324
11481
  providerModelName: "anthropic/claude-opus-4.6-fast",
@@ -11369,7 +11526,8 @@ var catalog_default4 = {
11369
11526
  deprecation: {
11370
11527
  shutdownDate: "2026-06-29",
11371
11528
  source: "openrouter"
11372
- }
11529
+ },
11530
+ wireSpec: "openai/chat-completions"
11373
11531
  },
11374
11532
  "openrouter/claude-opus-4.7": {
11375
11533
  providerModelName: "anthropic/claude-opus-4.7",
@@ -11416,7 +11574,8 @@ var catalog_default4 = {
11416
11574
  family: "claude-opus",
11417
11575
  version: "4.7",
11418
11576
  status: "stable",
11419
- active: true
11577
+ active: true,
11578
+ wireSpec: "openai/chat-completions"
11420
11579
  },
11421
11580
  "openrouter/claude-opus-4.7-fast": {
11422
11581
  providerModelName: "anthropic/claude-opus-4.7-fast",
@@ -11463,7 +11622,8 @@ var catalog_default4 = {
11463
11622
  family: "claude-opus",
11464
11623
  version: "4.7",
11465
11624
  status: "stable",
11466
- active: true
11625
+ active: true,
11626
+ wireSpec: "openai/chat-completions"
11467
11627
  },
11468
11628
  "openrouter/claude-opus-4.8": {
11469
11629
  providerModelName: "anthropic/claude-opus-4.8",
@@ -11510,7 +11670,8 @@ var catalog_default4 = {
11510
11670
  family: "claude-opus",
11511
11671
  version: "4.8",
11512
11672
  status: "stable",
11513
- active: true
11673
+ active: true,
11674
+ wireSpec: "openai/chat-completions"
11514
11675
  },
11515
11676
  "openrouter/claude-opus-4.8-fast": {
11516
11677
  providerModelName: "anthropic/claude-opus-4.8-fast",
@@ -11557,7 +11718,8 @@ var catalog_default4 = {
11557
11718
  family: "claude-opus",
11558
11719
  version: "4.8",
11559
11720
  status: "stable",
11560
- active: true
11721
+ active: true,
11722
+ wireSpec: "openai/chat-completions"
11561
11723
  },
11562
11724
  "openrouter/claude-sonnet-4": {
11563
11725
  providerModelName: "anthropic/claude-sonnet-4",
@@ -11604,7 +11766,8 @@ var catalog_default4 = {
11604
11766
  family: "claude-sonnet",
11605
11767
  version: "4",
11606
11768
  status: "legacy",
11607
- active: true
11769
+ active: true,
11770
+ wireSpec: "openai/chat-completions"
11608
11771
  },
11609
11772
  "openrouter/claude-sonnet-4.5": {
11610
11773
  providerModelName: "anthropic/claude-sonnet-4.5",
@@ -11651,7 +11814,8 @@ var catalog_default4 = {
11651
11814
  family: "claude-sonnet",
11652
11815
  version: "4.5",
11653
11816
  status: "stable",
11654
- active: true
11817
+ active: true,
11818
+ wireSpec: "openai/chat-completions"
11655
11819
  },
11656
11820
  "openrouter/claude-sonnet-4.6": {
11657
11821
  providerModelName: "anthropic/claude-sonnet-4.6",
@@ -11698,7 +11862,8 @@ var catalog_default4 = {
11698
11862
  family: "claude-sonnet",
11699
11863
  version: "4.6",
11700
11864
  status: "stable",
11701
- active: true
11865
+ active: true,
11866
+ wireSpec: "openai/chat-completions"
11702
11867
  },
11703
11868
  "openrouter/claude-haiku-3": {
11704
11869
  providerModelName: "anthropic/claude-3-haiku",
@@ -11745,7 +11910,8 @@ var catalog_default4 = {
11745
11910
  family: "claude-haiku",
11746
11911
  version: "3",
11747
11912
  status: "legacy",
11748
- active: true
11913
+ active: true,
11914
+ wireSpec: "openai/chat-completions"
11749
11915
  },
11750
11916
  "openrouter/claude-haiku-3.5": {
11751
11917
  providerModelName: "anthropic/claude-3.5-haiku",
@@ -11792,7 +11958,8 @@ var catalog_default4 = {
11792
11958
  family: "claude-haiku",
11793
11959
  version: "3.5",
11794
11960
  status: "legacy",
11795
- active: true
11961
+ active: true,
11962
+ wireSpec: "openai/chat-completions"
11796
11963
  },
11797
11964
  "openrouter/claude-haiku-4.5": {
11798
11965
  providerModelName: "anthropic/claude-haiku-4.5",
@@ -11839,7 +12006,8 @@ var catalog_default4 = {
11839
12006
  family: "claude-haiku",
11840
12007
  version: "4.5",
11841
12008
  status: "stable",
11842
- active: true
12009
+ active: true,
12010
+ wireSpec: "openai/chat-completions"
11843
12011
  },
11844
12012
  "openrouter/gpt-3.5-turbo": {
11845
12013
  providerModelName: "openai/gpt-3.5-turbo",
@@ -11886,7 +12054,8 @@ var catalog_default4 = {
11886
12054
  family: "gpt",
11887
12055
  version: "3.5",
11888
12056
  status: "legacy",
11889
- active: true
12057
+ active: true,
12058
+ wireSpec: "openai/chat-completions"
11890
12059
  },
11891
12060
  "openrouter/gpt-4": {
11892
12061
  providerModelName: "openai/gpt-4",
@@ -11931,7 +12100,8 @@ var catalog_default4 = {
11931
12100
  family: "gpt",
11932
12101
  version: "4",
11933
12102
  status: "legacy",
11934
- active: true
12103
+ active: true,
12104
+ wireSpec: "openai/chat-completions"
11935
12105
  },
11936
12106
  "openrouter/gpt-4-turbo": {
11937
12107
  providerModelName: "openai/gpt-4-turbo",
@@ -11978,7 +12148,8 @@ var catalog_default4 = {
11978
12148
  family: "gpt",
11979
12149
  version: "4",
11980
12150
  status: "legacy",
11981
- active: true
12151
+ active: true,
12152
+ wireSpec: "openai/chat-completions"
11982
12153
  },
11983
12154
  "openrouter/gpt-4.1": {
11984
12155
  providerModelName: "openai/gpt-4.1",
@@ -12025,7 +12196,8 @@ var catalog_default4 = {
12025
12196
  family: "gpt",
12026
12197
  version: "4.1",
12027
12198
  status: "legacy",
12028
- active: true
12199
+ active: true,
12200
+ wireSpec: "openai/chat-completions"
12029
12201
  },
12030
12202
  "openrouter/gpt-5": {
12031
12203
  providerModelName: "openai/gpt-5",
@@ -12072,7 +12244,8 @@ var catalog_default4 = {
12072
12244
  family: "gpt",
12073
12245
  version: "5",
12074
12246
  status: "legacy",
12075
- active: true
12247
+ active: true,
12248
+ wireSpec: "openai/chat-completions"
12076
12249
  },
12077
12250
  "openrouter/gpt-5.1": {
12078
12251
  providerModelName: "openai/gpt-5.1",
@@ -12119,7 +12292,8 @@ var catalog_default4 = {
12119
12292
  family: "gpt",
12120
12293
  version: "5.1",
12121
12294
  status: "legacy",
12122
- active: true
12295
+ active: true,
12296
+ wireSpec: "openai/chat-completions"
12123
12297
  },
12124
12298
  "openrouter/gpt-5.2": {
12125
12299
  providerModelName: "openai/gpt-5.2",
@@ -12166,7 +12340,8 @@ var catalog_default4 = {
12166
12340
  family: "gpt",
12167
12341
  version: "5.2",
12168
12342
  status: "stable",
12169
- active: true
12343
+ active: true,
12344
+ wireSpec: "openai/chat-completions"
12170
12345
  },
12171
12346
  "openrouter/gpt-5.4": {
12172
12347
  providerModelName: "openai/gpt-5.4",
@@ -12213,7 +12388,8 @@ var catalog_default4 = {
12213
12388
  family: "gpt",
12214
12389
  version: "5.4",
12215
12390
  status: "stable",
12216
- active: true
12391
+ active: true,
12392
+ wireSpec: "openai/chat-completions"
12217
12393
  },
12218
12394
  "openrouter/gpt-5.5": {
12219
12395
  providerModelName: "openai/gpt-5.5",
@@ -12260,7 +12436,8 @@ var catalog_default4 = {
12260
12436
  family: "gpt",
12261
12437
  version: "5.5",
12262
12438
  status: "stable",
12263
- active: true
12439
+ active: true,
12440
+ wireSpec: "openai/chat-completions"
12264
12441
  },
12265
12442
  "openrouter/gpt-5-chat": {
12266
12443
  providerModelName: "openai/gpt-5-chat",
@@ -12307,7 +12484,8 @@ var catalog_default4 = {
12307
12484
  family: "gpt-chat",
12308
12485
  version: "5",
12309
12486
  status: "legacy",
12310
- active: true
12487
+ active: true,
12488
+ wireSpec: "openai/chat-completions"
12311
12489
  },
12312
12490
  "openrouter/gpt-5.1-chat": {
12313
12491
  providerModelName: "openai/gpt-5.1-chat",
@@ -12354,7 +12532,8 @@ var catalog_default4 = {
12354
12532
  family: "gpt-chat",
12355
12533
  version: "5.1",
12356
12534
  status: "legacy",
12357
- active: true
12535
+ active: true,
12536
+ wireSpec: "openai/chat-completions"
12358
12537
  },
12359
12538
  "openrouter/gpt-5.2-chat": {
12360
12539
  providerModelName: "openai/gpt-5.2-chat",
@@ -12405,7 +12584,8 @@ var catalog_default4 = {
12405
12584
  deprecation: {
12406
12585
  shutdownDate: "2026-08-10",
12407
12586
  source: "openrouter"
12408
- }
12587
+ },
12588
+ wireSpec: "openai/chat-completions"
12409
12589
  },
12410
12590
  "openrouter/gpt-5.3-chat": {
12411
12591
  providerModelName: "openai/gpt-5.3-chat",
@@ -12456,7 +12636,8 @@ var catalog_default4 = {
12456
12636
  deprecation: {
12457
12637
  shutdownDate: "2026-08-10",
12458
12638
  source: "openrouter"
12459
- }
12639
+ },
12640
+ wireSpec: "openai/chat-completions"
12460
12641
  },
12461
12642
  "openrouter/gpt-5-codex": {
12462
12643
  providerModelName: "openai/gpt-5-codex",
@@ -12785,7 +12966,8 @@ var catalog_default4 = {
12785
12966
  family: "gpt-mini",
12786
12967
  version: "4.1",
12787
12968
  status: "legacy",
12788
- active: true
12969
+ active: true,
12970
+ wireSpec: "openai/chat-completions"
12789
12971
  },
12790
12972
  "openrouter/gpt-5-mini": {
12791
12973
  providerModelName: "openai/gpt-5-mini",
@@ -12832,7 +13014,8 @@ var catalog_default4 = {
12832
13014
  family: "gpt-mini",
12833
13015
  version: "5",
12834
13016
  status: "legacy",
12835
- active: true
13017
+ active: true,
13018
+ wireSpec: "openai/chat-completions"
12836
13019
  },
12837
13020
  "openrouter/gpt-5.4-mini": {
12838
13021
  providerModelName: "openai/gpt-5.4-mini",
@@ -12879,7 +13062,8 @@ var catalog_default4 = {
12879
13062
  family: "gpt-mini",
12880
13063
  version: "5.4",
12881
13064
  status: "stable",
12882
- active: true
13065
+ active: true,
13066
+ wireSpec: "openai/chat-completions"
12883
13067
  },
12884
13068
  "openrouter/gpt-4.1-nano": {
12885
13069
  providerModelName: "openai/gpt-4.1-nano",
@@ -12926,7 +13110,8 @@ var catalog_default4 = {
12926
13110
  family: "gpt-nano",
12927
13111
  version: "4.1",
12928
13112
  status: "legacy",
12929
- active: true
13113
+ active: true,
13114
+ wireSpec: "openai/chat-completions"
12930
13115
  },
12931
13116
  "openrouter/gpt-5-nano": {
12932
13117
  providerModelName: "openai/gpt-5-nano",
@@ -12973,7 +13158,8 @@ var catalog_default4 = {
12973
13158
  family: "gpt-nano",
12974
13159
  version: "5",
12975
13160
  status: "legacy",
12976
- active: true
13161
+ active: true,
13162
+ wireSpec: "openai/chat-completions"
12977
13163
  },
12978
13164
  "openrouter/gpt-5.4-nano": {
12979
13165
  providerModelName: "openai/gpt-5.4-nano",
@@ -13020,7 +13206,8 @@ var catalog_default4 = {
13020
13206
  family: "gpt-nano",
13021
13207
  version: "5.4",
13022
13208
  status: "stable",
13023
- active: true
13209
+ active: true,
13210
+ wireSpec: "openai/chat-completions"
13024
13211
  },
13025
13212
  "openrouter/gpt-5-pro": {
13026
13213
  providerModelName: "openai/gpt-5-pro",
@@ -13066,7 +13253,8 @@ var catalog_default4 = {
13066
13253
  family: "gpt-pro",
13067
13254
  version: "5",
13068
13255
  status: "legacy",
13069
- active: true
13256
+ active: true,
13257
+ wireSpec: "openai/chat-completions"
13070
13258
  },
13071
13259
  "openrouter/gpt-5.2-pro": {
13072
13260
  providerModelName: "openai/gpt-5.2-pro",
@@ -13112,7 +13300,8 @@ var catalog_default4 = {
13112
13300
  family: "gpt-pro",
13113
13301
  version: "5.2",
13114
13302
  status: "legacy",
13115
- active: true
13303
+ active: true,
13304
+ wireSpec: "openai/chat-completions"
13116
13305
  },
13117
13306
  "openrouter/gpt-5.4-pro": {
13118
13307
  providerModelName: "openai/gpt-5.4-pro",
@@ -13158,7 +13347,8 @@ var catalog_default4 = {
13158
13347
  family: "gpt-pro",
13159
13348
  version: "5.4",
13160
13349
  status: "stable",
13161
- active: true
13350
+ active: true,
13351
+ wireSpec: "openai/chat-completions"
13162
13352
  },
13163
13353
  "openrouter/gpt-5.5-pro": {
13164
13354
  providerModelName: "openai/gpt-5.5-pro",
@@ -13204,7 +13394,8 @@ var catalog_default4 = {
13204
13394
  family: "gpt-pro",
13205
13395
  version: "5.5",
13206
13396
  status: "stable",
13207
- active: true
13397
+ active: true,
13398
+ wireSpec: "openai/chat-completions"
13208
13399
  },
13209
13400
  "openrouter/gpt-4o": {
13210
13401
  providerModelName: "openai/gpt-4o",
@@ -13253,7 +13444,8 @@ var catalog_default4 = {
13253
13444
  ],
13254
13445
  family: "gpt-4o",
13255
13446
  version: "4o",
13256
- active: true
13447
+ active: true,
13448
+ wireSpec: "openai/chat-completions"
13257
13449
  },
13258
13450
  "openrouter/gpt-4o-mini": {
13259
13451
  providerModelName: "openai/gpt-4o-mini",
@@ -13301,7 +13493,8 @@ var catalog_default4 = {
13301
13493
  ],
13302
13494
  family: "gpt-4o",
13303
13495
  version: "4o",
13304
- active: true
13496
+ active: true,
13497
+ wireSpec: "openai/chat-completions"
13305
13498
  },
13306
13499
  "openrouter/gpt-4o-search": {
13307
13500
  providerModelName: "openai/gpt-4o-search-preview",
@@ -13653,7 +13846,8 @@ var catalog_default4 = {
13653
13846
  family: "gpt-oss",
13654
13847
  version: "1",
13655
13848
  status: "stable",
13656
- active: true
13849
+ active: true,
13850
+ wireSpec: "openai/chat-completions"
13657
13851
  },
13658
13852
  "openrouter/gpt-oss-120b": {
13659
13853
  providerModelName: "openai/gpt-oss-120b",
@@ -13699,7 +13893,8 @@ var catalog_default4 = {
13699
13893
  family: "gpt-oss",
13700
13894
  version: "1",
13701
13895
  status: "stable",
13702
- active: true
13896
+ active: true,
13897
+ wireSpec: "openai/chat-completions"
13703
13898
  },
13704
13899
  "openrouter/gpt-oss-safeguard-20b": {
13705
13900
  providerModelName: "openai/gpt-oss-safeguard-20b",
@@ -13883,7 +14078,8 @@ var catalog_default4 = {
13883
14078
  ],
13884
14079
  family: "o-series",
13885
14080
  version: "1",
13886
- active: true
14081
+ active: true,
14082
+ wireSpec: "openai/chat-completions"
13887
14083
  },
13888
14084
  "openrouter/o1-pro": {
13889
14085
  providerModelName: "openai/o1-pro",
@@ -13928,7 +14124,8 @@ var catalog_default4 = {
13928
14124
  ],
13929
14125
  family: "o-series",
13930
14126
  version: "1",
13931
- active: true
14127
+ active: true,
14128
+ wireSpec: "openai/chat-completions"
13932
14129
  },
13933
14130
  "openrouter/o3": {
13934
14131
  providerModelName: "openai/o3",
@@ -13974,7 +14171,8 @@ var catalog_default4 = {
13974
14171
  ],
13975
14172
  family: "o-series",
13976
14173
  version: "3",
13977
- active: true
14174
+ active: true,
14175
+ wireSpec: "openai/chat-completions"
13978
14176
  },
13979
14177
  "openrouter/o3-mini": {
13980
14178
  providerModelName: "openai/o3-mini",
@@ -14020,7 +14218,8 @@ var catalog_default4 = {
14020
14218
  ],
14021
14219
  family: "o-series",
14022
14220
  version: "3",
14023
- active: true
14221
+ active: true,
14222
+ wireSpec: "openai/chat-completions"
14024
14223
  },
14025
14224
  "openrouter/o3-pro": {
14026
14225
  providerModelName: "openai/o3-pro",
@@ -14065,7 +14264,8 @@ var catalog_default4 = {
14065
14264
  ],
14066
14265
  family: "o-series",
14067
14266
  version: "3",
14068
- active: true
14267
+ active: true,
14268
+ wireSpec: "openai/chat-completions"
14069
14269
  },
14070
14270
  "openrouter/o3-deep-research": {
14071
14271
  providerModelName: "openai/o3-deep-research",
@@ -14111,7 +14311,8 @@ var catalog_default4 = {
14111
14311
  ],
14112
14312
  family: "o-series",
14113
14313
  version: "3",
14114
- active: true
14314
+ active: true,
14315
+ wireSpec: "openai/chat-completions"
14115
14316
  },
14116
14317
  "openrouter/o4-mini": {
14117
14318
  providerModelName: "openai/o4-mini",
@@ -14158,7 +14359,8 @@ var catalog_default4 = {
14158
14359
  ],
14159
14360
  family: "o-series",
14160
14361
  version: "4",
14161
- active: true
14362
+ active: true,
14363
+ wireSpec: "openai/chat-completions"
14162
14364
  },
14163
14365
  "openrouter/o4-mini-deep-research": {
14164
14366
  providerModelName: "openai/o4-mini-deep-research",
@@ -14204,7 +14406,8 @@ var catalog_default4 = {
14204
14406
  ],
14205
14407
  family: "o-series",
14206
14408
  version: "4",
14207
- active: true
14409
+ active: true,
14410
+ wireSpec: "openai/chat-completions"
14208
14411
  },
14209
14412
  "openrouter/gpt-3.5-turbo-instruct": {
14210
14413
  providerModelName: "openai/gpt-3.5-turbo-instruct",
@@ -14298,7 +14501,8 @@ var catalog_default4 = {
14298
14501
  family: "gemini-pro",
14299
14502
  version: "2.5",
14300
14503
  status: "stable",
14301
- active: true
14504
+ active: true,
14505
+ wireSpec: "openai/chat-completions"
14302
14506
  },
14303
14507
  "openrouter/gemini-3.1-pro": {
14304
14508
  providerModelName: "google/gemini-3.1-pro-preview",
@@ -14346,7 +14550,8 @@ var catalog_default4 = {
14346
14550
  family: "gemini-pro",
14347
14551
  version: "3.1",
14348
14552
  status: "preview",
14349
- active: true
14553
+ active: true,
14554
+ wireSpec: "openai/chat-completions"
14350
14555
  },
14351
14556
  "openrouter/gemini-3.1-pro-customtools": {
14352
14557
  providerModelName: "google/gemini-3.1-pro-preview-customtools",
@@ -14394,7 +14599,8 @@ var catalog_default4 = {
14394
14599
  family: "gemini-pro",
14395
14600
  version: "3.1",
14396
14601
  status: "preview",
14397
- active: true
14602
+ active: true,
14603
+ wireSpec: "openai/chat-completions"
14398
14604
  },
14399
14605
  "openrouter/gemini-2.5-flash": {
14400
14606
  providerModelName: "google/gemini-2.5-flash",
@@ -14442,7 +14648,8 @@ var catalog_default4 = {
14442
14648
  family: "gemini-flash",
14443
14649
  version: "2.5",
14444
14650
  status: "stable",
14445
- active: true
14651
+ active: true,
14652
+ wireSpec: "openai/chat-completions"
14446
14653
  },
14447
14654
  "openrouter/gemini-3-flash": {
14448
14655
  providerModelName: "google/gemini-3-flash-preview",
@@ -14490,7 +14697,8 @@ var catalog_default4 = {
14490
14697
  family: "gemini-flash",
14491
14698
  version: "3",
14492
14699
  status: "preview",
14493
- active: true
14700
+ active: true,
14701
+ wireSpec: "openai/chat-completions"
14494
14702
  },
14495
14703
  "openrouter/gemini-3.5-flash": {
14496
14704
  providerModelName: "google/gemini-3.5-flash",
@@ -14538,7 +14746,8 @@ var catalog_default4 = {
14538
14746
  family: "gemini-flash",
14539
14747
  version: "3.5",
14540
14748
  status: "stable",
14541
- active: true
14749
+ active: true,
14750
+ wireSpec: "openai/chat-completions"
14542
14751
  },
14543
14752
  "openrouter/gemini-2.5-flash-lite": {
14544
14753
  providerModelName: "google/gemini-2.5-flash-lite",
@@ -14587,7 +14796,8 @@ var catalog_default4 = {
14587
14796
  family: "gemini-flash-lite",
14588
14797
  version: "2.5",
14589
14798
  status: "stable",
14590
- active: true
14799
+ active: true,
14800
+ wireSpec: "openai/chat-completions"
14591
14801
  },
14592
14802
  "openrouter/gemini-3.1-flash-lite": {
14593
14803
  providerModelName: "google/gemini-3.1-flash-lite",
@@ -14636,7 +14846,8 @@ var catalog_default4 = {
14636
14846
  family: "gemini-flash-lite",
14637
14847
  version: "3.1",
14638
14848
  status: "stable",
14639
- active: true
14849
+ active: true,
14850
+ wireSpec: "openai/chat-completions"
14640
14851
  },
14641
14852
  "openrouter/gemini-2.5-flash-image": {
14642
14853
  providerModelName: "google/gemini-2.5-flash-image",
@@ -14898,7 +15109,8 @@ var catalog_default4 = {
14898
15109
  family: "gemma",
14899
15110
  version: "2",
14900
15111
  status: "legacy",
14901
- active: true
15112
+ active: true,
15113
+ wireSpec: "openai/chat-completions"
14902
15114
  },
14903
15115
  "openrouter/gemma-3-4b": {
14904
15116
  providerModelName: "google/gemma-3-4b-it",
@@ -14944,7 +15156,8 @@ var catalog_default4 = {
14944
15156
  family: "gemma",
14945
15157
  version: "3",
14946
15158
  status: "legacy",
14947
- active: true
15159
+ active: true,
15160
+ wireSpec: "openai/chat-completions"
14948
15161
  },
14949
15162
  "openrouter/gemma-3-12b": {
14950
15163
  providerModelName: "google/gemma-3-12b-it",
@@ -14990,7 +15203,8 @@ var catalog_default4 = {
14990
15203
  family: "gemma",
14991
15204
  version: "3",
14992
15205
  status: "legacy",
14993
- active: true
15206
+ active: true,
15207
+ wireSpec: "openai/chat-completions"
14994
15208
  },
14995
15209
  "openrouter/gemma-3-27b": {
14996
15210
  providerModelName: "google/gemma-3-27b-it",
@@ -15037,7 +15251,8 @@ var catalog_default4 = {
15037
15251
  family: "gemma",
15038
15252
  version: "3",
15039
15253
  status: "legacy",
15040
- active: true
15254
+ active: true,
15255
+ wireSpec: "openai/chat-completions"
15041
15256
  },
15042
15257
  "openrouter/gemma-3n-e4b": {
15043
15258
  providerModelName: "google/gemma-3n-e4b-it",
@@ -15081,7 +15296,8 @@ var catalog_default4 = {
15081
15296
  family: "gemma",
15082
15297
  version: "3",
15083
15298
  status: "legacy",
15084
- active: true
15299
+ active: true,
15300
+ wireSpec: "openai/chat-completions"
15085
15301
  },
15086
15302
  "openrouter/gemma-4-26b-a4b": {
15087
15303
  providerModelName: "google/gemma-4-26b-a4b-it",
@@ -15128,7 +15344,8 @@ var catalog_default4 = {
15128
15344
  family: "gemma",
15129
15345
  version: "4",
15130
15346
  status: "stable",
15131
- active: true
15347
+ active: true,
15348
+ wireSpec: "openai/chat-completions"
15132
15349
  },
15133
15350
  "openrouter/gemma-4-31b": {
15134
15351
  providerModelName: "google/gemma-4-31b-it",
@@ -15176,7 +15393,8 @@ var catalog_default4 = {
15176
15393
  family: "gemma",
15177
15394
  version: "4",
15178
15395
  status: "stable",
15179
- active: true
15396
+ active: true,
15397
+ wireSpec: "openai/chat-completions"
15180
15398
  },
15181
15399
  "openrouter/lyria-3-clip": {
15182
15400
  providerModelName: "google/lyria-3-clip-preview",
@@ -15314,7 +15532,8 @@ var catalog_default4 = {
15314
15532
  family: "grok",
15315
15533
  version: "4.20",
15316
15534
  status: "stable",
15317
- active: true
15535
+ active: true,
15536
+ wireSpec: "openai/chat-completions"
15318
15537
  },
15319
15538
  "openrouter/grok-4.20-multi-agent": {
15320
15539
  providerModelName: "x-ai/grok-4.20-multi-agent",
@@ -15360,7 +15579,8 @@ var catalog_default4 = {
15360
15579
  family: "grok",
15361
15580
  version: "4.20",
15362
15581
  status: "stable",
15363
- active: true
15582
+ active: true,
15583
+ wireSpec: "openai/chat-completions"
15364
15584
  },
15365
15585
  "openrouter/grok-4.3": {
15366
15586
  providerModelName: "x-ai/grok-4.3",
@@ -15406,7 +15626,8 @@ var catalog_default4 = {
15406
15626
  family: "grok",
15407
15627
  version: "4.3",
15408
15628
  status: "stable",
15409
- active: true
15629
+ active: true,
15630
+ wireSpec: "openai/chat-completions"
15410
15631
  },
15411
15632
  "openrouter/grok-build-0.1": {
15412
15633
  providerModelName: "x-ai/grok-build-0.1",
@@ -15497,7 +15718,8 @@ var catalog_default4 = {
15497
15718
  family: "deepseek-chat",
15498
15719
  version: "3",
15499
15720
  status: "stable",
15500
- active: true
15721
+ active: true,
15722
+ wireSpec: "openai/chat-completions"
15501
15723
  },
15502
15724
  "openrouter/deepseek-v3": {
15503
15725
  providerModelName: "deepseek/deepseek-chat-v3-0324",
@@ -15543,7 +15765,8 @@ var catalog_default4 = {
15543
15765
  family: "deepseek-chat",
15544
15766
  version: "3",
15545
15767
  status: "legacy",
15546
- active: true
15768
+ active: true,
15769
+ wireSpec: "openai/chat-completions"
15547
15770
  },
15548
15771
  "openrouter/deepseek-v3.1": {
15549
15772
  providerModelName: "deepseek/deepseek-chat-v3.1",
@@ -15590,7 +15813,8 @@ var catalog_default4 = {
15590
15813
  family: "deepseek-chat",
15591
15814
  version: "3.1",
15592
15815
  status: "stable",
15593
- active: true
15816
+ active: true,
15817
+ wireSpec: "openai/chat-completions"
15594
15818
  },
15595
15819
  "openrouter/deepseek-v3.2": {
15596
15820
  providerModelName: "deepseek/deepseek-v3.2",
@@ -15637,7 +15861,8 @@ var catalog_default4 = {
15637
15861
  family: "deepseek-chat",
15638
15862
  version: "3.2",
15639
15863
  status: "stable",
15640
- active: true
15864
+ active: true,
15865
+ wireSpec: "openai/chat-completions"
15641
15866
  },
15642
15867
  "openrouter/deepseek-v4-flash": {
15643
15868
  providerModelName: "deepseek/deepseek-v4-flash",
@@ -15682,7 +15907,8 @@ var catalog_default4 = {
15682
15907
  family: "deepseek-chat",
15683
15908
  version: "4",
15684
15909
  status: "stable",
15685
- active: true
15910
+ active: true,
15911
+ wireSpec: "openai/chat-completions"
15686
15912
  },
15687
15913
  "openrouter/deepseek-v4-pro": {
15688
15914
  providerModelName: "deepseek/deepseek-v4-pro",
@@ -15728,7 +15954,8 @@ var catalog_default4 = {
15728
15954
  family: "deepseek-chat",
15729
15955
  version: "4",
15730
15956
  status: "stable",
15731
- active: true
15957
+ active: true,
15958
+ wireSpec: "openai/chat-completions"
15732
15959
  },
15733
15960
  "openrouter/deepseek-r1": {
15734
15961
  providerModelName: "deepseek/deepseek-r1",
@@ -15774,7 +16001,8 @@ var catalog_default4 = {
15774
16001
  family: "deepseek-r1",
15775
16002
  version: "1",
15776
16003
  status: "stable",
15777
- active: true
16004
+ active: true,
16005
+ wireSpec: "openai/chat-completions"
15778
16006
  },
15779
16007
  "openrouter/deepseek-r1-distill-llama-70b": {
15780
16008
  providerModelName: "deepseek/deepseek-r1-distill-llama-70b",
@@ -15819,7 +16047,8 @@ var catalog_default4 = {
15819
16047
  family: "deepseek-r1",
15820
16048
  version: "1",
15821
16049
  status: "stable",
15822
- active: true
16050
+ active: true,
16051
+ wireSpec: "openai/chat-completions"
15823
16052
  },
15824
16053
  "openrouter/deepseek-r1-distill-qwen-32b": {
15825
16054
  providerModelName: "deepseek/deepseek-r1-distill-qwen-32b",
@@ -15864,7 +16093,8 @@ var catalog_default4 = {
15864
16093
  family: "deepseek-r1",
15865
16094
  version: "1",
15866
16095
  status: "stable",
15867
- active: true
16096
+ active: true,
16097
+ wireSpec: "openai/chat-completions"
15868
16098
  },
15869
16099
  "openrouter/qwen-2.5-7b": {
15870
16100
  providerModelName: "qwen/qwen-2.5-7b-instruct",
@@ -15909,7 +16139,8 @@ var catalog_default4 = {
15909
16139
  family: "qwen",
15910
16140
  version: "2.5",
15911
16141
  status: "legacy",
15912
- active: true
16142
+ active: true,
16143
+ wireSpec: "openai/chat-completions"
15913
16144
  },
15914
16145
  "openrouter/qwen-2.5-72b": {
15915
16146
  providerModelName: "qwen/qwen-2.5-72b-instruct",
@@ -15954,7 +16185,8 @@ var catalog_default4 = {
15954
16185
  family: "qwen",
15955
16186
  version: "2.5",
15956
16187
  status: "legacy",
15957
- active: true
16188
+ active: true,
16189
+ wireSpec: "openai/chat-completions"
15958
16190
  },
15959
16191
  "openrouter/qwen-2.5-vl-72b": {
15960
16192
  providerModelName: "qwen/qwen2.5-vl-72b-instruct",
@@ -16047,7 +16279,8 @@ var catalog_default4 = {
16047
16279
  family: "qwen",
16048
16280
  version: "3",
16049
16281
  status: "stable",
16050
- active: true
16282
+ active: true,
16283
+ wireSpec: "openai/chat-completions"
16051
16284
  },
16052
16285
  "openrouter/qwen-3-14b": {
16053
16286
  providerModelName: "qwen/qwen3-14b",
@@ -16092,7 +16325,8 @@ var catalog_default4 = {
16092
16325
  family: "qwen",
16093
16326
  version: "3",
16094
16327
  status: "stable",
16095
- active: true
16328
+ active: true,
16329
+ wireSpec: "openai/chat-completions"
16096
16330
  },
16097
16331
  "openrouter/qwen-3-30b-a3b": {
16098
16332
  providerModelName: "qwen/qwen3-30b-a3b",
@@ -16139,7 +16373,8 @@ var catalog_default4 = {
16139
16373
  family: "qwen",
16140
16374
  version: "3",
16141
16375
  status: "stable",
16142
- active: true
16376
+ active: true,
16377
+ wireSpec: "openai/chat-completions"
16143
16378
  },
16144
16379
  "openrouter/qwen-3-32b": {
16145
16380
  providerModelName: "qwen/qwen3-32b",
@@ -16184,7 +16419,8 @@ var catalog_default4 = {
16184
16419
  family: "qwen",
16185
16420
  version: "3",
16186
16421
  status: "stable",
16187
- active: true
16422
+ active: true,
16423
+ wireSpec: "openai/chat-completions"
16188
16424
  },
16189
16425
  "openrouter/qwen-3-235b-a22b": {
16190
16426
  providerModelName: "qwen/qwen3-235b-a22b",
@@ -16231,7 +16467,8 @@ var catalog_default4 = {
16231
16467
  family: "qwen",
16232
16468
  version: "3",
16233
16469
  status: "stable",
16234
- active: true
16470
+ active: true,
16471
+ wireSpec: "openai/chat-completions"
16235
16472
  },
16236
16473
  "openrouter/qwen-3-next-80b-a3b": {
16237
16474
  providerModelName: "qwen/qwen3-next-80b-a3b-instruct",
@@ -16279,7 +16516,8 @@ var catalog_default4 = {
16279
16516
  family: "qwen",
16280
16517
  version: "3",
16281
16518
  status: "stable",
16282
- active: true
16519
+ active: true,
16520
+ wireSpec: "openai/chat-completions"
16283
16521
  },
16284
16522
  "openrouter/qwen-3.5-9b": {
16285
16523
  providerModelName: "qwen/qwen3.5-9b",
@@ -16325,7 +16563,8 @@ var catalog_default4 = {
16325
16563
  family: "qwen",
16326
16564
  version: "3.5",
16327
16565
  status: "stable",
16328
- active: true
16566
+ active: true,
16567
+ wireSpec: "openai/chat-completions"
16329
16568
  },
16330
16569
  "openrouter/qwen-3.5-27b": {
16331
16570
  providerModelName: "qwen/qwen3.5-27b",
@@ -16371,7 +16610,8 @@ var catalog_default4 = {
16371
16610
  family: "qwen",
16372
16611
  version: "3.5",
16373
16612
  status: "stable",
16374
- active: true
16613
+ active: true,
16614
+ wireSpec: "openai/chat-completions"
16375
16615
  },
16376
16616
  "openrouter/qwen-3.5-35b-a3b": {
16377
16617
  providerModelName: "qwen/qwen3.5-35b-a3b",
@@ -16418,7 +16658,8 @@ var catalog_default4 = {
16418
16658
  family: "qwen",
16419
16659
  version: "3.5",
16420
16660
  status: "stable",
16421
- active: true
16661
+ active: true,
16662
+ wireSpec: "openai/chat-completions"
16422
16663
  },
16423
16664
  "openrouter/qwen-3.5-122b-a10b": {
16424
16665
  providerModelName: "qwen/qwen3.5-122b-a10b",
@@ -16464,7 +16705,8 @@ var catalog_default4 = {
16464
16705
  family: "qwen",
16465
16706
  version: "3.5",
16466
16707
  status: "stable",
16467
- active: true
16708
+ active: true,
16709
+ wireSpec: "openai/chat-completions"
16468
16710
  },
16469
16711
  "openrouter/qwen-3.5-397b-a17b": {
16470
16712
  providerModelName: "qwen/qwen3.5-397b-a17b",
@@ -16511,7 +16753,8 @@ var catalog_default4 = {
16511
16753
  family: "qwen",
16512
16754
  version: "3.5",
16513
16755
  status: "stable",
16514
- active: true
16756
+ active: true,
16757
+ wireSpec: "openai/chat-completions"
16515
16758
  },
16516
16759
  "openrouter/qwen-3.6-27b": {
16517
16760
  providerModelName: "qwen/qwen3.6-27b",
@@ -16558,7 +16801,8 @@ var catalog_default4 = {
16558
16801
  family: "qwen",
16559
16802
  version: "3.6",
16560
16803
  status: "stable",
16561
- active: true
16804
+ active: true,
16805
+ wireSpec: "openai/chat-completions"
16562
16806
  },
16563
16807
  "openrouter/qwen-3.6-35b-a3b": {
16564
16808
  providerModelName: "qwen/qwen3.6-35b-a3b",
@@ -16605,7 +16849,8 @@ var catalog_default4 = {
16605
16849
  family: "qwen",
16606
16850
  version: "3.6",
16607
16851
  status: "stable",
16608
- active: true
16852
+ active: true,
16853
+ wireSpec: "openai/chat-completions"
16609
16854
  },
16610
16855
  "openrouter/qwen-plus": {
16611
16856
  providerModelName: "qwen/qwen-plus",
@@ -16653,7 +16898,8 @@ var catalog_default4 = {
16653
16898
  family: "qwen-plus",
16654
16899
  version: "1",
16655
16900
  status: "legacy",
16656
- active: true
16901
+ active: true,
16902
+ wireSpec: "openai/chat-completions"
16657
16903
  },
16658
16904
  "openrouter/qwen-3.5-plus": {
16659
16905
  providerModelName: "qwen/qwen3.5-plus-20260420",
@@ -16700,7 +16946,8 @@ var catalog_default4 = {
16700
16946
  family: "qwen-plus",
16701
16947
  version: "3.5",
16702
16948
  status: "stable",
16703
- active: true
16949
+ active: true,
16950
+ wireSpec: "openai/chat-completions"
16704
16951
  },
16705
16952
  "openrouter/qwen-3.6-plus": {
16706
16953
  providerModelName: "qwen/qwen3.6-plus",
@@ -16746,7 +16993,8 @@ var catalog_default4 = {
16746
16993
  family: "qwen-plus",
16747
16994
  version: "3.6",
16748
16995
  status: "stable",
16749
- active: true
16996
+ active: true,
16997
+ wireSpec: "openai/chat-completions"
16750
16998
  },
16751
16999
  "openrouter/qwen-3.7-plus": {
16752
17000
  providerModelName: "qwen/qwen3.7-plus",
@@ -16793,7 +17041,8 @@ var catalog_default4 = {
16793
17041
  family: "qwen-plus",
16794
17042
  version: "3.7",
16795
17043
  status: "stable",
16796
- active: true
17044
+ active: true,
17045
+ wireSpec: "openai/chat-completions"
16797
17046
  },
16798
17047
  "openrouter/qwen-3-max": {
16799
17048
  providerModelName: "qwen/qwen3-max",
@@ -16840,7 +17089,8 @@ var catalog_default4 = {
16840
17089
  family: "qwen-max",
16841
17090
  version: "3",
16842
17091
  status: "stable",
16843
- active: true
17092
+ active: true,
17093
+ wireSpec: "openai/chat-completions"
16844
17094
  },
16845
17095
  "openrouter/qwen-3.6-max": {
16846
17096
  providerModelName: "qwen/qwen3.6-max-preview",
@@ -16885,7 +17135,8 @@ var catalog_default4 = {
16885
17135
  family: "qwen-max",
16886
17136
  version: "3.6",
16887
17137
  status: "preview",
16888
- active: true
17138
+ active: true,
17139
+ wireSpec: "openai/chat-completions"
16889
17140
  },
16890
17141
  "openrouter/qwen-3.7-max": {
16891
17142
  providerModelName: "qwen/qwen3.7-max",
@@ -16931,7 +17182,8 @@ var catalog_default4 = {
16931
17182
  family: "qwen-max",
16932
17183
  version: "3.7",
16933
17184
  status: "stable",
16934
- active: true
17185
+ active: true,
17186
+ wireSpec: "openai/chat-completions"
16935
17187
  },
16936
17188
  "openrouter/qwen-3.5-flash": {
16937
17189
  providerModelName: "qwen/qwen3.5-flash-02-23",
@@ -16977,7 +17229,8 @@ var catalog_default4 = {
16977
17229
  family: "qwen-flash",
16978
17230
  version: "3.5",
16979
17231
  status: "stable",
16980
- active: true
17232
+ active: true,
17233
+ wireSpec: "openai/chat-completions"
16981
17234
  },
16982
17235
  "openrouter/qwen-3.6-flash": {
16983
17236
  providerModelName: "qwen/qwen3.6-flash",
@@ -17023,7 +17276,8 @@ var catalog_default4 = {
17023
17276
  family: "qwen-flash",
17024
17277
  version: "3.6",
17025
17278
  status: "stable",
17026
- active: true
17279
+ active: true,
17280
+ wireSpec: "openai/chat-completions"
17027
17281
  },
17028
17282
  "openrouter/qwen-2.5-coder-32b": {
17029
17283
  providerModelName: "qwen/qwen-2.5-coder-32b-instruct",
@@ -17395,7 +17649,8 @@ var catalog_default4 = {
17395
17649
  family: "llama",
17396
17650
  version: "3",
17397
17651
  status: "legacy",
17398
- active: true
17652
+ active: true,
17653
+ wireSpec: "openai/chat-completions"
17399
17654
  },
17400
17655
  "openrouter/llama-3-70b": {
17401
17656
  providerModelName: "meta-llama/llama-3-70b-instruct",
@@ -17444,7 +17699,8 @@ var catalog_default4 = {
17444
17699
  deprecation: {
17445
17700
  shutdownDate: "2026-06-19",
17446
17701
  source: "openrouter"
17447
- }
17702
+ },
17703
+ wireSpec: "openai/chat-completions"
17448
17704
  },
17449
17705
  "openrouter/llama-3.1-8b": {
17450
17706
  providerModelName: "meta-llama/llama-3.1-8b-instruct",
@@ -17490,7 +17746,8 @@ var catalog_default4 = {
17490
17746
  family: "llama",
17491
17747
  version: "3.1",
17492
17748
  status: "legacy",
17493
- active: true
17749
+ active: true,
17750
+ wireSpec: "openai/chat-completions"
17494
17751
  },
17495
17752
  "openrouter/llama-3.1-70b": {
17496
17753
  providerModelName: "meta-llama/llama-3.1-70b-instruct",
@@ -17535,7 +17792,8 @@ var catalog_default4 = {
17535
17792
  family: "llama",
17536
17793
  version: "3.1",
17537
17794
  status: "legacy",
17538
- active: true
17795
+ active: true,
17796
+ wireSpec: "openai/chat-completions"
17539
17797
  },
17540
17798
  "openrouter/llama-3.2-1b": {
17541
17799
  providerModelName: "meta-llama/llama-3.2-1b-instruct",
@@ -17580,7 +17838,8 @@ var catalog_default4 = {
17580
17838
  family: "llama",
17581
17839
  version: "3.2",
17582
17840
  status: "legacy",
17583
- active: true
17841
+ active: true,
17842
+ wireSpec: "openai/chat-completions"
17584
17843
  },
17585
17844
  "openrouter/llama-3.2-3b": {
17586
17845
  providerModelName: "meta-llama/llama-3.2-3b-instruct",
@@ -17626,7 +17885,8 @@ var catalog_default4 = {
17626
17885
  family: "llama",
17627
17886
  version: "3.2",
17628
17887
  status: "legacy",
17629
- active: true
17888
+ active: true,
17889
+ wireSpec: "openai/chat-completions"
17630
17890
  },
17631
17891
  "openrouter/llama-3.2-11b-vision": {
17632
17892
  providerModelName: "meta-llama/llama-3.2-11b-vision-instruct",
@@ -17722,7 +17982,8 @@ var catalog_default4 = {
17722
17982
  family: "llama",
17723
17983
  version: "3.3",
17724
17984
  status: "stable",
17725
- active: true
17985
+ active: true,
17986
+ wireSpec: "openai/chat-completions"
17726
17987
  },
17727
17988
  "openrouter/llama-4-scout": {
17728
17989
  providerModelName: "meta-llama/llama-4-scout",
@@ -17768,7 +18029,8 @@ var catalog_default4 = {
17768
18029
  family: "llama",
17769
18030
  version: "4",
17770
18031
  status: "stable",
17771
- active: true
18032
+ active: true,
18033
+ wireSpec: "openai/chat-completions"
17772
18034
  },
17773
18035
  "openrouter/llama-4-maverick": {
17774
18036
  providerModelName: "meta-llama/llama-4-maverick",
@@ -17814,7 +18076,8 @@ var catalog_default4 = {
17814
18076
  family: "llama",
17815
18077
  version: "4",
17816
18078
  status: "stable",
17817
- active: true
18079
+ active: true,
18080
+ wireSpec: "openai/chat-completions"
17818
18081
  },
17819
18082
  "openrouter/llama-guard-3-8b": {
17820
18083
  providerModelName: "meta-llama/llama-guard-3-8b",
@@ -17949,7 +18212,8 @@ var catalog_default4 = {
17949
18212
  family: "mistral",
17950
18213
  version: "2",
17951
18214
  status: "stable",
17952
- active: true
18215
+ active: true,
18216
+ wireSpec: "openai/chat-completions"
17953
18217
  },
17954
18218
  "openrouter/mistral-medium-3": {
17955
18219
  providerModelName: "mistralai/mistral-medium-3",
@@ -17997,7 +18261,8 @@ var catalog_default4 = {
17997
18261
  family: "mistral",
17998
18262
  version: "3",
17999
18263
  status: "stable",
18000
- active: true
18264
+ active: true,
18265
+ wireSpec: "openai/chat-completions"
18001
18266
  },
18002
18267
  "openrouter/mistral-small": {
18003
18268
  providerModelName: "mistralai/mistral-small-24b-instruct-2501",
@@ -18045,7 +18310,8 @@ var catalog_default4 = {
18045
18310
  family: "mistral",
18046
18311
  version: "3",
18047
18312
  status: "stable",
18048
- active: true
18313
+ active: true,
18314
+ wireSpec: "openai/chat-completions"
18049
18315
  },
18050
18316
  "openrouter/ministral-3b": {
18051
18317
  providerModelName: "mistralai/ministral-3b-2512",
@@ -18092,7 +18358,8 @@ var catalog_default4 = {
18092
18358
  family: "mistral",
18093
18359
  version: "1",
18094
18360
  status: "stable",
18095
- active: true
18361
+ active: true,
18362
+ wireSpec: "openai/chat-completions"
18096
18363
  },
18097
18364
  "openrouter/ministral-8b": {
18098
18365
  providerModelName: "mistralai/ministral-8b-2512",
@@ -18139,7 +18406,8 @@ var catalog_default4 = {
18139
18406
  family: "mistral",
18140
18407
  version: "1",
18141
18408
  status: "stable",
18142
- active: true
18409
+ active: true,
18410
+ wireSpec: "openai/chat-completions"
18143
18411
  },
18144
18412
  "openrouter/ministral-14b": {
18145
18413
  providerModelName: "mistralai/ministral-14b-2512",
@@ -18186,7 +18454,8 @@ var catalog_default4 = {
18186
18454
  family: "mistral",
18187
18455
  version: "1",
18188
18456
  status: "stable",
18189
- active: true
18457
+ active: true,
18458
+ wireSpec: "openai/chat-completions"
18190
18459
  },
18191
18460
  "openrouter/mistral-nemo": {
18192
18461
  providerModelName: "mistralai/mistral-nemo",
@@ -18230,7 +18499,8 @@ var catalog_default4 = {
18230
18499
  family: "mistral",
18231
18500
  version: "1",
18232
18501
  status: "legacy",
18233
- active: true
18502
+ active: true,
18503
+ wireSpec: "openai/chat-completions"
18234
18504
  },
18235
18505
  "openrouter/mistral-saba": {
18236
18506
  providerModelName: "mistralai/mistral-saba",
@@ -18275,7 +18545,8 @@ var catalog_default4 = {
18275
18545
  family: "mistral",
18276
18546
  version: "1",
18277
18547
  status: "stable",
18278
- active: true
18548
+ active: true,
18549
+ wireSpec: "openai/chat-completions"
18279
18550
  },
18280
18551
  "openrouter/mixtral-8x22b": {
18281
18552
  providerModelName: "mistralai/mixtral-8x22b-instruct",
@@ -18321,7 +18592,8 @@ var catalog_default4 = {
18321
18592
  family: "mistral",
18322
18593
  version: "1",
18323
18594
  status: "legacy",
18324
- active: true
18595
+ active: true,
18596
+ wireSpec: "openai/chat-completions"
18325
18597
  },
18326
18598
  "openrouter/voxtral-small-24b": {
18327
18599
  providerModelName: "mistralai/voxtral-small-24b-2507",
@@ -18505,7 +18777,8 @@ var catalog_default4 = {
18505
18777
  family: "kimi",
18506
18778
  version: "2",
18507
18779
  status: "stable",
18508
- active: true
18780
+ active: true,
18781
+ wireSpec: "openai/chat-completions"
18509
18782
  },
18510
18783
  "openrouter/kimi-k2.5": {
18511
18784
  providerModelName: "moonshotai/kimi-k2.5",
@@ -18552,7 +18825,8 @@ var catalog_default4 = {
18552
18825
  family: "kimi",
18553
18826
  version: "2.5",
18554
18827
  status: "stable",
18555
- active: true
18828
+ active: true,
18829
+ wireSpec: "openai/chat-completions"
18556
18830
  },
18557
18831
  "openrouter/kimi-k2.6": {
18558
18832
  providerModelName: "moonshotai/kimi-k2.6",
@@ -18599,7 +18873,8 @@ var catalog_default4 = {
18599
18873
  family: "kimi",
18600
18874
  version: "2.6",
18601
18875
  status: "stable",
18602
- active: true
18876
+ active: true,
18877
+ wireSpec: "openai/chat-completions"
18603
18878
  },
18604
18879
  "openrouter/glm-4.5": {
18605
18880
  providerModelName: "z-ai/glm-4.5",
@@ -18651,7 +18926,8 @@ var catalog_default4 = {
18651
18926
  deprecation: {
18652
18927
  shutdownDate: "2026-12-31",
18653
18928
  source: "openrouter"
18654
- }
18929
+ },
18930
+ wireSpec: "openai/chat-completions"
18655
18931
  },
18656
18932
  "openrouter/glm-4.6": {
18657
18933
  providerModelName: "z-ai/glm-4.6",
@@ -18698,7 +18974,8 @@ var catalog_default4 = {
18698
18974
  family: "glm",
18699
18975
  version: "4.6",
18700
18976
  status: "stable",
18701
- active: true
18977
+ active: true,
18978
+ wireSpec: "openai/chat-completions"
18702
18979
  },
18703
18980
  "openrouter/glm-4.7": {
18704
18981
  providerModelName: "z-ai/glm-4.7",
@@ -18745,7 +19022,8 @@ var catalog_default4 = {
18745
19022
  family: "glm",
18746
19023
  version: "4.7",
18747
19024
  status: "stable",
18748
- active: true
19025
+ active: true,
19026
+ wireSpec: "openai/chat-completions"
18749
19027
  },
18750
19028
  "openrouter/glm-5": {
18751
19029
  providerModelName: "z-ai/glm-5",
@@ -18792,7 +19070,8 @@ var catalog_default4 = {
18792
19070
  family: "glm",
18793
19071
  version: "5",
18794
19072
  status: "stable",
18795
- active: true
19073
+ active: true,
19074
+ wireSpec: "openai/chat-completions"
18796
19075
  },
18797
19076
  "openrouter/glm-5.1": {
18798
19077
  providerModelName: "z-ai/glm-5.1",
@@ -18838,7 +19117,8 @@ var catalog_default4 = {
18838
19117
  version: "5.1",
18839
19118
  status: "stable",
18840
19119
  active: true,
18841
- maxOutput: 128e3
19120
+ maxOutput: 128e3,
19121
+ wireSpec: "openai/chat-completions"
18842
19122
  },
18843
19123
  "openrouter/minimax-01": {
18844
19124
  providerModelName: "minimax/minimax-01",
@@ -18884,7 +19164,8 @@ var catalog_default4 = {
18884
19164
  family: "minimax",
18885
19165
  version: "1",
18886
19166
  status: "legacy",
18887
- active: true
19167
+ active: true,
19168
+ wireSpec: "openai/chat-completions"
18888
19169
  },
18889
19170
  "openrouter/minimax-m1": {
18890
19171
  providerModelName: "minimax/minimax-m1",
@@ -18929,7 +19210,8 @@ var catalog_default4 = {
18929
19210
  family: "minimax",
18930
19211
  version: "1",
18931
19212
  status: "legacy",
18932
- active: true
19213
+ active: true,
19214
+ wireSpec: "openai/chat-completions"
18933
19215
  },
18934
19216
  "openrouter/minimax-m2": {
18935
19217
  providerModelName: "minimax/minimax-m2",
@@ -18977,7 +19259,8 @@ var catalog_default4 = {
18977
19259
  family: "minimax",
18978
19260
  version: "2",
18979
19261
  status: "stable",
18980
- active: true
19262
+ active: true,
19263
+ wireSpec: "openai/chat-completions"
18981
19264
  },
18982
19265
  "openrouter/minimax-m2.5": {
18983
19266
  providerModelName: "minimax/minimax-m2.5",
@@ -19023,7 +19306,8 @@ var catalog_default4 = {
19023
19306
  family: "minimax",
19024
19307
  version: "2.5",
19025
19308
  status: "stable",
19026
- active: true
19309
+ active: true,
19310
+ wireSpec: "openai/chat-completions"
19027
19311
  },
19028
19312
  "openrouter/minimax-m2.7": {
19029
19313
  providerModelName: "minimax/minimax-m2.7",
@@ -19069,7 +19353,8 @@ var catalog_default4 = {
19069
19353
  family: "minimax",
19070
19354
  version: "2.7",
19071
19355
  status: "stable",
19072
- active: true
19356
+ active: true,
19357
+ wireSpec: "openai/chat-completions"
19073
19358
  },
19074
19359
  "openrouter/minimax-m3": {
19075
19360
  providerModelName: "minimax/minimax-m3",
@@ -19116,7 +19401,8 @@ var catalog_default4 = {
19116
19401
  family: "minimax",
19117
19402
  version: "3",
19118
19403
  status: "stable",
19119
- active: true
19404
+ active: true,
19405
+ wireSpec: "openai/chat-completions"
19120
19406
  },
19121
19407
  "openrouter/nemotron-nano-9b-v2": {
19122
19408
  providerModelName: "nvidia/nemotron-nano-9b-v2:free",
@@ -19160,7 +19446,8 @@ var catalog_default4 = {
19160
19446
  family: "nemotron",
19161
19447
  version: "2",
19162
19448
  status: "stable",
19163
- active: true
19449
+ active: true,
19450
+ wireSpec: "openai/chat-completions"
19164
19451
  },
19165
19452
  "openrouter/nemotron-nano-12b-v2-vl": {
19166
19453
  providerModelName: "nvidia/nemotron-nano-12b-v2-vl:free",
@@ -19255,7 +19542,8 @@ var catalog_default4 = {
19255
19542
  deprecation: {
19256
19543
  shutdownDate: "2026-07-17",
19257
19544
  source: "openrouter"
19258
- }
19545
+ },
19546
+ wireSpec: "openai/chat-completions"
19259
19547
  },
19260
19548
  "openrouter/nemotron-3-nano-30b-a3b": {
19261
19549
  providerModelName: "nvidia/nemotron-3-nano-30b-a3b",
@@ -19302,7 +19590,8 @@ var catalog_default4 = {
19302
19590
  family: "nemotron",
19303
19591
  version: "3",
19304
19592
  status: "stable",
19305
- active: true
19593
+ active: true,
19594
+ wireSpec: "openai/chat-completions"
19306
19595
  },
19307
19596
  "openrouter/nemotron-3-super-120b-a12b": {
19308
19597
  providerModelName: "nvidia/nemotron-3-super-120b-a12b",
@@ -19347,7 +19636,8 @@ var catalog_default4 = {
19347
19636
  family: "nemotron",
19348
19637
  version: "3",
19349
19638
  status: "stable",
19350
- active: true
19639
+ active: true,
19640
+ wireSpec: "openai/chat-completions"
19351
19641
  },
19352
19642
  "openrouter/nemotron-3-ultra-550b-a55b": {
19353
19643
  providerModelName: "nvidia/nemotron-3-ultra-550b-a55b",
@@ -19394,7 +19684,8 @@ var catalog_default4 = {
19394
19684
  family: "nemotron",
19395
19685
  version: "3",
19396
19686
  status: "stable",
19397
- active: true
19687
+ active: true,
19688
+ wireSpec: "openai/chat-completions"
19398
19689
  },
19399
19690
  "openrouter/nemotron-3.5-content-safety": {
19400
19691
  providerModelName: "nvidia/nemotron-3.5-content-safety:free",
@@ -19485,7 +19776,8 @@ var catalog_default4 = {
19485
19776
  family: "nova",
19486
19777
  version: "1",
19487
19778
  status: "stable",
19488
- active: true
19779
+ active: true,
19780
+ wireSpec: "openai/chat-completions"
19489
19781
  },
19490
19782
  "openrouter/nova-lite": {
19491
19783
  providerModelName: "amazon/nova-lite-v1",
@@ -19531,7 +19823,8 @@ var catalog_default4 = {
19531
19823
  family: "nova",
19532
19824
  version: "1",
19533
19825
  status: "stable",
19534
- active: true
19826
+ active: true,
19827
+ wireSpec: "openai/chat-completions"
19535
19828
  },
19536
19829
  "openrouter/nova-2-lite": {
19537
19830
  providerModelName: "amazon/nova-2-lite-v1",
@@ -19577,7 +19870,8 @@ var catalog_default4 = {
19577
19870
  family: "nova",
19578
19871
  version: "2",
19579
19872
  status: "stable",
19580
- active: true
19873
+ active: true,
19874
+ wireSpec: "openai/chat-completions"
19581
19875
  },
19582
19876
  "openrouter/nova-pro": {
19583
19877
  providerModelName: "amazon/nova-pro-v1",
@@ -19623,7 +19917,8 @@ var catalog_default4 = {
19623
19917
  family: "nova",
19624
19918
  version: "1",
19625
19919
  status: "stable",
19626
- active: true
19920
+ active: true,
19921
+ wireSpec: "openai/chat-completions"
19627
19922
  },
19628
19923
  "openrouter/nova-premier": {
19629
19924
  providerModelName: "amazon/nova-premier-v1",
@@ -19670,7 +19965,8 @@ var catalog_default4 = {
19670
19965
  family: "nova",
19671
19966
  version: "1",
19672
19967
  status: "stable",
19673
- active: true
19968
+ active: true,
19969
+ wireSpec: "openai/chat-completions"
19674
19970
  },
19675
19971
  "openrouter/command-r7b": {
19676
19972
  providerModelName: "cohere/command-r7b-12-2024",
@@ -19715,7 +20011,8 @@ var catalog_default4 = {
19715
20011
  family: "command",
19716
20012
  version: "1",
19717
20013
  status: "stable",
19718
- active: true
20014
+ active: true,
20015
+ wireSpec: "openai/chat-completions"
19719
20016
  },
19720
20017
  "openrouter/command-r": {
19721
20018
  providerModelName: "cohere/command-r-08-2024",
@@ -19760,7 +20057,8 @@ var catalog_default4 = {
19760
20057
  family: "command",
19761
20058
  version: "1",
19762
20059
  status: "legacy",
19763
- active: true
20060
+ active: true,
20061
+ wireSpec: "openai/chat-completions"
19764
20062
  },
19765
20063
  "openrouter/command-r-plus": {
19766
20064
  providerModelName: "cohere/command-r-plus-08-2024",
@@ -19805,7 +20103,8 @@ var catalog_default4 = {
19805
20103
  family: "command",
19806
20104
  version: "1",
19807
20105
  status: "legacy",
19808
- active: true
20106
+ active: true,
20107
+ wireSpec: "openai/chat-completions"
19809
20108
  },
19810
20109
  "openrouter/command-a": {
19811
20110
  providerModelName: "cohere/command-a",
@@ -19850,7 +20149,8 @@ var catalog_default4 = {
19850
20149
  family: "command",
19851
20150
  version: "1",
19852
20151
  status: "stable",
19853
- active: true
20152
+ active: true,
20153
+ wireSpec: "openai/chat-completions"
19854
20154
  },
19855
20155
  "openrouter/phi-4": {
19856
20156
  providerModelName: "microsoft/phi-4",
@@ -19895,7 +20195,8 @@ var catalog_default4 = {
19895
20195
  family: "phi",
19896
20196
  version: "4",
19897
20197
  status: "stable",
19898
- active: true
20198
+ active: true,
20199
+ wireSpec: "openai/chat-completions"
19899
20200
  },
19900
20201
  "openrouter/phi-4-mini": {
19901
20202
  providerModelName: "microsoft/phi-4-mini-instruct",
@@ -19941,7 +20242,8 @@ var catalog_default4 = {
19941
20242
  family: "phi",
19942
20243
  version: "4",
19943
20244
  status: "stable",
19944
- active: true
20245
+ active: true,
20246
+ wireSpec: "openai/chat-completions"
19945
20247
  },
19946
20248
  "openrouter/wizardlm-2-8x22b": {
19947
20249
  providerModelName: "microsoft/wizardlm-2-8x22b",
@@ -19985,7 +20287,8 @@ var catalog_default4 = {
19985
20287
  ],
19986
20288
  family: "wizardlm",
19987
20289
  version: "2",
19988
- active: true
20290
+ active: true,
20291
+ wireSpec: "openai/chat-completions"
19989
20292
  },
19990
20293
  "openrouter/sonar": {
19991
20294
  providerModelName: "perplexity/sonar",
@@ -20215,7 +20518,8 @@ var catalog_default4 = {
20215
20518
  family: "hermes",
20216
20519
  version: "3",
20217
20520
  status: "legacy",
20218
- active: true
20521
+ active: true,
20522
+ wireSpec: "openai/chat-completions"
20219
20523
  },
20220
20524
  "openrouter/hermes-3-405b": {
20221
20525
  providerModelName: "nousresearch/hermes-3-llama-3.1-405b",
@@ -20261,7 +20565,8 @@ var catalog_default4 = {
20261
20565
  family: "hermes",
20262
20566
  version: "3",
20263
20567
  status: "legacy",
20264
- active: true
20568
+ active: true,
20569
+ wireSpec: "openai/chat-completions"
20265
20570
  },
20266
20571
  "openrouter/hermes-4-70b": {
20267
20572
  providerModelName: "nousresearch/hermes-4-70b",
@@ -20305,7 +20610,8 @@ var catalog_default4 = {
20305
20610
  family: "hermes",
20306
20611
  version: "4",
20307
20612
  status: "stable",
20308
- active: true
20613
+ active: true,
20614
+ wireSpec: "openai/chat-completions"
20309
20615
  },
20310
20616
  "openrouter/hermes-4-405b": {
20311
20617
  providerModelName: "nousresearch/hermes-4-405b",
@@ -20349,7 +20655,8 @@ var catalog_default4 = {
20349
20655
  family: "hermes",
20350
20656
  version: "4",
20351
20657
  status: "stable",
20352
- active: true
20658
+ active: true,
20659
+ wireSpec: "openai/chat-completions"
20353
20660
  },
20354
20661
  "openrouter/seed-1.6": {
20355
20662
  providerModelName: "bytedance-seed/seed-1.6",
@@ -20396,7 +20703,8 @@ var catalog_default4 = {
20396
20703
  family: "seed",
20397
20704
  version: "1.6",
20398
20705
  status: "stable",
20399
- active: true
20706
+ active: true,
20707
+ wireSpec: "openai/chat-completions"
20400
20708
  },
20401
20709
  "openrouter/seed-2.0-lite": {
20402
20710
  providerModelName: "bytedance-seed/seed-2.0-lite",
@@ -20442,7 +20750,8 @@ var catalog_default4 = {
20442
20750
  family: "seed",
20443
20751
  version: "2.0",
20444
20752
  status: "stable",
20445
- active: true
20753
+ active: true,
20754
+ wireSpec: "openai/chat-completions"
20446
20755
  },
20447
20756
  "openrouter/seed-2.0-mini": {
20448
20757
  providerModelName: "bytedance-seed/seed-2.0-mini",
@@ -20488,7 +20797,8 @@ var catalog_default4 = {
20488
20797
  family: "seed",
20489
20798
  version: "2.0",
20490
20799
  status: "stable",
20491
- active: true
20800
+ active: true,
20801
+ wireSpec: "openai/chat-completions"
20492
20802
  },
20493
20803
  "openrouter/ui-tars-1.5-7b": {
20494
20804
  providerModelName: "bytedance/ui-tars-1.5-7b",
@@ -20580,7 +20890,8 @@ var catalog_default4 = {
20580
20890
  family: "jamba",
20581
20891
  version: "1.7",
20582
20892
  status: "stable",
20583
- active: true
20893
+ active: true,
20894
+ wireSpec: "openai/chat-completions"
20584
20895
  },
20585
20896
  "openrouter/aion-1.0": {
20586
20897
  providerModelName: "aion-labs/aion-1.0",
@@ -20626,7 +20937,8 @@ var catalog_default4 = {
20626
20937
  family: "aion",
20627
20938
  version: "1.0",
20628
20939
  status: "legacy",
20629
- active: true
20940
+ active: true,
20941
+ wireSpec: "openai/chat-completions"
20630
20942
  },
20631
20943
  "openrouter/aion-2.0": {
20632
20944
  providerModelName: "aion-labs/aion-2.0",
@@ -20672,7 +20984,8 @@ var catalog_default4 = {
20672
20984
  family: "aion",
20673
20985
  version: "2.0",
20674
20986
  status: "stable",
20675
- active: true
20987
+ active: true,
20988
+ wireSpec: "openai/chat-completions"
20676
20989
  },
20677
20990
  "openrouter/olmo-3-32b-think": {
20678
20991
  providerModelName: "allenai/olmo-3-32b-think",
@@ -20717,7 +21030,8 @@ var catalog_default4 = {
20717
21030
  family: "olmo",
20718
21031
  version: "3",
20719
21032
  status: "stable",
20720
- active: true
21033
+ active: true,
21034
+ wireSpec: "openai/chat-completions"
20721
21035
  },
20722
21036
  "openrouter/trinity-large-thinking": {
20723
21037
  providerModelName: "arcee-ai/trinity-large-thinking",
@@ -20763,7 +21077,8 @@ var catalog_default4 = {
20763
21077
  family: "trinity",
20764
21078
  version: "1",
20765
21079
  status: "stable",
20766
- active: true
21080
+ active: true,
21081
+ wireSpec: "openai/chat-completions"
20767
21082
  },
20768
21083
  "openrouter/trinity-mini": {
20769
21084
  providerModelName: "arcee-ai/trinity-mini",
@@ -20808,7 +21123,8 @@ var catalog_default4 = {
20808
21123
  family: "trinity",
20809
21124
  version: "1",
20810
21125
  status: "stable",
20811
- active: true
21126
+ active: true,
21127
+ wireSpec: "openai/chat-completions"
20812
21128
  },
20813
21129
  "openrouter/virtuoso-large": {
20814
21130
  providerModelName: "arcee-ai/virtuoso-large",
@@ -20853,7 +21169,8 @@ var catalog_default4 = {
20853
21169
  family: "virtuoso",
20854
21170
  version: "1",
20855
21171
  status: "stable",
20856
- active: true
21172
+ active: true,
21173
+ wireSpec: "openai/chat-completions"
20857
21174
  },
20858
21175
  "openrouter/coder-large": {
20859
21176
  providerModelName: "arcee-ai/coder-large",
@@ -20987,7 +21304,8 @@ var catalog_default4 = {
20987
21304
  family: "cogito",
20988
21305
  version: "2.1",
20989
21306
  status: "stable",
20990
- active: true
21307
+ active: true,
21308
+ wireSpec: "openai/chat-completions"
20991
21309
  },
20992
21310
  "openrouter/rnj-1": {
20993
21311
  providerModelName: "essentialai/rnj-1-instruct",
@@ -21031,7 +21349,8 @@ var catalog_default4 = {
21031
21349
  family: "rnj",
21032
21350
  version: "1",
21033
21351
  status: "stable",
21034
- active: true
21352
+ active: true,
21353
+ wireSpec: "openai/chat-completions"
21035
21354
  },
21036
21355
  "openrouter/granite-4.0-h-micro": {
21037
21356
  providerModelName: "ibm-granite/granite-4.0-h-micro",
@@ -21076,7 +21395,8 @@ var catalog_default4 = {
21076
21395
  family: "granite",
21077
21396
  version: "4.0",
21078
21397
  status: "stable",
21079
- active: true
21398
+ active: true,
21399
+ wireSpec: "openai/chat-completions"
21080
21400
  },
21081
21401
  "openrouter/granite-4.1-8b": {
21082
21402
  providerModelName: "ibm-granite/granite-4.1-8b",
@@ -21122,7 +21442,8 @@ var catalog_default4 = {
21122
21442
  family: "granite",
21123
21443
  version: "4.1",
21124
21444
  status: "stable",
21125
- active: true
21445
+ active: true,
21446
+ wireSpec: "openai/chat-completions"
21126
21447
  },
21127
21448
  "openrouter/mercury-2": {
21128
21449
  providerModelName: "inception/mercury-2",
@@ -21168,7 +21489,8 @@ var catalog_default4 = {
21168
21489
  family: "mercury",
21169
21490
  version: "2",
21170
21491
  status: "stable",
21171
- active: true
21492
+ active: true,
21493
+ wireSpec: "openai/chat-completions"
21172
21494
  },
21173
21495
  "openrouter/ling-2.6-1t": {
21174
21496
  providerModelName: "inclusionai/ling-2.6-1t",
@@ -21214,7 +21536,8 @@ var catalog_default4 = {
21214
21536
  family: "ling",
21215
21537
  version: "2.6",
21216
21538
  status: "stable",
21217
- active: true
21539
+ active: true,
21540
+ wireSpec: "openai/chat-completions"
21218
21541
  },
21219
21542
  "openrouter/ling-2.6-flash": {
21220
21543
  providerModelName: "inclusionai/ling-2.6-flash",
@@ -21260,7 +21583,8 @@ var catalog_default4 = {
21260
21583
  family: "ling",
21261
21584
  version: "2.6",
21262
21585
  status: "stable",
21263
- active: true
21586
+ active: true,
21587
+ wireSpec: "openai/chat-completions"
21264
21588
  },
21265
21589
  "openrouter/ring-2.6-1t": {
21266
21590
  providerModelName: "inclusionai/ring-2.6-1t",
@@ -21306,7 +21630,8 @@ var catalog_default4 = {
21306
21630
  family: "ring",
21307
21631
  version: "2.6",
21308
21632
  status: "stable",
21309
- active: true
21633
+ active: true,
21634
+ wireSpec: "openai/chat-completions"
21310
21635
  },
21311
21636
  "openrouter/inflection-3-pi": {
21312
21637
  providerModelName: "inflection/inflection-3-pi",
@@ -21351,7 +21676,8 @@ var catalog_default4 = {
21351
21676
  family: "inflection",
21352
21677
  version: "3",
21353
21678
  status: "stable",
21354
- active: true
21679
+ active: true,
21680
+ wireSpec: "openai/chat-completions"
21355
21681
  },
21356
21682
  "openrouter/inflection-3-productivity": {
21357
21683
  providerModelName: "inflection/inflection-3-productivity",
@@ -21396,7 +21722,8 @@ var catalog_default4 = {
21396
21722
  family: "inflection",
21397
21723
  version: "3",
21398
21724
  status: "stable",
21399
- active: true
21725
+ active: true,
21726
+ wireSpec: "openai/chat-completions"
21400
21727
  },
21401
21728
  "openrouter/lfm-2-24b-a2b": {
21402
21729
  providerModelName: "liquid/lfm-2-24b-a2b",
@@ -21440,7 +21767,8 @@ var catalog_default4 = {
21440
21767
  family: "lfm",
21441
21768
  version: "2",
21442
21769
  status: "stable",
21443
- active: true
21770
+ active: true,
21771
+ wireSpec: "openai/chat-completions"
21444
21772
  },
21445
21773
  "openrouter/lfm-2.5-1.2b": {
21446
21774
  providerModelName: "liquid/lfm-2.5-1.2b-instruct:free",
@@ -21485,7 +21813,8 @@ var catalog_default4 = {
21485
21813
  family: "lfm",
21486
21814
  version: "2.5",
21487
21815
  status: "stable",
21488
- active: true
21816
+ active: true,
21817
+ wireSpec: "openai/chat-completions"
21489
21818
  },
21490
21819
  "openrouter/perceptron-mk1": {
21491
21820
  providerModelName: "perceptron/perceptron-mk1",
@@ -21531,7 +21860,8 @@ var catalog_default4 = {
21531
21860
  family: "perceptron",
21532
21861
  version: "1",
21533
21862
  status: "stable",
21534
- active: true
21863
+ active: true,
21864
+ wireSpec: "openai/chat-completions"
21535
21865
  },
21536
21866
  "openrouter/intellect-3": {
21537
21867
  providerModelName: "prime-intellect/intellect-3",
@@ -21576,7 +21906,8 @@ var catalog_default4 = {
21576
21906
  family: "intellect",
21577
21907
  version: "3",
21578
21908
  status: "stable",
21579
- active: true
21909
+ active: true,
21910
+ wireSpec: "openai/chat-completions"
21580
21911
  },
21581
21912
  "openrouter/reka-edge": {
21582
21913
  providerModelName: "rekaai/reka-edge",
@@ -21622,7 +21953,8 @@ var catalog_default4 = {
21622
21953
  family: "reka",
21623
21954
  version: "1",
21624
21955
  status: "legacy",
21625
- active: true
21956
+ active: true,
21957
+ wireSpec: "openai/chat-completions"
21626
21958
  },
21627
21959
  "openrouter/reka-flash-3": {
21628
21960
  providerModelName: "rekaai/reka-flash-3",
@@ -21667,7 +21999,8 @@ var catalog_default4 = {
21667
21999
  family: "reka",
21668
22000
  version: "3",
21669
22001
  status: "stable",
21670
- active: true
22002
+ active: true,
22003
+ wireSpec: "openai/chat-completions"
21671
22004
  },
21672
22005
  "openrouter/step-3.5-flash": {
21673
22006
  providerModelName: "stepfun/step-3.5-flash",
@@ -21713,7 +22046,8 @@ var catalog_default4 = {
21713
22046
  family: "step",
21714
22047
  version: "3.5",
21715
22048
  status: "stable",
21716
- active: true
22049
+ active: true,
22050
+ wireSpec: "openai/chat-completions"
21717
22051
  },
21718
22052
  "openrouter/step-3.7-flash": {
21719
22053
  providerModelName: "stepfun/step-3.7-flash",
@@ -21760,7 +22094,8 @@ var catalog_default4 = {
21760
22094
  family: "step",
21761
22095
  version: "3.7",
21762
22096
  status: "stable",
21763
- active: true
22097
+ active: true,
22098
+ wireSpec: "openai/chat-completions"
21764
22099
  },
21765
22100
  "openrouter/hunyuan-a13b": {
21766
22101
  providerModelName: "tencent/hunyuan-a13b-instruct",
@@ -21805,7 +22140,8 @@ var catalog_default4 = {
21805
22140
  family: "hunyuan",
21806
22141
  version: "1",
21807
22142
  status: "stable",
21808
- active: true
22143
+ active: true,
22144
+ wireSpec: "openai/chat-completions"
21809
22145
  },
21810
22146
  "openrouter/hunyuan-hy3": {
21811
22147
  providerModelName: "tencent/hy3",
@@ -21852,7 +22188,8 @@ var catalog_default4 = {
21852
22188
  family: "hunyuan",
21853
22189
  version: "3",
21854
22190
  status: "preview",
21855
- active: true
22191
+ active: true,
22192
+ wireSpec: "openai/chat-completions"
21856
22193
  },
21857
22194
  "openrouter/solar-pro-3": {
21858
22195
  providerModelName: "upstage/solar-pro-3",
@@ -21897,7 +22234,8 @@ var catalog_default4 = {
21897
22234
  family: "solar",
21898
22235
  version: "3",
21899
22236
  status: "stable",
21900
- active: true
22237
+ active: true,
22238
+ wireSpec: "openai/chat-completions"
21901
22239
  },
21902
22240
  "openrouter/palmyra-x5": {
21903
22241
  providerModelName: "writer/palmyra-x5",
@@ -21942,7 +22280,8 @@ var catalog_default4 = {
21942
22280
  family: "palmyra",
21943
22281
  version: "5",
21944
22282
  status: "stable",
21945
- active: true
22283
+ active: true,
22284
+ wireSpec: "openai/chat-completions"
21946
22285
  },
21947
22286
  "openrouter/mimo-v2-flash": {
21948
22287
  providerModelName: "xiaomi/mimo-v2-flash",
@@ -21988,7 +22327,8 @@ var catalog_default4 = {
21988
22327
  family: "mimo",
21989
22328
  version: "2",
21990
22329
  status: "stable",
21991
- active: true
22330
+ active: true,
22331
+ wireSpec: "openai/chat-completions"
21992
22332
  },
21993
22333
  "openrouter/mimo-v2.5": {
21994
22334
  providerModelName: "xiaomi/mimo-v2.5",
@@ -22036,7 +22376,8 @@ var catalog_default4 = {
22036
22376
  family: "mimo",
22037
22377
  version: "2.5",
22038
22378
  status: "stable",
22039
- active: true
22379
+ active: true,
22380
+ wireSpec: "openai/chat-completions"
22040
22381
  },
22041
22382
  "openrouter/mimo-v2.5-pro": {
22042
22383
  providerModelName: "xiaomi/mimo-v2.5-pro",
@@ -22082,7 +22423,8 @@ var catalog_default4 = {
22082
22423
  family: "mimo",
22083
22424
  version: "2.5",
22084
22425
  status: "stable",
22085
- active: true
22426
+ active: true,
22427
+ wireSpec: "openai/chat-completions"
22086
22428
  },
22087
22429
  "openrouter/nex-n2-pro": {
22088
22430
  providerModelName: "nex-agi/nex-n2-pro:free",
@@ -22130,7 +22472,8 @@ var catalog_default4 = {
22130
22472
  family: "nex",
22131
22473
  version: "2",
22132
22474
  status: "stable",
22133
- active: true
22475
+ active: true,
22476
+ wireSpec: "openai/chat-completions"
22134
22477
  },
22135
22478
  "openrouter/kat-coder-pro-v2": {
22136
22479
  providerModelName: "kwaipilot/kat-coder-pro-v2",
@@ -22316,7 +22659,8 @@ var catalog_default4 = {
22316
22659
  family: "roleplay-finetunes",
22317
22660
  version: "1",
22318
22661
  status: "stable",
22319
- active: true
22662
+ active: true,
22663
+ wireSpec: "openai/chat-completions"
22320
22664
  },
22321
22665
  "openrouter/magnum-v4-72b": {
22322
22666
  providerModelName: "anthracite-org/magnum-v4-72b",
@@ -22361,7 +22705,8 @@ var catalog_default4 = {
22361
22705
  family: "roleplay-finetunes",
22362
22706
  version: "4",
22363
22707
  status: "stable",
22364
- active: true
22708
+ active: true,
22709
+ wireSpec: "openai/chat-completions"
22365
22710
  },
22366
22711
  "openrouter/dolphin-mistral-24b-venice": {
22367
22712
  providerModelName: "cognitivecomputations/dolphin-mistral-24b-venice-edition:free",
@@ -22411,7 +22756,8 @@ var catalog_default4 = {
22411
22756
  shutdownDate: "2026-07-19",
22412
22757
  source: "openrouter"
22413
22758
  },
22414
- maxOutput: 8192
22759
+ maxOutput: 8192,
22760
+ wireSpec: "openai/chat-completions"
22415
22761
  },
22416
22762
  "openrouter/mythomax-l2-13b": {
22417
22763
  providerModelName: "gryphe/mythomax-l2-13b",
@@ -22456,7 +22802,8 @@ var catalog_default4 = {
22456
22802
  family: "roleplay-finetunes",
22457
22803
  version: "2",
22458
22804
  status: "legacy",
22459
- active: true
22805
+ active: true,
22806
+ wireSpec: "openai/chat-completions"
22460
22807
  },
22461
22808
  "openrouter/weaver": {
22462
22809
  providerModelName: "mancer/weaver",
@@ -22501,7 +22848,8 @@ var catalog_default4 = {
22501
22848
  family: "roleplay-finetunes",
22502
22849
  version: "1",
22503
22850
  status: "legacy",
22504
- active: true
22851
+ active: true,
22852
+ wireSpec: "openai/chat-completions"
22505
22853
  },
22506
22854
  "openrouter/lunaris-8b": {
22507
22855
  providerModelName: "sao10k/l3-lunaris-8b",
@@ -22546,7 +22894,8 @@ var catalog_default4 = {
22546
22894
  family: "roleplay-finetunes",
22547
22895
  version: "3",
22548
22896
  status: "stable",
22549
- active: true
22897
+ active: true,
22898
+ wireSpec: "openai/chat-completions"
22550
22899
  },
22551
22900
  "openrouter/euryale-70b": {
22552
22901
  providerModelName: "sao10k/l3.1-euryale-70b",
@@ -22593,7 +22942,8 @@ var catalog_default4 = {
22593
22942
  family: "roleplay-finetunes",
22594
22943
  version: "3.1",
22595
22944
  status: "stable",
22596
- active: true
22945
+ active: true,
22946
+ wireSpec: "openai/chat-completions"
22597
22947
  },
22598
22948
  "openrouter/cydonia-24b-v4.1": {
22599
22949
  providerModelName: "thedrummer/cydonia-24b-v4.1",
@@ -22639,7 +22989,8 @@ var catalog_default4 = {
22639
22989
  family: "roleplay-finetunes",
22640
22990
  version: "4.1",
22641
22991
  status: "stable",
22642
- active: true
22992
+ active: true,
22993
+ wireSpec: "openai/chat-completions"
22643
22994
  },
22644
22995
  "openrouter/rocinante-12b": {
22645
22996
  providerModelName: "thedrummer/rocinante-12b",
@@ -22684,7 +23035,8 @@ var catalog_default4 = {
22684
23035
  family: "roleplay-finetunes",
22685
23036
  version: "1",
22686
23037
  status: "stable",
22687
- active: true
23038
+ active: true,
23039
+ wireSpec: "openai/chat-completions"
22688
23040
  },
22689
23041
  "openrouter/skyfall-36b-v2": {
22690
23042
  providerModelName: "thedrummer/skyfall-36b-v2",
@@ -22730,7 +23082,8 @@ var catalog_default4 = {
22730
23082
  family: "roleplay-finetunes",
22731
23083
  version: "2",
22732
23084
  status: "stable",
22733
- active: true
23085
+ active: true,
23086
+ wireSpec: "openai/chat-completions"
22734
23087
  },
22735
23088
  "openrouter/unslopnemo-12b": {
22736
23089
  providerModelName: "thedrummer/unslopnemo-12b",
@@ -22775,7 +23128,8 @@ var catalog_default4 = {
22775
23128
  family: "roleplay-finetunes",
22776
23129
  version: "1",
22777
23130
  status: "stable",
22778
- active: true
23131
+ active: true,
23132
+ wireSpec: "openai/chat-completions"
22779
23133
  },
22780
23134
  "openrouter/remm-slerp-l2-13b": {
22781
23135
  providerModelName: "undi95/remm-slerp-l2-13b",
@@ -22820,7 +23174,8 @@ var catalog_default4 = {
22820
23174
  family: "roleplay-finetunes",
22821
23175
  version: "2",
22822
23176
  status: "legacy",
22823
- active: true
23177
+ active: true,
23178
+ wireSpec: "openai/chat-completions"
22824
23179
  },
22825
23180
  "openrouter/claude-sonnet-5": {
22826
23181
  providerModelName: "anthropic/claude-sonnet-5",
@@ -22867,7 +23222,8 @@ var catalog_default4 = {
22867
23222
  family: "claude-sonnet",
22868
23223
  version: "5",
22869
23224
  status: "stable",
22870
- active: true
23225
+ active: true,
23226
+ wireSpec: "openai/chat-completions"
22871
23227
  },
22872
23228
  "openrouter/gpt-5.6-luna": {
22873
23229
  providerModelName: "openai/gpt-5.6-luna",
@@ -22914,7 +23270,8 @@ var catalog_default4 = {
22914
23270
  family: "gpt",
22915
23271
  version: "5.6",
22916
23272
  status: "stable",
22917
- active: true
23273
+ active: true,
23274
+ wireSpec: "openai/chat-completions"
22918
23275
  },
22919
23276
  "openrouter/gpt-5.6-terra": {
22920
23277
  providerModelName: "openai/gpt-5.6-terra",
@@ -22961,7 +23318,8 @@ var catalog_default4 = {
22961
23318
  family: "gpt",
22962
23319
  version: "5.6",
22963
23320
  status: "stable",
22964
- active: true
23321
+ active: true,
23322
+ wireSpec: "openai/chat-completions"
22965
23323
  },
22966
23324
  "openrouter/gpt-5.6-sol": {
22967
23325
  providerModelName: "openai/gpt-5.6-sol",
@@ -23008,7 +23366,8 @@ var catalog_default4 = {
23008
23366
  family: "gpt",
23009
23367
  version: "5.6",
23010
23368
  status: "stable",
23011
- active: true
23369
+ active: true,
23370
+ wireSpec: "openai/chat-completions"
23012
23371
  },
23013
23372
  "openrouter/gpt-5.6-luna-pro": {
23014
23373
  providerModelName: "openai/gpt-5.6-luna-pro",
@@ -23055,7 +23414,8 @@ var catalog_default4 = {
23055
23414
  family: "gpt-pro",
23056
23415
  version: "5.6",
23057
23416
  status: "stable",
23058
- active: true
23417
+ active: true,
23418
+ wireSpec: "openai/chat-completions"
23059
23419
  },
23060
23420
  "openrouter/gpt-5.6-terra-pro": {
23061
23421
  providerModelName: "openai/gpt-5.6-terra-pro",
@@ -23102,7 +23462,8 @@ var catalog_default4 = {
23102
23462
  family: "gpt-pro",
23103
23463
  version: "5.6",
23104
23464
  status: "stable",
23105
- active: true
23465
+ active: true,
23466
+ wireSpec: "openai/chat-completions"
23106
23467
  },
23107
23468
  "openrouter/gpt-5.6-sol-pro": {
23108
23469
  providerModelName: "openai/gpt-5.6-sol-pro",
@@ -23149,7 +23510,8 @@ var catalog_default4 = {
23149
23510
  family: "gpt-pro",
23150
23511
  version: "5.6",
23151
23512
  status: "stable",
23152
- active: true
23513
+ active: true,
23514
+ wireSpec: "openai/chat-completions"
23153
23515
  },
23154
23516
  "openrouter/gemini-3.1-flash-lite-image": {
23155
23517
  providerModelName: "google/gemini-3.1-flash-lite-image",
@@ -23266,7 +23628,8 @@ var catalog_default4 = {
23266
23628
  family: "grok",
23267
23629
  version: "4.5",
23268
23630
  status: "stable",
23269
- active: true
23631
+ active: true,
23632
+ wireSpec: "openai/chat-completions"
23270
23633
  },
23271
23634
  "openrouter/glm-5.2": {
23272
23635
  providerModelName: "z-ai/glm-5.2",
@@ -23312,7 +23675,8 @@ var catalog_default4 = {
23312
23675
  family: "glm",
23313
23676
  version: "5.2",
23314
23677
  status: "stable",
23315
- active: true
23678
+ active: true,
23679
+ wireSpec: "openai/chat-completions"
23316
23680
  },
23317
23681
  "openrouter/glm-5v-turbo": {
23318
23682
  providerModelName: "z-ai/glm-5v-turbo",
@@ -23409,7 +23773,8 @@ var catalog_default4 = {
23409
23773
  family: "aion",
23410
23774
  version: "3.0",
23411
23775
  status: "stable",
23412
- active: true
23776
+ active: true,
23777
+ wireSpec: "openai/chat-completions"
23413
23778
  },
23414
23779
  "openrouter/aion-3.0": {
23415
23780
  providerModelName: "aion-labs/aion-3.0",
@@ -23455,7 +23820,8 @@ var catalog_default4 = {
23455
23820
  family: "aion",
23456
23821
  version: "3.0",
23457
23822
  status: "stable",
23458
- active: true
23823
+ active: true,
23824
+ wireSpec: "openai/chat-completions"
23459
23825
  },
23460
23826
  "openrouter/nex-n2-mini": {
23461
23827
  providerModelName: "nex-agi/nex-n2-mini",
@@ -23502,7 +23868,8 @@ var catalog_default4 = {
23502
23868
  family: "nex",
23503
23869
  version: "2",
23504
23870
  status: "stable",
23505
- active: true
23871
+ active: true,
23872
+ wireSpec: "openai/chat-completions"
23506
23873
  },
23507
23874
  "openrouter/laguna-xs.2.1": {
23508
23875
  providerModelName: "poolside/laguna-xs-2.1",
@@ -23597,7 +23964,8 @@ var catalog_default4 = {
23597
23964
  family: "fugu",
23598
23965
  version: "1",
23599
23966
  status: "stable",
23600
- active: true
23967
+ active: true,
23968
+ wireSpec: "openai/chat-completions"
23601
23969
  },
23602
23970
  "openrouter/north-mini-code": {
23603
23971
  providerModelName: "cohere/north-mini-code:free",
@@ -23780,7 +24148,8 @@ var catalog_default4 = {
23780
24148
  family: "claude-opus",
23781
24149
  version: "5",
23782
24150
  status: "stable",
23783
- active: true
24151
+ active: true,
24152
+ wireSpec: "openai/chat-completions"
23784
24153
  },
23785
24154
  "openrouter/claude-opus-5": {
23786
24155
  providerModelName: "anthropic/claude-opus-5",
@@ -23827,7 +24196,8 @@ var catalog_default4 = {
23827
24196
  family: "claude-opus",
23828
24197
  version: "5",
23829
24198
  status: "stable",
23830
- active: true
24199
+ active: true,
24200
+ wireSpec: "openai/chat-completions"
23831
24201
  },
23832
24202
  "openrouter/gemini-3.6-flash": {
23833
24203
  providerModelName: "google/gemini-3.6-flash",
@@ -23875,7 +24245,8 @@ var catalog_default4 = {
23875
24245
  family: "gemini-flash",
23876
24246
  version: "3.6",
23877
24247
  status: "stable",
23878
- active: true
24248
+ active: true,
24249
+ wireSpec: "openai/chat-completions"
23879
24250
  },
23880
24251
  "openrouter/gemini-3.5-flash-lite": {
23881
24252
  providerModelName: "google/gemini-3.5-flash-lite",
@@ -23923,7 +24294,8 @@ var catalog_default4 = {
23923
24294
  family: "gemini-flash-lite",
23924
24295
  version: "3.5",
23925
24296
  status: "stable",
23926
- active: true
24297
+ active: true,
24298
+ wireSpec: "openai/chat-completions"
23927
24299
  },
23928
24300
  "openrouter/kimi-k3": {
23929
24301
  providerModelName: "moonshotai/kimi-k3",
@@ -23969,7 +24341,8 @@ var catalog_default4 = {
23969
24341
  family: "kimi",
23970
24342
  version: "3",
23971
24343
  status: "stable",
23972
- active: true
24344
+ active: true,
24345
+ wireSpec: "openai/chat-completions"
23973
24346
  },
23974
24347
  "openrouter/ling-3.0-flash": {
23975
24348
  providerModelName: "inclusionai/ling-3.0-flash:free",
@@ -24014,7 +24387,8 @@ var catalog_default4 = {
24014
24387
  family: "ling",
24015
24388
  version: "3.0",
24016
24389
  status: "stable",
24017
- active: true
24390
+ active: true,
24391
+ wireSpec: "openai/chat-completions"
24018
24392
  },
24019
24393
  "openrouter/kat-coder-air-v2.5": {
24020
24394
  providerModelName: "kwaipilot/kat-coder-air-v2.5",
@@ -24199,7 +24573,8 @@ var catalog_default4 = {
24199
24573
  family: "longcat",
24200
24574
  version: "2.0",
24201
24575
  status: "stable",
24202
- active: true
24576
+ active: true,
24577
+ wireSpec: "openai/chat-completions"
24203
24578
  },
24204
24579
  "openrouter/inkling": {
24205
24580
  providerModelName: "thinkingmachines/inkling",
@@ -24246,7 +24621,8 @@ var catalog_default4 = {
24246
24621
  family: "inkling",
24247
24622
  version: "1",
24248
24623
  status: "stable",
24249
- active: true
24624
+ active: true,
24625
+ wireSpec: "openai/chat-completions"
24250
24626
  },
24251
24627
  "openrouter/muse-spark-1.1": {
24252
24628
  providerModelName: "meta/muse-spark-1.1",
@@ -24323,8 +24699,8 @@ var catalog_default4 = {
24323
24699
  }
24324
24700
  };
24325
24701
 
24326
- // src/llm/providers/xai/catalog.json
24327
- var catalog_default5 = {
24702
+ // src/catalog/data/xai.json
24703
+ var xai_default = {
24328
24704
  "xai/grok-4.20": {
24329
24705
  providerModelName: "grok-4.20-0309-reasoning",
24330
24706
  aliases: [
@@ -24378,7 +24754,8 @@ var catalog_default5 = {
24378
24754
  family: "grok",
24379
24755
  version: "4.20",
24380
24756
  status: "stable",
24381
- active: true
24757
+ active: true,
24758
+ wireSpec: "openai/responses"
24382
24759
  },
24383
24760
  "xai/grok-4.20-non-reasoning": {
24384
24761
  providerModelName: "grok-4.20-0309-non-reasoning",
@@ -24432,7 +24809,8 @@ var catalog_default5 = {
24432
24809
  version: "4.20",
24433
24810
  status: "stable",
24434
24811
  active: true,
24435
- contextWindow: 2e6
24812
+ contextWindow: 2e6,
24813
+ wireSpec: "openai/responses"
24436
24814
  },
24437
24815
  "xai/grok-4.20-multi-agent": {
24438
24816
  providerModelName: "grok-4.20-multi-agent-0309",
@@ -24485,7 +24863,8 @@ var catalog_default5 = {
24485
24863
  family: "grok",
24486
24864
  version: "4.20",
24487
24865
  status: "stable",
24488
- active: true
24866
+ active: true,
24867
+ wireSpec: "openai/responses"
24489
24868
  },
24490
24869
  "xai/grok-4.3": {
24491
24870
  providerModelName: "grok-4.3",
@@ -24540,7 +24919,8 @@ var catalog_default5 = {
24540
24919
  family: "grok",
24541
24920
  version: "4.3",
24542
24921
  status: "stable",
24543
- active: true
24922
+ active: true,
24923
+ wireSpec: "openai/responses"
24544
24924
  },
24545
24925
  "xai/grok-build-0.1": {
24546
24926
  providerModelName: "grok-build-0.1",
@@ -24948,11 +25328,12 @@ var catalog_default5 = {
24948
25328
  family: "grok",
24949
25329
  version: "4.5",
24950
25330
  status: "stable",
24951
- active: true
25331
+ active: true,
25332
+ wireSpec: "openai/responses"
24952
25333
  }
24953
25334
  };
24954
25335
 
24955
- // src/llm/providers/builtin-tools.ts
25336
+ // src/catalog/builtin-tools.ts
24956
25337
  var PROVIDER_BUILTIN_TOOLS = {
24957
25338
  anthropic: ["web_search", "web_fetch", "code_interpreter"],
24958
25339
  openai: ["web_search", "code_interpreter"],
@@ -24961,13 +25342,13 @@ var PROVIDER_BUILTIN_TOOLS = {
24961
25342
  openrouter: ["web_search"]
24962
25343
  };
24963
25344
 
24964
- // src/plugins/model-catalog/catalog.ts
25345
+ // src/catalog/catalog.ts
24965
25346
  var PROVIDER_DEFAULT_CATALOGS = [
24966
- catalog_default,
24967
- catalog_default3,
24968
- catalog_default2,
24969
- catalog_default5,
24970
- catalog_default4
25347
+ anthropic_default,
25348
+ openai_default,
25349
+ google_default,
25350
+ xai_default,
25351
+ openrouter_default
24971
25352
  ];
24972
25353
  var PROVIDER_STATE = {
24973
25354
  // OpenAI/xAI: previous_response_id survives most model swaps but can break at
@@ -25029,6 +25410,8 @@ var ModelCatalog = class {
25029
25410
  tokenizer: info.tokenizer,
25030
25411
  requiresDedicatedClient: info.requiresDedicatedClient,
25031
25412
  supportsPreviousResponseId: info.supportsPreviousResponseId,
25413
+ wire: info.wire,
25414
+ wireSpec: info.wireSpec,
25032
25415
  stateRetentionDuration: info.stateRetentionDuration,
25033
25416
  stateModelBound: info.stateModelBound,
25034
25417
  providerModelName: info.providerModelName,
@@ -25562,9 +25945,9 @@ function buildContext(client, options) {
25562
25945
  ...provided,
25563
25946
  sessionId: provided.sessionId ?? client.sessionId,
25564
25947
  clientId: provided.clientId ?? client.id,
25565
- queueName: provided.queueName ?? client.queueName,
25566
- configName: options.configName ?? provided.configName ?? client.configName,
25567
- cacheName: options.cacheName ?? provided.cacheName ?? client.cacheName,
25948
+ queueName: provided.queueName ?? client.routing.queueName,
25949
+ configName: options.configName ?? provided.configName ?? client.routing.configName,
25950
+ cacheName: options.cacheName ?? provided.cacheName ?? client.routing.cacheName,
25568
25951
  cacheKey: options.cacheKey ?? provided.cacheKey
25569
25952
  };
25570
25953
  if (!ctx.callId) ctx.callId = `call_${crypto.randomUUID().slice(0, 8)}`;
@@ -25617,6 +26000,9 @@ var LLMClient = class {
25617
26000
  queueName;
25618
26001
  configName;
25619
26002
  cacheName;
26003
+ /** The routing names this client was configured with, exposed so context
26004
+ * building does not have to cast into the privates above. */
26005
+ routing;
25620
26006
  cacheKeyFn;
25621
26007
  catalog;
25622
26008
  constructor(config) {
@@ -25646,6 +26032,11 @@ var LLMClient = class {
25646
26032
  this.queueName = config.queueName ?? `${config.provider}/${config.model}`;
25647
26033
  this.configName = config.configName ?? `${config.provider}/${config.model}`;
25648
26034
  this.cacheName = config.cacheName ?? "default";
26035
+ this.routing = Object.freeze({
26036
+ queueName: this.queueName,
26037
+ configName: this.configName,
26038
+ cacheName: this.cacheName
26039
+ });
25649
26040
  this.cacheKeyFn = config.cacheKeyFn;
25650
26041
  this.catalog = config.catalog ?? new ModelCatalog();
25651
26042
  this.hooks.emitSync("onClientCreate", {
@@ -25739,6 +26130,7 @@ var LLMClient = class {
25739
26130
  const ctx = buildContext(this, options);
25740
26131
  const normalized = {
25741
26132
  model: this.model,
26133
+ wire: this.catalog.get(this.provider, this.model)?.wire,
25742
26134
  messages,
25743
26135
  system: composedSystem,
25744
26136
  maxTokens: options.maxTokens,
@@ -25911,6 +26303,7 @@ var LLMClient = class {
25911
26303
  const ctx = buildContext(this, options);
25912
26304
  const normalized = {
25913
26305
  model: this.model,
26306
+ wire: this.catalog.get(this.provider, this.model)?.wire,
25914
26307
  messages,
25915
26308
  system: composedSystem,
25916
26309
  maxTokens: options.maxTokens,
@@ -26099,7 +26492,7 @@ var DEFAULT_ANTHROPIC_THINKING_BUDGET = 2048;
26099
26492
  var ANTHROPIC_ADAPTIVE_THINKING_MIN = { major: 4, minor: 6 };
26100
26493
  function anthropicThinkingShape(model) {
26101
26494
  const id = model.toLowerCase().replace(/^anthropic\//, "");
26102
- const modern = /^claude-[a-z]+-(\d+)(?:[-.](\d+))?/.exec(id);
26495
+ const modern = /^claude-[a-z]+-(\d+)(?:[-.](\d{1,2})(?!\d))?/.exec(id);
26103
26496
  if (modern) {
26104
26497
  const major = Number(modern[1]);
26105
26498
  const minor = modern[2] === void 0 ? 0 : Number(modern[2]);
@@ -26346,6 +26739,11 @@ function extractFinishReason(hasToolCalls, providerReason, reasonMap) {
26346
26739
  return (providerReason !== void 0 ? reasonMap[providerReason] : void 0) ?? "stop";
26347
26740
  }
26348
26741
 
26742
+ // src/llm/providers/_shared/sse.ts
26743
+ function sseJson(event) {
26744
+ return JSON.parse(event.data);
26745
+ }
26746
+
26349
26747
  // src/llm/providers/anthropic/messages.ts
26350
26748
  var ANTHROPIC_REQUEST_TIER = {
26351
26749
  auto: "auto",
@@ -26436,7 +26834,7 @@ var AnthropicAdapter = class {
26436
26834
  }
26437
26835
  if (req.temperature !== void 0) body.temperature = req.temperature;
26438
26836
  if (req.topP !== void 0) body.top_p = req.topP;
26439
- if (req.topK !== void 0 && anthropicAcceptsTopK(req.model)) body.top_k = req.topK;
26837
+ if (req.topK !== void 0 && (req.wire?.topK ?? anthropicAcceptsTopK(req.model))) body.top_k = req.topK;
26440
26838
  if (req.stop) body.stop_sequences = req.stop;
26441
26839
  const tier = anthropicRequestTier(req.serviceTier);
26442
26840
  if (tier) body.service_tier = tier;
@@ -26490,7 +26888,7 @@ var AnthropicAdapter = class {
26490
26888
  }
26491
26889
  if (req.thinking) {
26492
26890
  if (req.thinking.mode === "off") {
26493
- } else if (anthropicThinkingShape(req.model) === "adaptive") {
26891
+ } else if ((req.wire?.thinking ?? anthropicThinkingShape(req.model)) === "adaptive") {
26494
26892
  const thinking = { type: "adaptive" };
26495
26893
  if (req.thinking.visibility === "hidden") thinking.display = "omitted";
26496
26894
  body.thinking = thinking;
@@ -26665,7 +27063,7 @@ var AnthropicAdapter = class {
26665
27063
  }
26666
27064
  streamEvents(event, state) {
26667
27065
  if (event.event === "ping") return [];
26668
- const data = JSON.parse(event.data);
27066
+ const data = sseJson(event);
26669
27067
  const type = data.type;
26670
27068
  if (type === "content_block_delta") {
26671
27069
  const delta = data.delta;
@@ -26877,6 +27275,11 @@ var GoogleBatchAdapter = class {
26877
27275
 
26878
27276
  // src/llm/providers/google/files.ts
26879
27277
  var FORTY_EIGHT_HOURS = 48 * 60 * 60 * 1e3;
27278
+ function googleFileName(remoteId) {
27279
+ if (remoteId.includes("/files/")) return remoteId.split("/files/").pop() ?? remoteId;
27280
+ if (remoteId.startsWith("files/")) return remoteId.slice("files/".length);
27281
+ return remoteId;
27282
+ }
26880
27283
  var GoogleFileAdapter = class {
26881
27284
  name = "google";
26882
27285
  expiresAfter = FORTY_EIGHT_HOURS;
@@ -26941,7 +27344,7 @@ var GoogleFileAdapter = class {
26941
27344
  };
26942
27345
  }
26943
27346
  async delete(remoteId, fetch2) {
26944
- const name = remoteId.includes("/files/") ? remoteId.split("/files/").pop() : remoteId;
27347
+ const name = googleFileName(remoteId);
26945
27348
  await fetch2({
26946
27349
  url: `${this.baseURL}/v1beta/files/${name}?key=${this.apiKey}`,
26947
27350
  method: "DELETE",
@@ -26953,7 +27356,7 @@ var GoogleFileAdapter = class {
26953
27356
  });
26954
27357
  }
26955
27358
  async getInfo(remoteId, fetch2) {
26956
- const name = remoteId.includes("/files/") ? remoteId.split("/files/").pop() : remoteId;
27359
+ const name = googleFileName(remoteId);
26957
27360
  const res = await fetch2({
26958
27361
  url: `${this.baseURL}/v1beta/files/${name}?key=${this.apiKey}`,
26959
27362
  method: "GET",
@@ -27103,7 +27506,30 @@ var GoogleAdapter = class {
27103
27506
  functionDeclarations: fnTools.map((t) => ({
27104
27507
  name: t.name,
27105
27508
  description: t.description,
27106
- parameters: t.parameters
27509
+ // `parametersJsonSchema`, NOT `parameters`. The two are mutually exclusive
27510
+ // (sending both is a 400) and accept different things:
27511
+ //
27512
+ // parameters a narrow OpenAPI subset. Anything outside it is
27513
+ // rejected outright with `Unknown name "<keyword>"` —
27514
+ // measured: additionalProperties (at any depth),
27515
+ // $schema, $ref, $defs, definitions, const, examples,
27516
+ // exclusiveMinimum/Maximum, multipleOf, uniqueItems,
27517
+ // patternProperties, propertyNames, if/then,
27518
+ // readOnly, deprecated, and `type` as an array.
27519
+ // parametersJsonSchema full JSON Schema.
27520
+ //
27521
+ // We passed callers' schemas straight into `parameters`, so any tool defined
27522
+ // with `additionalProperties: false` — which OpenAI's strict mode requires —
27523
+ // failed on EVERY Gemini model. A consuming app had to delete it from its
27524
+ // manifest, degrading its OpenAI schema to keep Google working.
27525
+ //
27526
+ // Sanitising into the subset was the obvious fix and is the wrong one: it
27527
+ // silently drops constraints and cannot express a `$ref` at all. Verified on
27528
+ // every tool-capable model we ship (2.5 pro/flash/flash-lite, 3-flash,
27529
+ // 3.1-pro incl. customtools, 3.1-flash-lite, 3.5-flash/-lite, 3.6-flash,
27530
+ // gemma-4-26b/-31b) that this field takes the schema unchanged and the model
27531
+ // still calls the tool.
27532
+ parametersJsonSchema: t.parameters
27107
27533
  }))
27108
27534
  });
27109
27535
  }
@@ -27127,7 +27553,8 @@ var GoogleAdapter = class {
27127
27553
  const thinkingConfig = {
27128
27554
  includeThoughts: req.thinking.visibility !== "hidden"
27129
27555
  };
27130
- if (googleUsesThinkingBudget(req.model)) {
27556
+ const usesBudget = req.wire?.thinking ? req.wire.thinking === "budget" : googleUsesThinkingBudget(req.model);
27557
+ if (usesBudget) {
27131
27558
  thinkingConfig.thinkingBudget = GOOGLE_THINKING_BUDGETS[effort] ?? GOOGLE_THINKING_BUDGETS.high;
27132
27559
  } else {
27133
27560
  thinkingConfig.thinkingLevel = GOOGLE_THINKING_LEVELS[effort] ?? "HIGH";
@@ -27354,7 +27781,7 @@ var GoogleAdapter = class {
27354
27781
  return (event) => this.streamEvents(event, state);
27355
27782
  }
27356
27783
  streamEvents(event, state) {
27357
- const data = JSON.parse(event.data);
27784
+ const data = sseJson(event);
27358
27785
  const candidates = data.candidates ?? [];
27359
27786
  const candidate = candidates[0];
27360
27787
  if (!candidate) {
@@ -27695,7 +28122,7 @@ var GoogleInteractionsAdapter = class {
27695
28122
  * function call's `arguments_delta` carries no id, so we correlate it to the
27696
28123
  * currently-open call id held in `state`. */
27697
28124
  streamEvents(event, state) {
27698
- const data = JSON.parse(event.data);
28125
+ const data = sseJson(event);
27699
28126
  const type = data.event_type ?? data.type;
27700
28127
  const events = [];
27701
28128
  if (type === "step.start") {
@@ -27789,7 +28216,7 @@ function sniffImageMime(b) {
27789
28216
  return void 0;
27790
28217
  }
27791
28218
 
27792
- // src/plugins/media/source-image.ts
28219
+ // src/util/source-image.ts
27793
28220
  function mimeFromBase64Prefix(b64) {
27794
28221
  try {
27795
28222
  const n = Math.min(24, b64.length - b64.length % 4);
@@ -27925,42 +28352,103 @@ var GoogleMediaAdapter = class {
27925
28352
  audioStreaming: false
27926
28353
  };
27927
28354
  }
27928
- async generateImage(req, fetch2) {
27929
- const model = req.model ?? "imagen-4.0-generate-001";
27930
- if (!model.startsWith("imagen")) {
27931
- const generationConfig = { responseModalities: ["IMAGE"] };
27932
- const image = {};
27933
- if (req.params?.aspectRatio) image.aspectRatio = req.params.aspectRatio;
27934
- if (req.params?.imageSize) image.imageSize = req.params.imageSize;
27935
- if (Object.keys(image).length) generationConfig.imageConfig = image;
27936
- const { items, usage } = await this.generateContentMedia(
27937
- model,
27938
- req.prompt,
27939
- generationConfig,
27940
- fetch2
27941
- );
27942
- return items.map((m, i) => ({
27943
- data: base64ToBytes(m.data),
27944
- mimeType: m.mimeType ?? "image/png",
27945
- usage: i === 0 ? usage : void 0
27946
- }));
27947
- }
28355
+ // ─── request builders ────────────────────────────────────────────────
28356
+ //
28357
+ // Split out from the methods that fetch and parse, so a request can be built,
28358
+ // inspected and asserted without performing it. Everything above this line
28359
+ // used to construct its request inline, which meant the only way to see what
28360
+ // the adapter would send was to intercept the network.
28361
+ /** Imagen image generation: the Vertex-style `:predict` envelope. */
28362
+ buildImagenRequest(req, model = req.model ?? "imagen-4.0-generate-001") {
27948
28363
  const parameters = { sampleCount: req.params?.n ?? 1 };
27949
28364
  if (req.params?.aspectRatio) parameters.aspectRatio = req.params.aspectRatio;
27950
28365
  if (req.params?.imageSize) parameters.sampleImageSize = req.params.imageSize;
27951
- const body = {
27952
- instances: [{ prompt: req.prompt }],
27953
- parameters
27954
- };
27955
- const res = await fetch2({
28366
+ return {
27956
28367
  url: `${this.baseURL}/v1beta/models/${model}:predict?key=${this.apiKey}`,
27957
28368
  method: "POST",
27958
28369
  headers: { "content-type": "application/json" },
27959
- body,
28370
+ body: { instances: [{ prompt: req.prompt }], parameters },
28371
+ provider: "google",
28372
+ model,
28373
+ responseType: "json"
28374
+ };
28375
+ }
28376
+ /** The inline-media path shared by gemini image generation, editing and TTS. */
28377
+ buildGenerateContentRequest(model, text, generationConfig, extraParts = []) {
28378
+ return {
28379
+ url: `${this.baseURL}/v1beta/models/${model}:generateContent?key=${this.apiKey}`,
28380
+ method: "POST",
28381
+ headers: { "content-type": "application/json" },
28382
+ body: { contents: [{ parts: [{ text }, ...extraParts] }], generationConfig },
27960
28383
  provider: "google",
27961
28384
  model,
27962
28385
  responseType: "json"
28386
+ };
28387
+ }
28388
+ /** Veo video submission — a long-running operation, hence the endpoint. */
28389
+ buildVideoRequest(req, model = req.model ?? "veo-3.1-generate-preview") {
28390
+ const instance = { prompt: req.prompt };
28391
+ if (req.sourceImage) instance.image = googleVeoImage(normalizeImageSource(req.sourceImage));
28392
+ const parameters = {};
28393
+ if (req.params?.duration) parameters.durationSeconds = req.params.duration;
28394
+ if (req.params?.aspectRatio) parameters.aspectRatio = req.params.aspectRatio;
28395
+ if (req.params?.resolution) parameters.resolution = req.params.resolution;
28396
+ return {
28397
+ url: `${this.baseURL}/v1beta/models/${model}:predictLongRunning?key=${this.apiKey}`,
28398
+ method: "POST",
28399
+ headers: { "content-type": "application/json" },
28400
+ body: { instances: [instance], parameters },
28401
+ provider: "google",
28402
+ model,
28403
+ responseType: "json"
28404
+ };
28405
+ }
28406
+ /** `generationConfig` for the gemini image paths — generation and editing take
28407
+ * the same one. */
28408
+ imageGenerationConfig(params) {
28409
+ const generationConfig = { responseModalities: ["IMAGE"] };
28410
+ const image = {};
28411
+ if (params?.aspectRatio) image.aspectRatio = params.aspectRatio;
28412
+ if (params?.imageSize) image.imageSize = params.imageSize;
28413
+ if (Object.keys(image).length) generationConfig.imageConfig = image;
28414
+ return generationConfig;
28415
+ }
28416
+ /** The complete image request, whichever of the two Google image paths applies:
28417
+ * Imagen models use `:predict`, gemini-* models generate inline via
28418
+ * `:generateContent` steered by responseModalities. */
28419
+ buildImageRequest(req, model = req.model ?? "imagen-4.0-generate-001") {
28420
+ return model.startsWith("imagen") ? this.buildImagenRequest(req, model) : this.buildGenerateContentRequest(model, req.prompt, this.imageGenerationConfig(req.params));
28421
+ }
28422
+ /** Gemini TTS: the same inline path with an AUDIO modality and a speechConfig. */
28423
+ buildAudioRequest(req, model = req.model ?? "gemini-2.5-flash-preview-tts") {
28424
+ const voiceName = resolveVoice("google", req.params?.voice) ?? "Kore";
28425
+ return this.buildGenerateContentRequest(model, req.input, {
28426
+ responseModalities: ["AUDIO"],
28427
+ speechConfig: { voiceConfig: { prebuiltVoiceConfig: { voiceName } } }
27963
28428
  });
28429
+ }
28430
+ /** Image-to-image edit: image generation plus the source image as a second part. */
28431
+ buildEditImageRequest(req, model = req.model ?? "gemini-2.5-flash-image") {
28432
+ return this.buildGenerateContentRequest(
28433
+ model,
28434
+ req.prompt,
28435
+ this.imageGenerationConfig(req.params),
28436
+ [googleImagePart(normalizeImageSource(req.sourceImage))]
28437
+ );
28438
+ }
28439
+ async generateImage(req, fetch2) {
28440
+ const model = req.model ?? "imagen-4.0-generate-001";
28441
+ if (!model.startsWith("imagen")) {
28442
+ const { items, usage } = await this.parseGenerateContent(
28443
+ await fetch2(this.buildImageRequest(req, model))
28444
+ );
28445
+ return items.map((m, i) => ({
28446
+ data: base64ToBytes(m.data),
28447
+ mimeType: m.mimeType ?? "image/png",
28448
+ usage: i === 0 ? usage : void 0
28449
+ }));
28450
+ }
28451
+ const res = await fetch2(this.buildImagenRequest(req, model));
27964
28452
  const data = res.body;
27965
28453
  const predictions = data.predictions ?? [];
27966
28454
  return predictions.map((pred) => {
@@ -27972,17 +28460,7 @@ var GoogleMediaAdapter = class {
27972
28460
  });
27973
28461
  }
27974
28462
  async generateAudio(req, fetch2) {
27975
- const model = req.model ?? "gemini-2.5-flash-preview-tts";
27976
- const voiceName = resolveVoice("google", req.params?.voice) ?? "Kore";
27977
- const media = await this.generateContentMedia(
27978
- model,
27979
- req.input,
27980
- {
27981
- responseModalities: ["AUDIO"],
27982
- speechConfig: { voiceConfig: { prebuiltVoiceConfig: { voiceName } } }
27983
- },
27984
- fetch2
27985
- );
28463
+ const media = await this.parseGenerateContent(await fetch2(this.buildAudioRequest(req)));
27986
28464
  const first = media.items[0];
27987
28465
  if (!first) throw new Error("Google TTS: no audio returned by generateContent");
27988
28466
  const playable = ensurePlayableAudio(base64ToBytes(first.data), first.mimeType ?? "audio/wav");
@@ -27991,19 +28469,8 @@ var GoogleMediaAdapter = class {
27991
28469
  /** Image-to-image edit: gemini generateContent with the source image as an
27992
28470
  * extra inline/file part next to the instruction. */
27993
28471
  async editImage(req, fetch2) {
27994
- const model = req.model ?? "gemini-2.5-flash-image";
27995
- const generationConfig = { responseModalities: ["IMAGE"] };
27996
- const image = {};
27997
- if (req.params?.aspectRatio) image.aspectRatio = req.params.aspectRatio;
27998
- if (req.params?.imageSize) image.imageSize = req.params.imageSize;
27999
- if (Object.keys(image).length) generationConfig.imageConfig = image;
28000
- const imagePart = googleImagePart(normalizeImageSource(req.sourceImage));
28001
- const { items, usage } = await this.generateContentMedia(
28002
- model,
28003
- req.prompt,
28004
- generationConfig,
28005
- fetch2,
28006
- [imagePart]
28472
+ const { items, usage } = await this.parseGenerateContent(
28473
+ await fetch2(this.buildEditImageRequest(req))
28007
28474
  );
28008
28475
  return items.map((m, i) => ({
28009
28476
  data: base64ToBytes(m.data),
@@ -28011,18 +28478,10 @@ var GoogleMediaAdapter = class {
28011
28478
  usage: i === 0 ? usage : void 0
28012
28479
  }));
28013
28480
  }
28014
- /** Shared inline-media path: POST :generateContent and collect inlineData
28015
- * parts + the reported token usage (token-priced media). */
28016
- async generateContentMedia(model, text, generationConfig, fetch2, extraParts = []) {
28017
- const res = await fetch2({
28018
- url: `${this.baseURL}/v1beta/models/${model}:generateContent?key=${this.apiKey}`,
28019
- method: "POST",
28020
- headers: { "content-type": "application/json" },
28021
- body: { contents: [{ parts: [{ text }, ...extraParts] }], generationConfig },
28022
- provider: "google",
28023
- model,
28024
- responseType: "json"
28025
- });
28481
+ /** Collect inlineData parts + reported usage from a `:generateContent`
28482
+ * response. The request half is `buildGenerateContentRequest`; keeping the two
28483
+ * apart is what lets a request be asserted without performing it. */
28484
+ parseGenerateContent(res) {
28026
28485
  const data = res.body;
28027
28486
  const parts2 = data.candidates?.[0]?.content?.parts ?? [];
28028
28487
  const items = parts2.filter((p) => p.inlineData?.data).map((p) => ({ mimeType: p.inlineData?.mimeType, data: p.inlineData?.data }));
@@ -28030,22 +28489,7 @@ var GoogleMediaAdapter = class {
28030
28489
  }
28031
28490
  async submitVideo(req, fetch2) {
28032
28491
  const model = req.model ?? "veo-3.1-generate-preview";
28033
- const instance = { prompt: req.prompt };
28034
- if (req.sourceImage) instance.image = googleVeoImage(normalizeImageSource(req.sourceImage));
28035
- const parameters = {};
28036
- if (req.params?.duration) parameters.durationSeconds = req.params.duration;
28037
- if (req.params?.aspectRatio) parameters.aspectRatio = req.params.aspectRatio;
28038
- if (req.params?.resolution) parameters.resolution = req.params.resolution;
28039
- const body = { instances: [instance], parameters };
28040
- const res = await fetch2({
28041
- url: `${this.baseURL}/v1beta/models/${model}:predictLongRunning?key=${this.apiKey}`,
28042
- method: "POST",
28043
- headers: { "content-type": "application/json" },
28044
- body,
28045
- provider: "google",
28046
- model,
28047
- responseType: "json"
28048
- });
28492
+ const res = await fetch2(this.buildVideoRequest(req, model));
28049
28493
  const data = res.body;
28050
28494
  return data.name ?? "";
28051
28495
  }
@@ -28181,48 +28625,61 @@ var GoogleRealtimeAdapter = class {
28181
28625
  this.apiKey = config.apiKey;
28182
28626
  this.base = (config.baseURL ?? GOOGLE_WS_BASE).replace(/^http/, "ws").replace(/\/$/, "");
28183
28627
  }
28184
- connect(config, connect) {
28628
+ /** The WebSocket descriptor. Separated from `connect` so it can be asserted
28629
+ * without opening a socket. Gemini authenticates with a query-string key and
28630
+ * does NOT name the model in the URL — that goes in the setup frame. */
28631
+ buildConnectRequest(config) {
28185
28632
  const url = `${this.base}/ws/google.ai.generativelanguage.${API_VERSION}.GenerativeService.BidiGenerateContent?key=${this.apiKey}`;
28186
- const req = { url, provider: "google", model: config.model };
28187
- return new GoogleRealtimeSession(connect(req), config);
28633
+ return { url, provider: "google", model: config.model };
28634
+ }
28635
+ connect(config, connect) {
28636
+ return new GoogleRealtimeSession(connect(this.buildConnectRequest(config)), config);
28188
28637
  }
28189
28638
  };
28190
28639
  function toResponseModalities(mods) {
28191
28640
  return (mods ?? ["text"]).map((m) => m === "audio" ? "AUDIO" : "TEXT");
28192
28641
  }
28642
+ function buildGoogleSetupFrame(config) {
28643
+ const voice = config.voice;
28644
+ const setup = {
28645
+ model: config.model.startsWith("models/") ? config.model : `models/${config.model}`,
28646
+ generationConfig: {
28647
+ responseModalities: toResponseModalities(config.modalities),
28648
+ ...voice ? { speechConfig: { voiceConfig: { prebuiltVoiceConfig: { voiceName: voice } } } } : {}
28649
+ }
28650
+ };
28651
+ if (config.instructions) {
28652
+ setup.systemInstruction = { parts: [{ text: config.instructions }] };
28653
+ }
28654
+ return { setup };
28655
+ }
28656
+ function buildGoogleTurnFrames(input, opts) {
28657
+ const parts2 = [];
28658
+ if (input.text != null) parts2.push({ text: input.text });
28659
+ if (input.audio) {
28660
+ parts2.push({ inlineData: { mimeType: "audio/pcm", data: bytesToBase64(input.audio) } });
28661
+ }
28662
+ return [
28663
+ {
28664
+ clientContent: {
28665
+ turns: [{ role: "user", parts: parts2 }],
28666
+ turnComplete: opts?.turnComplete !== false
28667
+ }
28668
+ }
28669
+ ];
28670
+ }
28193
28671
  var GoogleRealtimeSession = class extends BaseRealtimeSession {
28194
28672
  setupFrame;
28195
28673
  constructor(conn, config) {
28196
28674
  super(conn);
28197
- const voice = config.voice;
28198
- const setup = {
28199
- model: config.model.startsWith("models/") ? config.model : `models/${config.model}`,
28200
- generationConfig: {
28201
- responseModalities: toResponseModalities(config.modalities),
28202
- ...voice ? { speechConfig: { voiceConfig: { prebuiltVoiceConfig: { voiceName: voice } } } } : {}
28203
- }
28204
- };
28205
- if (config.instructions) {
28206
- setup.systemInstruction = { parts: [{ text: config.instructions }] };
28207
- }
28208
- this.setupFrame = { setup };
28675
+ this.setupFrame = buildGoogleSetupFrame(config);
28209
28676
  }
28210
28677
  onOpen() {
28211
28678
  this.sendJSON(this.setupFrame);
28212
28679
  }
28213
28680
  send(input, opts) {
28214
28681
  this.whenReady(() => {
28215
- const parts2 = [];
28216
- if (input.text != null) parts2.push({ text: input.text });
28217
- if (input.audio) {
28218
- parts2.push({ inlineData: { mimeType: "audio/pcm", data: bytesToBase64(input.audio) } });
28219
- }
28220
- this.sendJSON({
28221
- clientContent: {
28222
- turns: [{ role: "user", parts: parts2 }],
28223
- turnComplete: opts?.turnComplete !== false
28224
- }
28225
- });
28682
+ for (const frame of buildGoogleTurnFrames(input, opts)) this.sendJSON(frame);
28226
28683
  });
28227
28684
  }
28228
28685
  onFrame(frame) {
@@ -28715,7 +29172,7 @@ var OpenAIAdapter = class {
28715
29172
  };
28716
29173
  }
28717
29174
  parseStreamEvent(event, state) {
28718
- const data = JSON.parse(event.data);
29175
+ const data = sseJson(event);
28719
29176
  if (data.moderation) {
28720
29177
  const report = parseNativeModeration(data.moderation);
28721
29178
  const out = [];
@@ -28917,8 +29374,14 @@ var OpenAIMediaAdapter = class {
28917
29374
  authHeaders() {
28918
29375
  return { authorization: `Bearer ${this.apiKey}`, "content-type": "application/json" };
28919
29376
  }
28920
- async generateImage(req, fetch2) {
28921
- const model = req.model ?? "gpt-image-1";
29377
+ // ─── request builders ──────────────────────────────────────────────────
29378
+ //
29379
+ // Separated from the methods that fetch and parse, so a request can be built
29380
+ // and asserted without performing it. Every method below used to assemble its
29381
+ // request inline, which meant the only way to see what the adapter would send
29382
+ // was to intercept the network.
29383
+ /** Text-to-image. */
29384
+ buildGenerateImageRequest(req, model = req.model ?? "gpt-image-1") {
28922
29385
  const body = {
28923
29386
  model,
28924
29387
  prompt: req.prompt,
@@ -28932,7 +29395,7 @@ var OpenAIMediaAdapter = class {
28932
29395
  if (req.params?.style) body.style = req.params.style;
28933
29396
  if (req.params?.background) body.background = req.params.background;
28934
29397
  if (req.params?.outputFormat) body.output_format = req.params.outputFormat;
28935
- const res = await fetch2({
29398
+ return {
28936
29399
  url: `${this.baseURL}/v1/images/generations`,
28937
29400
  method: "POST",
28938
29401
  headers: this.authHeaders(),
@@ -28940,25 +29403,11 @@ var OpenAIMediaAdapter = class {
28940
29403
  provider: "openai",
28941
29404
  model,
28942
29405
  responseType: "json"
28943
- });
28944
- return this.parseImages(res.body);
28945
- }
28946
- /** Parse `/v1/images/{generations,edits}` response → RawMediaResult[], with
28947
- * the request-level usage attached to the first item (billed once). */
28948
- parseImages(data) {
28949
- const items = data.data ?? [];
28950
- const usage = mapOpenAIImageUsage(data.usage);
28951
- return items.map((item, i) => ({
28952
- data: base64ToBytes(item.b64_json ?? ""),
28953
- mimeType: "image/png",
28954
- revisedPrompt: item.revised_prompt,
28955
- usage: i === 0 ? usage : void 0
28956
- }));
29406
+ };
28957
29407
  }
28958
- /** Image-to-image edit via `/v1/images/edits` (JSON, base64 data-URL or
28959
- * file_id references). */
28960
- async editImage(req, fetch2) {
28961
- const model = req.model ?? "gpt-image-1";
29408
+ /** Image-to-image edit. Generation's field set minus `style`, plus the source
29409
+ * image and an optional mask. */
29410
+ buildEditImageRequest(req, model = req.model ?? "gpt-image-1") {
28962
29411
  const body = {
28963
29412
  model,
28964
29413
  prompt: req.prompt,
@@ -28970,7 +29419,7 @@ var OpenAIMediaAdapter = class {
28970
29419
  if (req.params?.quality) body.quality = req.params.quality;
28971
29420
  if (req.params?.background) body.background = req.params.background;
28972
29421
  if (req.params?.outputFormat) body.output_format = req.params.outputFormat;
28973
- const res = await fetch2({
29422
+ return {
28974
29423
  url: `${this.baseURL}/v1/images/edits`,
28975
29424
  method: "POST",
28976
29425
  headers: this.authHeaders(),
@@ -28978,12 +29427,10 @@ var OpenAIMediaAdapter = class {
28978
29427
  provider: "openai",
28979
29428
  model,
28980
29429
  responseType: "json"
28981
- });
28982
- return this.parseImages(res.body);
29430
+ };
28983
29431
  }
28984
- async generateAudio(req, fetch2) {
28985
- const model = req.model;
28986
- if (!model) throw new Error('OpenAI TTS requires a model (e.g. "tts-1", "gpt-4o-mini-tts")');
29432
+ /** TTS. `responseType` is arraybuffer because the response is audio bytes. */
29433
+ buildAudioRequest(req, model) {
28987
29434
  const body = {
28988
29435
  model,
28989
29436
  input: req.input,
@@ -28992,7 +29439,7 @@ var OpenAIMediaAdapter = class {
28992
29439
  if (req.params?.format) body.response_format = req.params.format;
28993
29440
  if (req.params?.speed) body.speed = req.params.speed;
28994
29441
  if (req.params?.instructions) body.instructions = req.params.instructions;
28995
- const res = await fetch2({
29442
+ return {
28996
29443
  url: `${this.baseURL}/v1/audio/speech`,
28997
29444
  method: "POST",
28998
29445
  headers: this.authHeaders(),
@@ -29000,29 +29447,17 @@ var OpenAIMediaAdapter = class {
29000
29447
  provider: "openai",
29001
29448
  model,
29002
29449
  responseType: "arraybuffer"
29003
- });
29004
- const buffer = res.body;
29005
- const format = req.params?.format ?? "mp3";
29006
- const mimeMap = {
29007
- mp3: "audio/mp3",
29008
- wav: "audio/wav",
29009
- pcm: "audio/pcm",
29010
- opus: "audio/opus",
29011
- aac: "audio/aac",
29012
- flac: "audio/flac"
29013
29450
  };
29014
- return { data: buffer, mimeType: mimeMap[format] ?? "audio/mp3" };
29015
29451
  }
29016
- // ─── Sora video (async: create poll download) ──────────────────────
29017
- async submitVideo(req, fetch2) {
29018
- const model = req.model ?? "sora-2";
29452
+ /** Sora video submission. `seconds` goes on the wire as a string. */
29453
+ buildVideoRequest(req, model = req.model ?? "sora-2") {
29019
29454
  const body = { model, prompt: req.prompt };
29020
29455
  if (req.params?.duration) body.seconds = String(req.params.duration);
29021
29456
  if (req.params?.size) body.size = req.params.size;
29022
29457
  if (req.sourceImage) {
29023
29458
  body.input_reference = openaiImageRef(normalizeImageSource(req.sourceImage));
29024
29459
  }
29025
- const res = await fetch2({
29460
+ return {
29026
29461
  url: `${this.baseURL}/v1/videos`,
29027
29462
  method: "POST",
29028
29463
  headers: this.authHeaders(),
@@ -29030,7 +29465,49 @@ var OpenAIMediaAdapter = class {
29030
29465
  provider: "openai",
29031
29466
  model,
29032
29467
  responseType: "json"
29033
- });
29468
+ };
29469
+ }
29470
+ async generateImage(req, fetch2) {
29471
+ const res = await fetch2(this.buildGenerateImageRequest(req));
29472
+ return this.parseImages(res.body);
29473
+ }
29474
+ /** Parse `/v1/images/{generations,edits}` response → RawMediaResult[], with
29475
+ * the request-level usage attached to the first item (billed once). */
29476
+ parseImages(data) {
29477
+ const items = data.data ?? [];
29478
+ const usage = mapOpenAIImageUsage(data.usage);
29479
+ return items.map((item, i) => ({
29480
+ data: base64ToBytes(item.b64_json ?? ""),
29481
+ mimeType: "image/png",
29482
+ revisedPrompt: item.revised_prompt,
29483
+ usage: i === 0 ? usage : void 0
29484
+ }));
29485
+ }
29486
+ /** Image-to-image edit via `/v1/images/edits` (JSON, base64 data-URL or
29487
+ * file_id references). */
29488
+ async editImage(req, fetch2) {
29489
+ const res = await fetch2(this.buildEditImageRequest(req));
29490
+ return this.parseImages(res.body);
29491
+ }
29492
+ async generateAudio(req, fetch2) {
29493
+ const model = req.model;
29494
+ if (!model) throw new Error('OpenAI TTS requires a model (e.g. "tts-1", "gpt-4o-mini-tts")');
29495
+ const res = await fetch2(this.buildAudioRequest(req, model));
29496
+ const buffer = res.body;
29497
+ const format = req.params?.format ?? "mp3";
29498
+ const mimeMap = {
29499
+ mp3: "audio/mp3",
29500
+ wav: "audio/wav",
29501
+ pcm: "audio/pcm",
29502
+ opus: "audio/opus",
29503
+ aac: "audio/aac",
29504
+ flac: "audio/flac"
29505
+ };
29506
+ return { data: buffer, mimeType: mimeMap[format] ?? "audio/mp3" };
29507
+ }
29508
+ // ─── Sora video (async: create → poll → download) ──────────────────────
29509
+ async submitVideo(req, fetch2) {
29510
+ const res = await fetch2(this.buildVideoRequest(req));
29034
29511
  const data = res.body;
29035
29512
  return data.id ?? "";
29036
29513
  }
@@ -29202,19 +29679,44 @@ var OpenAIRealtimeAdapter = class {
29202
29679
  this.apiKey = config.apiKey;
29203
29680
  this.baseURL = config.baseURL ?? "https://api.openai.com";
29204
29681
  }
29205
- connect(config, connect) {
29682
+ /** The WebSocket descriptor. Separated from `connect` so it can be asserted
29683
+ * without opening a socket. Note the auth: OpenAI carries the key in a
29684
+ * SUBPROTOCOL, not a header or query param, because browsers cannot set
29685
+ * WebSocket headers. */
29686
+ buildConnectRequest(config) {
29206
29687
  const url = new URL(`${this.baseURL.replace(/\/$/, "")}/v1/realtime`);
29207
29688
  url.protocol = "wss";
29208
29689
  url.searchParams.set("model", config.model);
29209
- const req = {
29690
+ return {
29210
29691
  url: url.toString(),
29211
29692
  protocols: ["realtime", `openai-insecure-api-key.${this.apiKey}`],
29212
29693
  provider: "openai",
29213
29694
  model: config.model
29214
29695
  };
29215
- return new OpenAIRealtimeSession(connect(req), config);
29696
+ }
29697
+ connect(config, connect) {
29698
+ return new OpenAIRealtimeSession(connect(this.buildConnectRequest(config)), config);
29216
29699
  }
29217
29700
  };
29701
+ function buildOpenAISessionUpdate(config) {
29702
+ const session = {
29703
+ type: "realtime",
29704
+ output_modalities: config.modalities ?? ["text"]
29705
+ };
29706
+ if (config.instructions) session.instructions = config.instructions;
29707
+ if (config.voice) session.audio = { output: { voice: config.voice } };
29708
+ return { type: "session.update", session };
29709
+ }
29710
+ function buildOpenAITurnFrames(input, opts) {
29711
+ const content = [];
29712
+ if (input.text != null) content.push({ type: "input_text", text: input.text });
29713
+ if (input.audio) content.push({ type: "input_audio", audio: bytesToBase64(input.audio) });
29714
+ const frames = [
29715
+ { type: "conversation.item.create", item: { type: "message", role: "user", content } }
29716
+ ];
29717
+ if (opts?.turnComplete !== false) frames.push({ type: "response.create" });
29718
+ return frames;
29719
+ }
29218
29720
  var OpenAIRealtimeSession = class extends BaseRealtimeSession {
29219
29721
  modalities;
29220
29722
  instructions;
@@ -29226,25 +29728,18 @@ var OpenAIRealtimeSession = class extends BaseRealtimeSession {
29226
29728
  this.voice = config.voice;
29227
29729
  }
29228
29730
  onOpen() {
29229
- const session = {
29230
- type: "realtime",
29231
- output_modalities: this.modalities
29232
- };
29233
- if (this.instructions) session.instructions = this.instructions;
29234
- if (this.voice) session.audio = { output: { voice: this.voice } };
29235
- this.sendJSON({ type: "session.update", session });
29731
+ this.sendJSON(
29732
+ buildOpenAISessionUpdate({
29733
+ modalities: this.modalities,
29734
+ instructions: this.instructions,
29735
+ voice: this.voice
29736
+ })
29737
+ );
29236
29738
  this.markReady();
29237
29739
  }
29238
29740
  send(input, opts) {
29239
29741
  this.whenReady(() => {
29240
- const content = [];
29241
- if (input.text != null) content.push({ type: "input_text", text: input.text });
29242
- if (input.audio) content.push({ type: "input_audio", audio: bytesToBase64(input.audio) });
29243
- this.sendJSON({
29244
- type: "conversation.item.create",
29245
- item: { type: "message", role: "user", content }
29246
- });
29247
- if (opts?.turnComplete !== false) this.sendJSON({ type: "response.create" });
29742
+ for (const frame of buildOpenAITurnFrames(input, opts)) this.sendJSON(frame);
29248
29743
  });
29249
29744
  }
29250
29745
  onFrame(frame) {
@@ -29754,7 +30249,7 @@ var OpenAIResponsesAdapter = class {
29754
30249
  };
29755
30250
  }
29756
30251
  parseStreamEvent(event, phaseByItem) {
29757
- const data = JSON.parse(event.data);
30252
+ const data = sseJson(event);
29758
30253
  const type = data.type;
29759
30254
  const events = [];
29760
30255
  if (type === "response.output_text.delta") {
@@ -30037,7 +30532,24 @@ var OpenRouterResponsesAdapter = class extends OpenAIResponsesAdapter {
30037
30532
  }
30038
30533
  };
30039
30534
 
30535
+ // src/util/hash.ts
30536
+ function fnv1a322(input) {
30537
+ let h = 2166136261;
30538
+ for (let i = 0; i < input.length; i++) {
30539
+ h ^= input.charCodeAt(i);
30540
+ h = Math.imul(h, 16777619) >>> 0;
30541
+ }
30542
+ return h >>> 0;
30543
+ }
30544
+ function fnv1a32Hex(input) {
30545
+ return fnv1a322(input).toString(16).padStart(8, "0");
30546
+ }
30547
+
30040
30548
  // src/llm/providers/xai/batch.ts
30549
+ function batchName(requests) {
30550
+ const digest = fnv1a32Hex(requests.map((r) => r.customId).join("\0"));
30551
+ return `batch_${requests.length}_${digest}`;
30552
+ }
30041
30553
  var XAIBatchAdapter = class {
30042
30554
  name = "xai";
30043
30555
  apiKey;
@@ -30054,7 +30566,7 @@ var XAIBatchAdapter = class {
30054
30566
  url: `${this.baseURL}/v1/batches`,
30055
30567
  method: "POST",
30056
30568
  headers: { ...this.bearer(), "content-type": "application/json" },
30057
- body: { name: `batch_${Date.now()}` },
30569
+ body: { name: batchName(requests) },
30058
30570
  provider: "xai",
30059
30571
  model: "batch",
30060
30572
  responseType: "json"
@@ -30173,7 +30685,7 @@ var XAIAdapter = class extends OpenAIAdapter {
30173
30685
  parseStreamEvent(event, state) {
30174
30686
  const events = super.parseStreamEvent(event, state);
30175
30687
  try {
30176
- const data = JSON.parse(event.data);
30688
+ const data = sseJson(event);
30177
30689
  const choices = data.choices ?? [];
30178
30690
  const delta = choices[0]?.delta ?? {};
30179
30691
  if (delta.reasoning_content) {
@@ -32085,6 +32597,123 @@ var AgentLoop = class _AgentLoop {
32085
32597
  this._stopRequested = true;
32086
32598
  this._abortController?.abort();
32087
32599
  }
32600
+ // ─── shared run scaffolding ─────────────────────────────────────────────
32601
+ //
32602
+ // `complete()` and `stream()` are the same loop with different plumbing, and
32603
+ // they had drifted into near-duplicates: 167 identical lines across ~560. The
32604
+ // three pieces below are what was copied verbatim — how a run's error is
32605
+ // recorded, how its final text is decided, and how its final response is
32606
+ // shaped. Sharing them means a fix to one path cannot silently miss the other.
32607
+ /** Record a thrown error onto the run: emit `onRunError` and return the parts
32608
+ * the caller assigns. Both paths report `phase: 'llm_call'`. */
32609
+ async recordRunError(e, args) {
32610
+ await this.hooks.emit("onRunError", {
32611
+ runId: args.runId,
32612
+ agentId: this.id,
32613
+ step: args.stepCount,
32614
+ error: e instanceof Error ? e : new Error(String(e)),
32615
+ phase: "llm_call",
32616
+ trace: args.runTrace
32617
+ });
32618
+ return { errorMsg: e instanceof Error ? e.message : String(e), caughtError: e };
32619
+ }
32620
+ /** The run's final text.
32621
+ *
32622
+ * `finalAnswerText` strips `phase: 'commentary'` parts: a codex-family model
32623
+ * narrates before it answers and `response.text` concatenates both, so an
32624
+ * agent's final output used to include its own thinking-out-loud. Falls back
32625
+ * to `.text` when the content carries no text parts, and is identical to
32626
+ * `.text` for every model that reports no phase.
32627
+ *
32628
+ * The streaming path passes what it accumulated; the non-streaming path lets
32629
+ * the last response decide. Both share the guardrail / max-steps overrides. */
32630
+ resolveFinalText(args) {
32631
+ if (args.reason === "guardrail") return args.guardrailTripReason ?? "";
32632
+ if (args.reason === "max_steps") return `stopped: reached maxSteps (${this._maxSteps})`;
32633
+ if (args.streamedText !== void 0) return args.streamedText;
32634
+ const last = args.lastResponse;
32635
+ return last ? finalAnswerText(last.content ?? []) || (last.text ?? "") : "";
32636
+ }
32637
+ /** Compose the run's CompletionResponse. `media` and `raw` are parameters
32638
+ * because the two paths genuinely differ: the streaming path has already
32639
+ * emitted media as events and never holds a raw provider payload. */
32640
+ buildFinalResponse(args) {
32641
+ const last = args.lastResponse;
32642
+ const reason = args.reason;
32643
+ return {
32644
+ id: last?.id ?? `agent-${args.runId}`,
32645
+ model: this.client.model,
32646
+ content: args.finalContent,
32647
+ finishReason: reason === "done" ? (
32648
+ // Ended because the model requested no tools — surface the provider's
32649
+ // actual reason (stop / content_filter / length), not a flat 'stop'.
32650
+ last?.finishReason ?? "stop"
32651
+ ) : reason === "stopped" ? "stop" : reason === "guardrail" ? "stop" : reason === "max_steps" ? "length" : "error",
32652
+ usage: args.totalUsage,
32653
+ text: args.finalText,
32654
+ toolCalls: last?.toolCalls ?? [],
32655
+ thinking: last?.thinking ?? null,
32656
+ media: args.media,
32657
+ // Propagate hosted-tool file outputs + inline-moderation result from the
32658
+ // final LLM response (e.g. code-execution files produced during the run).
32659
+ ...last?.files ? { files: last.files } : {},
32660
+ ...last?.builtinToolCalls ? { builtinToolCalls: last.builtinToolCalls } : {},
32661
+ ...last?.moderation ? { moderation: last.moderation } : {},
32662
+ latencyMs: performance.now() - args.startPerf,
32663
+ raw: args.raw
32664
+ };
32665
+ }
32666
+ /** Close out a run: write the report, then surface a failure.
32667
+ *
32668
+ * The order matters and is the reason this is one function rather than two
32669
+ * calls at each site — a failed run must still emit its metrics and hooks
32670
+ * before the error propagates, or a crash silently loses the run's telemetry.
32671
+ * A failed run throws rather than returning empty text, matching the raw
32672
+ * client. */
32673
+ async settleRun(args) {
32674
+ await this.finalizeRun(args);
32675
+ if (args.reason === "error") {
32676
+ throw args.caughtError ?? new Error(args.error ?? "agent run failed");
32677
+ }
32678
+ }
32679
+ /** Per-step options for the underlying LLM call: loop defaults, then the
32680
+ * caller's overrides, then the run's trace.
32681
+ *
32682
+ * `complete()` and `stream()` duplicated this verbatim, differing only in the
32683
+ * name of the local holding the composed system prompt. That is a bad place
32684
+ * for a copy: the ctx block below is what stops one conversation arriving at
32685
+ * the collector as several unrelated traces, and a fix applied to one path
32686
+ * would have left the other silently splitting. */
32687
+ buildStepOptions(options, composedSystem, runTrace) {
32688
+ return {
32689
+ ...options,
32690
+ system: composedSystem,
32691
+ history: options.history ?? this._history,
32692
+ maxTokens: options.maxTokens ?? this._maxTokens,
32693
+ temperature: options.temperature ?? this._temperature,
32694
+ thinking: options.thinking ?? this._thinking,
32695
+ cache: options.cache ?? this._cache,
32696
+ tools: this.toolDefinitions(options),
32697
+ ctx: {
32698
+ // The RUN's trace, handed down to every LLM call it makes.
32699
+ //
32700
+ // Without this the agent kept `runTrace` to itself: its own spans used it
32701
+ // while each `client.complete()` fell through to mint-if-absent and
32702
+ // invented a fresh `requestId`. Since the trace id is `sessionId:requestId`,
32703
+ // one conversation arrived at the backend as SEVERAL unrelated traces —
32704
+ // measured against a real collector: a single turn with one tool call
32705
+ // produced six. Correlation is the whole point of a trace id, so this is
32706
+ // the one thing it must not get wrong.
32707
+ ...runTrace,
32708
+ conversationId: this._history.id,
32709
+ // A caller's explicit ctx wins over all of the above: an app that already
32710
+ // owns a request id or a conversation id has better information than we do,
32711
+ // and silently overwriting it is how its telemetry stops joining up.
32712
+ ...options.ctx
32713
+ },
32714
+ signal: options.signal ?? this._abortController?.signal
32715
+ };
32716
+ }
32088
32717
  // ─── complete (non-streaming) ───────────────────────────────────────────
32089
32718
  async complete(input, options = {}) {
32090
32719
  const { runId, startedAt, startPerf, userMessageText, runTrace } = await this.beginRun(input, options.ctx);
@@ -32131,32 +32760,7 @@ var AgentLoop = class _AgentLoop {
32131
32760
  break;
32132
32761
  }
32133
32762
  lastResponse = await this.client.complete(this._history.messages(), {
32134
- ...options,
32135
- system: composedSystemStr,
32136
- history: options.history ?? this._history,
32137
- maxTokens: options.maxTokens ?? this._maxTokens,
32138
- temperature: options.temperature ?? this._temperature,
32139
- thinking: options.thinking ?? this._thinking,
32140
- cache: options.cache ?? this._cache,
32141
- tools: this.toolDefinitions(options),
32142
- ctx: {
32143
- // The RUN's trace, handed down to every LLM call it makes.
32144
- //
32145
- // Without this the agent kept `runTrace` to itself: its own spans used it
32146
- // while each `client.complete()` fell through to mint-if-absent and
32147
- // invented a fresh `requestId`. Since the trace id is `sessionId:requestId`,
32148
- // one conversation arrived at the backend as SEVERAL unrelated traces —
32149
- // measured against a real collector: a single turn with one tool call
32150
- // produced six. Correlation is the whole point of a trace id, so this is
32151
- // the one thing it must not get wrong.
32152
- ...runTrace,
32153
- conversationId: this._history.id,
32154
- // A caller's explicit ctx wins over all of the above: an app that already
32155
- // owns a request id or a conversation id has better information than we do,
32156
- // and silently overwriting it is how its telemetry stops joining up.
32157
- ...options.ctx
32158
- },
32159
- signal: options.signal ?? this._abortController?.signal
32763
+ ...this.buildStepOptions(options, composedSystemStr, runTrace)
32160
32764
  });
32161
32765
  const stepLatency = performance.now() - stepStart;
32162
32766
  totalLlmTimeMs += stepLatency;
@@ -32252,45 +32856,25 @@ var AgentLoop = class _AgentLoop {
32252
32856
  }
32253
32857
  } catch (e) {
32254
32858
  reason = "error";
32255
- errorMsg = e instanceof Error ? e.message : String(e);
32256
- caughtError = e;
32257
- await this.hooks.emit("onRunError", {
32258
- runId,
32259
- agentId: this.id,
32260
- step: stepCount,
32261
- error: e instanceof Error ? e : new Error(String(e)),
32262
- phase: "llm_call",
32263
- trace: runTrace
32264
- });
32859
+ ({ errorMsg, caughtError } = await this.recordRunError(e, { runId, stepCount, runTrace }));
32265
32860
  } finally {
32266
32861
  this._running = false;
32267
32862
  this._abortController = null;
32268
32863
  }
32269
- const finalText = reason === "guardrail" ? guardrailTripReason ?? "" : reason === "max_steps" ? `stopped: reached maxSteps (${this._maxSteps})` : lastResponse ? finalAnswerText(lastResponse.content ?? []) || (lastResponse.text ?? "") : "";
32864
+ const finalText = this.resolveFinalText({ reason, guardrailTripReason, lastResponse });
32270
32865
  const finalContent = lastResponse?.content ?? [];
32271
- const finalResponse = {
32272
- id: lastResponse?.id ?? `agent-${runId}`,
32273
- model: this.client.model,
32274
- content: finalContent,
32275
- finishReason: reason === "done" ? (
32276
- // Ended because the model requested no tools — surface the provider's
32277
- // actual reason (stop / content_filter / length), not a flat 'stop'.
32278
- lastResponse?.finishReason ?? "stop"
32279
- ) : reason === "stopped" ? "stop" : reason === "guardrail" ? "stop" : reason === "max_steps" ? "length" : "error",
32280
- usage: totalUsage,
32281
- text: finalText,
32282
- toolCalls: lastResponse?.toolCalls ?? [],
32283
- thinking: lastResponse?.thinking ?? null,
32866
+ const finalResponse = this.buildFinalResponse({
32867
+ runId,
32868
+ startPerf,
32869
+ reason,
32870
+ finalText,
32871
+ finalContent,
32872
+ totalUsage,
32873
+ lastResponse,
32284
32874
  media: lastResponse?.media ?? [],
32285
- // Propagate hosted-tool file outputs + inline-moderation result from the final
32286
- // LLM response (e.g. code-execution files produced during the run).
32287
- ...lastResponse?.files ? { files: lastResponse.files } : {},
32288
- ...lastResponse?.builtinToolCalls ? { builtinToolCalls: lastResponse.builtinToolCalls } : {},
32289
- ...lastResponse?.moderation ? { moderation: lastResponse.moderation } : {},
32290
- latencyMs: performance.now() - startPerf,
32291
32875
  raw: lastResponse?.raw ?? null
32292
- };
32293
- await this.finalizeRun({
32876
+ });
32877
+ await this.settleRun({
32294
32878
  runId,
32295
32879
  startedAt,
32296
32880
  startPerf,
@@ -32299,6 +32883,7 @@ var AgentLoop = class _AgentLoop {
32299
32883
  finalText,
32300
32884
  reason,
32301
32885
  error: errorMsg,
32886
+ caughtError,
32302
32887
  response: finalResponse,
32303
32888
  steps,
32304
32889
  stepCount,
@@ -32308,7 +32893,6 @@ var AgentLoop = class _AgentLoop {
32308
32893
  totalToolTimeMs,
32309
32894
  runTrace
32310
32895
  });
32311
- if (reason === "error") throw caughtError ?? new Error(errorMsg ?? "agent run failed");
32312
32896
  return finalResponse;
32313
32897
  }
32314
32898
  /** Run `complete` with a JSON Schema enforced via `structured`, then
@@ -32371,32 +32955,7 @@ var AgentLoop = class _AgentLoop {
32371
32955
  break;
32372
32956
  }
32373
32957
  for await (const event of this.client.stream(this._history.messages(), {
32374
- ...options,
32375
- system: composedSystemForStream,
32376
- history: options.history ?? this._history,
32377
- maxTokens: options.maxTokens ?? this._maxTokens,
32378
- temperature: options.temperature ?? this._temperature,
32379
- thinking: options.thinking ?? this._thinking,
32380
- cache: options.cache ?? this._cache,
32381
- tools: this.toolDefinitions(options),
32382
- ctx: {
32383
- // The RUN's trace, handed down to every LLM call it makes.
32384
- //
32385
- // Without this the agent kept `runTrace` to itself: its own spans used it
32386
- // while each `client.complete()` fell through to mint-if-absent and
32387
- // invented a fresh `requestId`. Since the trace id is `sessionId:requestId`,
32388
- // one conversation arrived at the backend as SEVERAL unrelated traces —
32389
- // measured against a real collector: a single turn with one tool call
32390
- // produced six. Correlation is the whole point of a trace id, so this is
32391
- // the one thing it must not get wrong.
32392
- ...runTrace,
32393
- conversationId: this._history.id,
32394
- // A caller's explicit ctx wins over all of the above: an app that already
32395
- // owns a request id or a conversation id has better information than we do,
32396
- // and silently overwriting it is how its telemetry stops joining up.
32397
- ...options.ctx
32398
- },
32399
- signal: options.signal ?? this._abortController?.signal
32958
+ ...this.buildStepOptions(options, composedSystemForStream, runTrace)
32400
32959
  })) {
32401
32960
  const toYield = accumulateStreamEvent(event, state);
32402
32961
  if (toYield) yield toYield;
@@ -32481,43 +33040,26 @@ var AgentLoop = class _AgentLoop {
32481
33040
  }
32482
33041
  } catch (e) {
32483
33042
  reason = "error";
32484
- errorMsg = e instanceof Error ? e.message : String(e);
32485
- caughtError = e;
32486
- await this.hooks.emit("onRunError", {
32487
- runId,
32488
- agentId: this.id,
32489
- step: stepCount,
32490
- error: e instanceof Error ? e : new Error(String(e)),
32491
- phase: "llm_call",
32492
- trace: runTrace
32493
- });
33043
+ ({ errorMsg, caughtError } = await this.recordRunError(e, { runId, stepCount, runTrace }));
32494
33044
  } finally {
32495
33045
  this._running = false;
32496
33046
  this._abortController = null;
32497
33047
  }
32498
- if (reason === "guardrail") finalText = guardrailTripReason ?? "";
32499
- if (reason === "max_steps") finalText = `stopped: reached maxSteps (${this._maxSteps})`;
32500
- const finalResponse = {
32501
- id: lastResponse?.id ?? `agent-${runId}`,
32502
- model: this.client.model,
32503
- content: finalContent,
32504
- finishReason: reason === "done" ? (
32505
- // Ended because the model requested no tools — surface the provider's
32506
- // actual reason (stop / content_filter / length), not a flat 'stop'.
32507
- lastResponse?.finishReason ?? "stop"
32508
- ) : reason === "stopped" ? "stop" : reason === "guardrail" ? "stop" : reason === "max_steps" ? "length" : "error",
32509
- usage: totalUsage,
32510
- text: finalText,
32511
- toolCalls: lastResponse?.toolCalls ?? [],
32512
- thinking: lastResponse?.thinking ?? null,
33048
+ finalText = this.resolveFinalText({ reason, guardrailTripReason, streamedText: finalText });
33049
+ const finalResponse = this.buildFinalResponse({
33050
+ runId,
33051
+ startPerf,
33052
+ reason,
33053
+ finalText,
33054
+ finalContent,
33055
+ totalUsage,
33056
+ lastResponse,
33057
+ // The streaming path already emitted media as events, and never holds a
33058
+ // raw provider payload.
32513
33059
  media: [],
32514
- ...lastResponse?.files ? { files: lastResponse.files } : {},
32515
- ...lastResponse?.builtinToolCalls ? { builtinToolCalls: lastResponse.builtinToolCalls } : {},
32516
- ...lastResponse?.moderation ? { moderation: lastResponse.moderation } : {},
32517
- latencyMs: performance.now() - startPerf,
32518
33060
  raw: null
32519
- };
32520
- await this.finalizeRun({
33061
+ });
33062
+ await this.settleRun({
32521
33063
  runId,
32522
33064
  startedAt,
32523
33065
  startPerf,
@@ -32526,6 +33068,7 @@ var AgentLoop = class _AgentLoop {
32526
33068
  finalText,
32527
33069
  reason,
32528
33070
  error: errorMsg,
33071
+ caughtError,
32529
33072
  response: finalResponse,
32530
33073
  steps,
32531
33074
  stepCount,
@@ -32535,7 +33078,6 @@ var AgentLoop = class _AgentLoop {
32535
33078
  totalToolTimeMs,
32536
33079
  runTrace
32537
33080
  });
32538
- if (reason === "error") throw caughtError ?? new Error(errorMsg ?? "agent run failed");
32539
33081
  yield { type: "done", response: finalResponse };
32540
33082
  }
32541
33083
  /** Yield tool_call_start events for all tool calls in this step. */
@@ -34955,286 +35497,6 @@ var HybridTokenCounter = class {
34955
35497
  }
34956
35498
  };
34957
35499
 
34958
- // src/helpers/client-pool.ts
34959
- var ClientPool = class {
34960
- constructor(catalog) {
34961
- this.catalog = catalog;
34962
- }
34963
- catalog;
34964
- clients = /* @__PURE__ */ new Map();
34965
- get(provider, model, config) {
34966
- const key = this.keyFor(provider, model);
34967
- let client = this.clients.get(key);
34968
- if (!client) {
34969
- client = new LLMClient({ ...config, model });
34970
- this.clients.set(key, client);
34971
- }
34972
- return client;
34973
- }
34974
- async destroy() {
34975
- for (const [, client] of this.clients) {
34976
- client.destroy();
34977
- }
34978
- this.clients.clear();
34979
- }
34980
- get size() {
34981
- return this.clients.size;
34982
- }
34983
- keyFor(provider, model) {
34984
- const info = this.catalog?.get(provider, model);
34985
- if (info?.requiresDedicatedClient) {
34986
- return `${provider}/${model}`;
34987
- }
34988
- return provider;
34989
- }
34990
- };
34991
-
34992
- // src/helpers/client-resolver.ts
34993
- function directFetch() {
34994
- return async (req) => {
34995
- const init = {
34996
- method: req.method ?? "POST",
34997
- headers: req.headers,
34998
- body: typeof req.body === "string" ? req.body : JSON.stringify(req.body)
34999
- };
35000
- if (req.signal) init.signal = req.signal;
35001
- const res = await globalThis.fetch(req.url, init);
35002
- const headers = {};
35003
- res.headers.forEach((v, k) => {
35004
- headers[k] = v;
35005
- });
35006
- const body = await res.json().catch(() => null);
35007
- return { status: res.status, headers, body };
35008
- };
35009
- }
35010
- var ClientResolver = class {
35011
- constructor(cfg) {
35012
- this.cfg = cfg;
35013
- this.pool = new ClientPool(cfg.catalog);
35014
- }
35015
- cfg;
35016
- pool;
35017
- /** Turn `"anthropic/claude-haiku-4-5"` → resolved client. */
35018
- resolve(modelId) {
35019
- const [provider, model] = parseModelId(modelId);
35020
- const apiKey = this.cfg.apiKeys[provider];
35021
- if (!apiKey) {
35022
- const known = Object.keys(this.cfg.apiKeys).filter(
35023
- (k) => !!this.cfg.apiKeys[k]
35024
- );
35025
- throw new Error(
35026
- `ClientResolver: no API key for provider "${provider}". Configured providers: [${known.join(", ") || "none"}]`
35027
- );
35028
- }
35029
- const fetchFn = this.cfg.fetch ?? directFetch();
35030
- const client = this.pool.get(provider, model, {
35031
- provider,
35032
- apiKey,
35033
- hooks: this.cfg.hooks,
35034
- model,
35035
- fetch: fetchFn,
35036
- fetchStream: this.cfg.fetchStream,
35037
- ...this.cfg.clientOptions
35038
- });
35039
- return { client, provider, model };
35040
- }
35041
- availableProviders() {
35042
- return Object.keys(this.cfg.apiKeys).filter((p) => !!this.cfg.apiKeys[p]);
35043
- }
35044
- async destroy() {
35045
- await this.pool.destroy();
35046
- }
35047
- get size() {
35048
- return this.pool.size;
35049
- }
35050
- };
35051
- function parseModelId(modelId) {
35052
- const slash = modelId.indexOf("/");
35053
- if (slash <= 0 || slash === modelId.length - 1) {
35054
- throw new Error(`Invalid model id "${modelId}" \u2014 expected format "provider/model"`);
35055
- }
35056
- const provider = modelId.slice(0, slash);
35057
- const model = modelId.slice(slash + 1);
35058
- return [provider, model];
35059
- }
35060
- function isNamespacedModelId(modelId) {
35061
- const slash = modelId.indexOf("/");
35062
- return slash > 0 && slash < modelId.length - 1;
35063
- }
35064
- function resolveModel(model, provider, label) {
35065
- if (isNamespacedModelId(model)) {
35066
- const [p, m] = parseModelId(model);
35067
- return { provider: p, model: m };
35068
- }
35069
- if (!provider) {
35070
- throw new Error(
35071
- `${label}: bare model "${model}" requires a provider \u2014 pass it explicitly or use "provider/model".`
35072
- );
35073
- }
35074
- return { provider, model };
35075
- }
35076
- var TIER_SUFFIXES = /* @__PURE__ */ new Set(["auto", "standard", "priority", "flex", "scale"]);
35077
- function parseModelTier(modelId) {
35078
- const colon = modelId.lastIndexOf(":");
35079
- if (colon <= 0) return { modelId };
35080
- const suffix = modelId.slice(colon + 1);
35081
- if (!TIER_SUFFIXES.has(suffix)) return { modelId };
35082
- return { modelId: modelId.slice(0, colon), serviceTier: suffix };
35083
- }
35084
-
35085
- // src/helpers/engine.ts
35086
- function createEngine(config = {}) {
35087
- const sessionId = config.sessionId ?? `sess_${crypto.randomUUID().slice(0, 12)}`;
35088
- const hooks = config.hooks ?? new HookBus();
35089
- const bus = config.bus ?? new AgentBus();
35090
- const persistence = resolvePersistence(config.persistence);
35091
- const cache2 = resolveCache(config.cache);
35092
- const catalog = resolveCatalog(config.catalog);
35093
- const network = new NetworkEngine({ hooks, fetch: config.fetch, retry: config.retry, queues: config.queues });
35094
- const fetchBound = (req, options) => network.fetch(req, options);
35095
- const fetchStreamBound = (req, options) => network.fetchStream(req, options);
35096
- const connectBound = (req) => network.connect(req);
35097
- const cost = new CostCollector({ hooks, catalog });
35098
- const telemetry = config.telemetry ? new TelemetryAdapter(hooks, config.telemetry) : null;
35099
- const handle = {
35100
- sessionId,
35101
- hooks,
35102
- bus,
35103
- persistence,
35104
- cache: cache2,
35105
- network,
35106
- fetch: fetchBound,
35107
- fetchStream: fetchStreamBound,
35108
- connect: connectBound,
35109
- catalog,
35110
- cost,
35111
- telemetry,
35112
- apiKeys: config.apiKeys ?? {},
35113
- destroy() {
35114
- cost.destroy();
35115
- telemetry?.destroy();
35116
- network.destroy();
35117
- }
35118
- };
35119
- if (config.registerAsDefault !== false) {
35120
- coreRegistry.set(handle);
35121
- }
35122
- return handle;
35123
- }
35124
- function resolveCatalog(config) {
35125
- const c = new ModelCatalog();
35126
- if (!config) return c;
35127
- if (config instanceof ModelCatalog) return config;
35128
- if (config === true || config === "defaults") {
35129
- c.loadProviderDefaults();
35130
- return c;
35131
- }
35132
- if (typeof config === "object" && "entries" in config) {
35133
- c.load(config.entries);
35134
- return c;
35135
- }
35136
- return c;
35137
- }
35138
- function resolvePersistence(config) {
35139
- if (!config) return new MemoryPersistence();
35140
- if (typeof config.get === "function") {
35141
- return config;
35142
- }
35143
- const c = config;
35144
- if (c.type === "memory") return new MemoryPersistence();
35145
- if (c.type === "file") {
35146
- if (!c.dir) {
35147
- throw new Error('createEngine: persistence type "file" requires a `dir` field');
35148
- }
35149
- return new FilePersistence(c.dir);
35150
- }
35151
- throw new Error(`createEngine: unknown persistence type "${c.type}"`);
35152
- }
35153
- function resolveCache(config) {
35154
- if (!config) return null;
35155
- if (config instanceof Cache) return config;
35156
- const c = config;
35157
- if (c.type === "memory") return new Cache({ store: new MemoryCacheStore() });
35158
- throw new Error(`createEngine: unknown cache type "${c.type}"`);
35159
- }
35160
- var CoreRegistry = class {
35161
- current = null;
35162
- /** Get the current default engine, creating a bare one on first read. */
35163
- get() {
35164
- if (!this.current) this.current = createEngine();
35165
- return this.current;
35166
- }
35167
- /** Set the default engine. Throws if one is already set unless replace=true.
35168
- * When replacing, the previous engine is destroyed AFTER the pointer
35169
- * swap so engine.destroy callbacks can safely query the registry. */
35170
- set(engine, opts = {}) {
35171
- if (this.current && !opts.replace) {
35172
- throw new Error(
35173
- "coreRegistry: an engine is already registered. Create additional engines with createEngine({ registerAsDefault: false }) and pass them explicitly to helpers, or use coreRegistry.set(engine, { replace: true }) to override."
35174
- );
35175
- }
35176
- const previous = this.current;
35177
- this.current = engine;
35178
- if (previous && opts.replace) {
35179
- previous.destroy();
35180
- }
35181
- }
35182
- /** Clear the default engine. */
35183
- clear() {
35184
- this.current?.destroy();
35185
- this.current = null;
35186
- }
35187
- has() {
35188
- return this.current !== null;
35189
- }
35190
- };
35191
- var coreRegistry = new CoreRegistry();
35192
-
35193
- // src/helpers/llm.ts
35194
- function createLLM(opts) {
35195
- const engine = opts.engine ?? coreRegistry.get();
35196
- const { provider, model } = resolveModel(opts.model, opts.provider, "createLLM");
35197
- const sendModel = engine.catalog.resolveModelId(provider, model);
35198
- const apiKey = opts.apiKey ?? engine.apiKeys[provider];
35199
- if (!apiKey) {
35200
- throw new Error(
35201
- `createLLM: no API key for provider "${provider}". Pass apiKey directly or set engine.apiKeys["${provider}"] via createEngine.`
35202
- );
35203
- }
35204
- const adapter = opts.adapter ?? defaultAdapterFactory();
35205
- return new LLMClient({
35206
- ...opts,
35207
- provider,
35208
- model: sendModel,
35209
- apiKey,
35210
- adapter,
35211
- fetch: opts.fetch ?? engine.fetch,
35212
- fetchStream: opts.fetchStream ?? engine.fetchStream,
35213
- hooks: opts.hooks ?? engine.hooks,
35214
- sessionId: engine.sessionId,
35215
- catalog: engine.catalog
35216
- });
35217
- }
35218
- function defaultAdapterFactory() {
35219
- return (provider, apiKey, api, baseURL) => {
35220
- const cfg = { apiKey, baseURL };
35221
- switch (provider) {
35222
- case "anthropic":
35223
- return new AnthropicAdapter(cfg);
35224
- case "openai":
35225
- return api === "responses" ? new OpenAIResponsesAdapter(cfg) : new OpenAIAdapter(cfg);
35226
- case "google":
35227
- return api === "interactions" ? new GoogleInteractionsAdapter(cfg) : new GoogleAdapter(cfg);
35228
- case "xai":
35229
- return api === "responses" ? new XAIResponsesAdapter(cfg) : new XAIAdapter(cfg);
35230
- case "openrouter":
35231
- return api === "responses" ? new OpenRouterResponsesAdapter(cfg) : new OpenRouterAdapter(cfg);
35232
- default:
35233
- throw new Error(`createLLM: no default adapter for provider '${provider}'`);
35234
- }
35235
- };
35236
- }
35237
-
35238
35500
  // src/plugins/internal-tools/runner/runner.ts
35239
35501
  var InternalToolRunner = class {
35240
35502
  constructor(config) {
@@ -35362,8 +35624,7 @@ var InternalToolRunner = class {
35362
35624
  const key = requiresDedicated ? `${provider}/${model}` : provider;
35363
35625
  let client = this.clients.get(key);
35364
35626
  if (!client) {
35365
- client = createLLM({
35366
- engine,
35627
+ client = engine.createClient({
35367
35628
  provider,
35368
35629
  model,
35369
35630
  apiKey,
@@ -38205,6 +38466,289 @@ var FACT_CATEGORIES = [
38205
38466
  "other"
38206
38467
  ];
38207
38468
 
38469
+ // src/helpers/client-pool.ts
38470
+ var ClientPool = class {
38471
+ constructor(catalog) {
38472
+ this.catalog = catalog;
38473
+ }
38474
+ catalog;
38475
+ clients = /* @__PURE__ */ new Map();
38476
+ get(provider, model, config) {
38477
+ const key = this.keyFor(provider, model);
38478
+ let client = this.clients.get(key);
38479
+ if (!client) {
38480
+ client = new LLMClient({ ...config, model });
38481
+ this.clients.set(key, client);
38482
+ }
38483
+ return client;
38484
+ }
38485
+ async destroy() {
38486
+ for (const [, client] of this.clients) {
38487
+ client.destroy();
38488
+ }
38489
+ this.clients.clear();
38490
+ }
38491
+ get size() {
38492
+ return this.clients.size;
38493
+ }
38494
+ keyFor(provider, model) {
38495
+ const info = this.catalog?.get(provider, model);
38496
+ if (info?.requiresDedicatedClient) {
38497
+ return `${provider}/${model}`;
38498
+ }
38499
+ return provider;
38500
+ }
38501
+ };
38502
+
38503
+ // src/helpers/client-resolver.ts
38504
+ function directFetch() {
38505
+ return async (req) => {
38506
+ const init = {
38507
+ method: req.method ?? "POST",
38508
+ headers: req.headers,
38509
+ body: typeof req.body === "string" ? req.body : JSON.stringify(req.body)
38510
+ };
38511
+ if (req.signal) init.signal = req.signal;
38512
+ const res = await globalThis.fetch(req.url, init);
38513
+ const headers = {};
38514
+ res.headers.forEach((v, k) => {
38515
+ headers[k] = v;
38516
+ });
38517
+ const body = await res.json().catch(() => null);
38518
+ return { status: res.status, headers, body };
38519
+ };
38520
+ }
38521
+ var ClientResolver = class {
38522
+ constructor(cfg) {
38523
+ this.cfg = cfg;
38524
+ this.pool = new ClientPool(cfg.catalog);
38525
+ }
38526
+ cfg;
38527
+ pool;
38528
+ /** Turn `"anthropic/claude-haiku-4-5"` → resolved client. */
38529
+ resolve(modelId) {
38530
+ const [provider, model] = parseModelId(modelId);
38531
+ const apiKey = this.cfg.apiKeys[provider];
38532
+ if (!apiKey) {
38533
+ const known = Object.keys(this.cfg.apiKeys).filter(
38534
+ (k) => !!this.cfg.apiKeys[k]
38535
+ );
38536
+ throw new Error(
38537
+ `ClientResolver: no API key for provider "${provider}". Configured providers: [${known.join(", ") || "none"}]`
38538
+ );
38539
+ }
38540
+ const fetchFn = this.cfg.fetch ?? directFetch();
38541
+ const client = this.pool.get(provider, model, {
38542
+ provider,
38543
+ apiKey,
38544
+ hooks: this.cfg.hooks,
38545
+ model,
38546
+ fetch: fetchFn,
38547
+ fetchStream: this.cfg.fetchStream,
38548
+ ...this.cfg.clientOptions
38549
+ });
38550
+ return { client, provider, model };
38551
+ }
38552
+ availableProviders() {
38553
+ return Object.keys(this.cfg.apiKeys).filter((p) => !!this.cfg.apiKeys[p]);
38554
+ }
38555
+ async destroy() {
38556
+ await this.pool.destroy();
38557
+ }
38558
+ get size() {
38559
+ return this.pool.size;
38560
+ }
38561
+ };
38562
+ function parseModelId(modelId) {
38563
+ const slash = modelId.indexOf("/");
38564
+ if (slash <= 0 || slash === modelId.length - 1) {
38565
+ throw new Error(`Invalid model id "${modelId}" \u2014 expected format "provider/model"`);
38566
+ }
38567
+ const provider = modelId.slice(0, slash);
38568
+ const model = modelId.slice(slash + 1);
38569
+ return [provider, model];
38570
+ }
38571
+ function isNamespacedModelId(modelId) {
38572
+ const slash = modelId.indexOf("/");
38573
+ return slash > 0 && slash < modelId.length - 1;
38574
+ }
38575
+ function resolveModel(model, provider, label) {
38576
+ if (isNamespacedModelId(model)) {
38577
+ const [p, m] = parseModelId(model);
38578
+ return { provider: p, model: m };
38579
+ }
38580
+ if (!provider) {
38581
+ throw new Error(
38582
+ `${label}: bare model "${model}" requires a provider \u2014 pass it explicitly or use "provider/model".`
38583
+ );
38584
+ }
38585
+ return { provider, model };
38586
+ }
38587
+ var TIER_SUFFIXES = /* @__PURE__ */ new Set(["auto", "standard", "priority", "flex", "scale"]);
38588
+ function parseModelTier(modelId) {
38589
+ const colon = modelId.lastIndexOf(":");
38590
+ if (colon <= 0) return { modelId };
38591
+ const suffix = modelId.slice(colon + 1);
38592
+ if (!TIER_SUFFIXES.has(suffix)) return { modelId };
38593
+ return { modelId: modelId.slice(0, colon), serviceTier: suffix };
38594
+ }
38595
+
38596
+ // src/helpers/engine.ts
38597
+ function createEngine(config = {}) {
38598
+ const sessionId = config.sessionId ?? `sess_${crypto.randomUUID().slice(0, 12)}`;
38599
+ const hooks = config.hooks ?? new HookBus();
38600
+ const bus = config.bus ?? new AgentBus();
38601
+ const persistence = resolvePersistence(config.persistence);
38602
+ const cache2 = resolveCache(config.cache);
38603
+ const catalog = resolveCatalog(config.catalog);
38604
+ const network = new NetworkEngine({ hooks, fetch: config.fetch, retry: config.retry, queues: config.queues });
38605
+ const fetchBound = (req, options) => network.fetch(req, options);
38606
+ const fetchStreamBound = (req, options) => network.fetchStream(req, options);
38607
+ const connectBound = (req) => network.connect(req);
38608
+ const cost = new CostCollector({ hooks, catalog });
38609
+ const telemetry = config.telemetry ? new TelemetryAdapter(hooks, config.telemetry) : null;
38610
+ const handle = {
38611
+ sessionId,
38612
+ hooks,
38613
+ bus,
38614
+ persistence,
38615
+ cache: cache2,
38616
+ network,
38617
+ fetch: fetchBound,
38618
+ fetchStream: fetchStreamBound,
38619
+ connect: connectBound,
38620
+ catalog,
38621
+ cost,
38622
+ telemetry,
38623
+ apiKeys: config.apiKeys ?? {},
38624
+ // Bound inside the literal so the closure captures this handle. The body runs
38625
+ // only when a caller asks for a client, so referencing `handle` here is safe.
38626
+ createClient: (options) => createLLM({ ...options, engine: handle }),
38627
+ destroy() {
38628
+ cost.destroy();
38629
+ telemetry?.destroy();
38630
+ network.destroy();
38631
+ }
38632
+ };
38633
+ if (config.registerAsDefault !== false) {
38634
+ coreRegistry.set(handle);
38635
+ }
38636
+ return handle;
38637
+ }
38638
+ function resolveCatalog(config) {
38639
+ const c = new ModelCatalog();
38640
+ if (!config) return c;
38641
+ if (config instanceof ModelCatalog) return config;
38642
+ if (config === true || config === "defaults") {
38643
+ c.loadProviderDefaults();
38644
+ return c;
38645
+ }
38646
+ if (typeof config === "object" && "entries" in config) {
38647
+ c.load(config.entries);
38648
+ return c;
38649
+ }
38650
+ return c;
38651
+ }
38652
+ function resolvePersistence(config) {
38653
+ if (!config) return new MemoryPersistence();
38654
+ if (typeof config.get === "function") {
38655
+ return config;
38656
+ }
38657
+ const c = config;
38658
+ if (c.type === "memory") return new MemoryPersistence();
38659
+ if (c.type === "file") {
38660
+ if (!c.dir) {
38661
+ throw new Error('createEngine: persistence type "file" requires a `dir` field');
38662
+ }
38663
+ return new FilePersistence(c.dir);
38664
+ }
38665
+ throw new Error(`createEngine: unknown persistence type "${c.type}"`);
38666
+ }
38667
+ function resolveCache(config) {
38668
+ if (!config) return null;
38669
+ if (config instanceof Cache) return config;
38670
+ const c = config;
38671
+ if (c.type === "memory") return new Cache({ store: new MemoryCacheStore() });
38672
+ throw new Error(`createEngine: unknown cache type "${c.type}"`);
38673
+ }
38674
+ var CoreRegistry = class {
38675
+ current = null;
38676
+ /** Get the current default engine, creating a bare one on first read. */
38677
+ get() {
38678
+ if (!this.current) this.current = createEngine();
38679
+ return this.current;
38680
+ }
38681
+ /** Set the default engine. Throws if one is already set unless replace=true.
38682
+ * When replacing, the previous engine is destroyed AFTER the pointer
38683
+ * swap so engine.destroy callbacks can safely query the registry. */
38684
+ set(engine, opts = {}) {
38685
+ if (this.current && !opts.replace) {
38686
+ throw new Error(
38687
+ "coreRegistry: an engine is already registered. Create additional engines with createEngine({ registerAsDefault: false }) and pass them explicitly to helpers, or use coreRegistry.set(engine, { replace: true }) to override."
38688
+ );
38689
+ }
38690
+ const previous = this.current;
38691
+ this.current = engine;
38692
+ if (previous && opts.replace) {
38693
+ previous.destroy();
38694
+ }
38695
+ }
38696
+ /** Clear the default engine. */
38697
+ clear() {
38698
+ this.current?.destroy();
38699
+ this.current = null;
38700
+ }
38701
+ has() {
38702
+ return this.current !== null;
38703
+ }
38704
+ };
38705
+ var coreRegistry = new CoreRegistry();
38706
+
38707
+ // src/helpers/llm.ts
38708
+ function createLLM(opts) {
38709
+ const engine = opts.engine ?? coreRegistry.get();
38710
+ const { provider, model } = resolveModel(opts.model, opts.provider, "createLLM");
38711
+ const sendModel = engine.catalog.resolveModelId(provider, model);
38712
+ const apiKey = opts.apiKey ?? engine.apiKeys[provider];
38713
+ if (!apiKey) {
38714
+ throw new Error(
38715
+ `createLLM: no API key for provider "${provider}". Pass apiKey directly or set engine.apiKeys["${provider}"] via createEngine.`
38716
+ );
38717
+ }
38718
+ const adapter = opts.adapter ?? defaultAdapterFactory();
38719
+ return new LLMClient({
38720
+ ...opts,
38721
+ provider,
38722
+ model: sendModel,
38723
+ apiKey,
38724
+ adapter,
38725
+ fetch: opts.fetch ?? engine.fetch,
38726
+ fetchStream: opts.fetchStream ?? engine.fetchStream,
38727
+ hooks: opts.hooks ?? engine.hooks,
38728
+ sessionId: engine.sessionId,
38729
+ catalog: engine.catalog
38730
+ });
38731
+ }
38732
+ function defaultAdapterFactory() {
38733
+ return (provider, apiKey, api, baseURL) => {
38734
+ const cfg = { apiKey, baseURL };
38735
+ switch (provider) {
38736
+ case "anthropic":
38737
+ return new AnthropicAdapter(cfg);
38738
+ case "openai":
38739
+ return api === "responses" ? new OpenAIResponsesAdapter(cfg) : new OpenAIAdapter(cfg);
38740
+ case "google":
38741
+ return api === "interactions" ? new GoogleInteractionsAdapter(cfg) : new GoogleAdapter(cfg);
38742
+ case "xai":
38743
+ return api === "responses" ? new XAIResponsesAdapter(cfg) : new XAIAdapter(cfg);
38744
+ case "openrouter":
38745
+ return api === "responses" ? new OpenRouterResponsesAdapter(cfg) : new OpenRouterAdapter(cfg);
38746
+ default:
38747
+ throw new Error(`createLLM: no default adapter for provider '${provider}'`);
38748
+ }
38749
+ };
38750
+ }
38751
+
38208
38752
  // src/helpers/agent.ts
38209
38753
  function createAgent(opts) {
38210
38754
  const engine = opts.engine ?? coreRegistry.get();
@@ -40358,10 +40902,10 @@ function toStopReason(finish) {
40358
40902
  if (finish === "stop") return "endTurn";
40359
40903
  return finish;
40360
40904
  }
40361
- function samplingHandler(config) {
40905
+ function samplingHandlerWith(complete2, config) {
40362
40906
  if (typeof config === "function") return config;
40363
40907
  return async (params) => {
40364
- const result = await complete({
40908
+ const result = await complete2({
40365
40909
  model: config.model,
40366
40910
  provider: config.provider,
40367
40911
  engine: config.engine,
@@ -41146,6 +41690,9 @@ var WsTransport = class extends BaseJsonRpcTransport {
41146
41690
  };
41147
41691
 
41148
41692
  // src/helpers/mcp.ts
41693
+ function samplingHandler(config) {
41694
+ return samplingHandlerWith(complete, config);
41695
+ }
41149
41696
  function defaultNamespace(config) {
41150
41697
  if (isHttpConfig(config)) {
41151
41698
  if (config.name) return config.name;