@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
package/dist/index.js CHANGED
@@ -3252,8 +3252,8 @@ function strictSupport(schema, dialect) {
3252
3252
  return reason ? { ok: false, reason } : { ok: true };
3253
3253
  }
3254
3254
 
3255
- // src/llm/providers/anthropic/catalog.json
3256
- var catalog_default = {
3255
+ // src/catalog/data/anthropic.json
3256
+ var anthropic_default = {
3257
3257
  "anthropic/claude-opus-4": {
3258
3258
  providerModelName: "claude-opus-4-20250514",
3259
3259
  aliases: [
@@ -3310,7 +3310,12 @@ var catalog_default = {
3310
3310
  deprecation: {
3311
3311
  date: "2026-05-14",
3312
3312
  source: "litellm"
3313
- }
3313
+ },
3314
+ wire: {
3315
+ thinking: "budgeted",
3316
+ topK: false
3317
+ },
3318
+ wireSpec: "anthropic/messages@4.0"
3314
3319
  },
3315
3320
  "anthropic/claude-opus-4.1": {
3316
3321
  providerModelName: "claude-opus-4-1-20250805",
@@ -3368,7 +3373,12 @@ var catalog_default = {
3368
3373
  deprecation: {
3369
3374
  date: "2026-08-05",
3370
3375
  source: "litellm"
3371
- }
3376
+ },
3377
+ wire: {
3378
+ thinking: "budgeted",
3379
+ topK: true
3380
+ },
3381
+ wireSpec: "anthropic/messages@4.1"
3372
3382
  },
3373
3383
  "anthropic/claude-opus-4.5": {
3374
3384
  providerModelName: "claude-opus-4-5-20251101",
@@ -3422,7 +3432,12 @@ var catalog_default = {
3422
3432
  family: "claude-opus",
3423
3433
  version: "4.5",
3424
3434
  status: "legacy",
3425
- active: true
3435
+ active: true,
3436
+ wire: {
3437
+ thinking: "budgeted",
3438
+ topK: true
3439
+ },
3440
+ wireSpec: "anthropic/messages@4.1"
3426
3441
  },
3427
3442
  "anthropic/claude-opus-4.6": {
3428
3443
  providerModelName: "claude-opus-4-6",
@@ -3480,7 +3495,12 @@ var catalog_default = {
3480
3495
  family: "claude-opus",
3481
3496
  version: "4.6",
3482
3497
  status: "stable",
3483
- active: true
3498
+ active: true,
3499
+ wire: {
3500
+ thinking: "adaptive",
3501
+ topK: true
3502
+ },
3503
+ wireSpec: "anthropic/messages@4.6"
3484
3504
  },
3485
3505
  "anthropic/claude-opus-4.7": {
3486
3506
  providerModelName: "claude-opus-4-7",
@@ -3538,7 +3558,12 @@ var catalog_default = {
3538
3558
  family: "claude-opus",
3539
3559
  version: "4.7",
3540
3560
  status: "stable",
3541
- active: true
3561
+ active: true,
3562
+ wire: {
3563
+ thinking: "adaptive",
3564
+ topK: false
3565
+ },
3566
+ wireSpec: "anthropic/messages@4.7"
3542
3567
  },
3543
3568
  "anthropic/claude-opus-4.8": {
3544
3569
  providerModelName: "claude-opus-4-8",
@@ -3596,7 +3621,12 @@ var catalog_default = {
3596
3621
  family: "claude-opus",
3597
3622
  version: "4.8",
3598
3623
  status: "stable",
3599
- active: true
3624
+ active: true,
3625
+ wire: {
3626
+ thinking: "adaptive",
3627
+ topK: false
3628
+ },
3629
+ wireSpec: "anthropic/messages@4.7"
3600
3630
  },
3601
3631
  "anthropic/claude-sonnet-4": {
3602
3632
  providerModelName: "claude-sonnet-4-20250514",
@@ -3654,7 +3684,12 @@ var catalog_default = {
3654
3684
  deprecation: {
3655
3685
  date: "2026-05-14",
3656
3686
  source: "litellm"
3657
- }
3687
+ },
3688
+ wire: {
3689
+ thinking: "budgeted",
3690
+ topK: false
3691
+ },
3692
+ wireSpec: "anthropic/messages@4.0"
3658
3693
  },
3659
3694
  "anthropic/claude-sonnet-4.5": {
3660
3695
  providerModelName: "claude-sonnet-4-5-20250929",
@@ -3708,7 +3743,12 @@ var catalog_default = {
3708
3743
  family: "claude-sonnet",
3709
3744
  version: "4.5",
3710
3745
  status: "stable",
3711
- active: true
3746
+ active: true,
3747
+ wire: {
3748
+ thinking: "budgeted",
3749
+ topK: true
3750
+ },
3751
+ wireSpec: "anthropic/messages@4.1"
3712
3752
  },
3713
3753
  "anthropic/claude-sonnet-4.6": {
3714
3754
  providerModelName: "claude-sonnet-4-6",
@@ -3762,7 +3802,12 @@ var catalog_default = {
3762
3802
  family: "claude-sonnet",
3763
3803
  version: "4.6",
3764
3804
  status: "stable",
3765
- active: true
3805
+ active: true,
3806
+ wire: {
3807
+ thinking: "adaptive",
3808
+ topK: true
3809
+ },
3810
+ wireSpec: "anthropic/messages@4.6"
3766
3811
  },
3767
3812
  "anthropic/claude-haiku-4.5": {
3768
3813
  providerModelName: "claude-haiku-4-5-20251001",
@@ -3816,7 +3861,12 @@ var catalog_default = {
3816
3861
  family: "claude-haiku",
3817
3862
  version: "4.5",
3818
3863
  status: "stable",
3819
- active: true
3864
+ active: true,
3865
+ wire: {
3866
+ thinking: "budgeted",
3867
+ topK: true
3868
+ },
3869
+ wireSpec: "anthropic/messages@4.1"
3820
3870
  },
3821
3871
  "anthropic/claude-fable-5": {
3822
3872
  providerModelName: "claude-fable-5",
@@ -3870,7 +3920,12 @@ var catalog_default = {
3870
3920
  family: "claude-fable",
3871
3921
  version: "5",
3872
3922
  status: "stable",
3873
- active: true
3923
+ active: true,
3924
+ wire: {
3925
+ thinking: "adaptive",
3926
+ topK: false
3927
+ },
3928
+ wireSpec: "anthropic/messages@4.7"
3874
3929
  },
3875
3930
  "anthropic/claude-sonnet-5": {
3876
3931
  providerModelName: "claude-sonnet-5",
@@ -3924,7 +3979,12 @@ var catalog_default = {
3924
3979
  family: "claude-sonnet",
3925
3980
  version: "5",
3926
3981
  status: "stable",
3927
- active: true
3982
+ active: true,
3983
+ wire: {
3984
+ thinking: "adaptive",
3985
+ topK: false
3986
+ },
3987
+ wireSpec: "anthropic/messages@4.7"
3928
3988
  },
3929
3989
  "anthropic/claude-mythos-5": {
3930
3990
  providerModelName: "claude-mythos-5",
@@ -3975,7 +4035,12 @@ var catalog_default = {
3975
4035
  version: "5",
3976
4036
  status: "stable",
3977
4037
  active: false,
3978
- availability: "limited"
4038
+ availability: "limited",
4039
+ wire: {
4040
+ thinking: "adaptive",
4041
+ topK: false
4042
+ },
4043
+ wireSpec: "anthropic/messages@4.7"
3979
4044
  },
3980
4045
  "anthropic/claude-opus-5": {
3981
4046
  providerModelName: "claude-opus-5",
@@ -4033,12 +4098,17 @@ var catalog_default = {
4033
4098
  family: "claude-opus",
4034
4099
  version: "5",
4035
4100
  status: "stable",
4036
- active: true
4101
+ active: true,
4102
+ wire: {
4103
+ thinking: "adaptive",
4104
+ topK: false
4105
+ },
4106
+ wireSpec: "anthropic/messages@4.7"
4037
4107
  }
4038
4108
  };
4039
4109
 
4040
- // src/llm/providers/google/catalog.json
4041
- var catalog_default2 = {
4110
+ // src/catalog/data/google.json
4111
+ var google_default = {
4042
4112
  "google/gemini-2.5-pro": {
4043
4113
  providerModelName: "gemini-2.5-pro",
4044
4114
  aliases: [
@@ -4102,7 +4172,11 @@ var catalog_default2 = {
4102
4172
  family: "gemini-pro",
4103
4173
  version: "2.5",
4104
4174
  status: "stable",
4105
- active: true
4175
+ active: true,
4176
+ wire: {
4177
+ thinking: "budget"
4178
+ },
4179
+ wireSpec: "google/generate@2.5"
4106
4180
  },
4107
4181
  "google/gemini-3.1-pro": {
4108
4182
  providerModelName: "gemini-3.1-pro-preview",
@@ -4168,7 +4242,11 @@ var catalog_default2 = {
4168
4242
  family: "gemini-pro",
4169
4243
  version: "3.1",
4170
4244
  status: "preview",
4171
- active: true
4245
+ active: true,
4246
+ wire: {
4247
+ thinking: "level"
4248
+ },
4249
+ wireSpec: "google/generate@3"
4172
4250
  },
4173
4251
  "google/gemini-3.1-pro-customtools": {
4174
4252
  providerModelName: "gemini-3.1-pro-preview-customtools",
@@ -4216,7 +4294,11 @@ var catalog_default2 = {
4216
4294
  family: "gemini-pro",
4217
4295
  version: "3.1",
4218
4296
  status: "preview",
4219
- active: true
4297
+ active: true,
4298
+ wire: {
4299
+ thinking: "level"
4300
+ },
4301
+ wireSpec: "google/generate@3"
4220
4302
  },
4221
4303
  "google/gemini-2.5-flash": {
4222
4304
  providerModelName: "gemini-2.5-flash",
@@ -4285,7 +4367,11 @@ var catalog_default2 = {
4285
4367
  family: "gemini-flash",
4286
4368
  version: "2.5",
4287
4369
  status: "stable",
4288
- active: true
4370
+ active: true,
4371
+ wire: {
4372
+ thinking: "budget"
4373
+ },
4374
+ wireSpec: "google/generate@2.5"
4289
4375
  },
4290
4376
  "google/gemini-3-flash": {
4291
4377
  providerModelName: "gemini-3-flash-preview",
@@ -4354,7 +4440,11 @@ var catalog_default2 = {
4354
4440
  family: "gemini-flash",
4355
4441
  version: "3",
4356
4442
  status: "preview",
4357
- active: true
4443
+ active: true,
4444
+ wire: {
4445
+ thinking: "level"
4446
+ },
4447
+ wireSpec: "google/generate@3"
4358
4448
  },
4359
4449
  "google/gemini-3.5-flash": {
4360
4450
  providerModelName: "gemini-3.5-flash",
@@ -4419,7 +4509,11 @@ var catalog_default2 = {
4419
4509
  family: "gemini-flash",
4420
4510
  version: "3.5",
4421
4511
  status: "stable",
4422
- active: true
4512
+ active: true,
4513
+ wire: {
4514
+ thinking: "level"
4515
+ },
4516
+ wireSpec: "google/generate@3"
4423
4517
  },
4424
4518
  "google/gemini-2.5-flash-lite": {
4425
4519
  providerModelName: "gemini-2.5-flash-lite",
@@ -4488,7 +4582,11 @@ var catalog_default2 = {
4488
4582
  family: "gemini-flash-lite",
4489
4583
  version: "2.5",
4490
4584
  status: "stable",
4491
- active: true
4585
+ active: true,
4586
+ wire: {
4587
+ thinking: "budget"
4588
+ },
4589
+ wireSpec: "google/generate@2.5"
4492
4590
  },
4493
4591
  "google/gemini-3.1-flash-lite": {
4494
4592
  providerModelName: "gemini-3.1-flash-lite",
@@ -4558,7 +4656,11 @@ var catalog_default2 = {
4558
4656
  family: "gemini-flash-lite",
4559
4657
  version: "3.1",
4560
4658
  status: "stable",
4561
- active: true
4659
+ active: true,
4660
+ wire: {
4661
+ thinking: "level"
4662
+ },
4663
+ wireSpec: "google/generate@3"
4562
4664
  },
4563
4665
  "google/gemini-2.5-flash-image": {
4564
4666
  providerModelName: "gemini-2.5-flash-image",
@@ -5458,7 +5560,11 @@ var catalog_default2 = {
5458
5560
  family: "gemma",
5459
5561
  version: "4",
5460
5562
  status: "stable",
5461
- active: true
5563
+ active: true,
5564
+ wire: {
5565
+ thinking: "level"
5566
+ },
5567
+ wireSpec: "google/generate@3"
5462
5568
  },
5463
5569
  "google/gemma-4-31b": {
5464
5570
  providerModelName: "gemma-4-31b-it",
@@ -5505,7 +5611,11 @@ var catalog_default2 = {
5505
5611
  family: "gemma",
5506
5612
  version: "4",
5507
5613
  status: "stable",
5508
- active: true
5614
+ active: true,
5615
+ wire: {
5616
+ thinking: "level"
5617
+ },
5618
+ wireSpec: "google/generate@3"
5509
5619
  },
5510
5620
  "google/imagen-4": {
5511
5621
  providerModelName: "imagen-4.0-generate-001",
@@ -6564,7 +6674,11 @@ var catalog_default2 = {
6564
6674
  family: "gemini-flash",
6565
6675
  version: "3.6",
6566
6676
  status: "stable",
6567
- active: true
6677
+ active: true,
6678
+ wire: {
6679
+ thinking: "level"
6680
+ },
6681
+ wireSpec: "google/generate@3"
6568
6682
  },
6569
6683
  "google/gemini-3.5-flash-lite": {
6570
6684
  providerModelName: "gemini-3.5-flash-lite",
@@ -6630,12 +6744,16 @@ var catalog_default2 = {
6630
6744
  family: "gemini-flash-lite",
6631
6745
  version: "3.5",
6632
6746
  status: "stable",
6633
- active: true
6747
+ active: true,
6748
+ wire: {
6749
+ thinking: "level"
6750
+ },
6751
+ wireSpec: "google/generate@3"
6634
6752
  }
6635
6753
  };
6636
6754
 
6637
- // src/llm/providers/openai/catalog.json
6638
- var catalog_default3 = {
6755
+ // src/catalog/data/openai.json
6756
+ var openai_default = {
6639
6757
  "openai/gpt-3.5-turbo": {
6640
6758
  providerModelName: "gpt-3.5-turbo",
6641
6759
  aliases: [
@@ -6683,7 +6801,8 @@ var catalog_default3 = {
6683
6801
  family: "gpt",
6684
6802
  version: "3.5",
6685
6803
  status: "legacy",
6686
- active: true
6804
+ active: true,
6805
+ wireSpec: "openai/responses"
6687
6806
  },
6688
6807
  "openai/gpt-4": {
6689
6808
  providerModelName: "gpt-4",
@@ -6730,7 +6849,8 @@ var catalog_default3 = {
6730
6849
  family: "gpt",
6731
6850
  version: "4",
6732
6851
  status: "legacy",
6733
- active: true
6852
+ active: true,
6853
+ wireSpec: "openai/responses"
6734
6854
  },
6735
6855
  "openai/gpt-4-turbo": {
6736
6856
  providerModelName: "gpt-4-turbo",
@@ -6778,7 +6898,8 @@ var catalog_default3 = {
6778
6898
  family: "gpt",
6779
6899
  version: "4",
6780
6900
  status: "legacy",
6781
- active: true
6901
+ active: true,
6902
+ wireSpec: "openai/responses"
6782
6903
  },
6783
6904
  "openai/gpt-4.1": {
6784
6905
  providerModelName: "gpt-4.1",
@@ -6827,7 +6948,8 @@ var catalog_default3 = {
6827
6948
  family: "gpt",
6828
6949
  version: "4.1",
6829
6950
  status: "legacy",
6830
- active: true
6951
+ active: true,
6952
+ wireSpec: "openai/responses"
6831
6953
  },
6832
6954
  "openai/gpt-5": {
6833
6955
  providerModelName: "gpt-5",
@@ -6876,7 +6998,8 @@ var catalog_default3 = {
6876
6998
  family: "gpt",
6877
6999
  version: "5",
6878
7000
  status: "legacy",
6879
- active: true
7001
+ active: true,
7002
+ wireSpec: "openai/responses"
6880
7003
  },
6881
7004
  "openai/gpt-5-search": {
6882
7005
  providerModelName: "gpt-5-search-api",
@@ -6974,7 +7097,8 @@ var catalog_default3 = {
6974
7097
  family: "gpt",
6975
7098
  version: "5.1",
6976
7099
  status: "legacy",
6977
- active: true
7100
+ active: true,
7101
+ wireSpec: "openai/responses"
6978
7102
  },
6979
7103
  "openai/gpt-5.2": {
6980
7104
  providerModelName: "gpt-5.2",
@@ -7023,7 +7147,8 @@ var catalog_default3 = {
7023
7147
  family: "gpt",
7024
7148
  version: "5.2",
7025
7149
  status: "stable",
7026
- active: true
7150
+ active: true,
7151
+ wireSpec: "openai/responses"
7027
7152
  },
7028
7153
  "openai/gpt-5.4": {
7029
7154
  providerModelName: "gpt-5.4",
@@ -7089,7 +7214,8 @@ var catalog_default3 = {
7089
7214
  family: "gpt",
7090
7215
  version: "5.4",
7091
7216
  status: "stable",
7092
- active: true
7217
+ active: true,
7218
+ wireSpec: "openai/responses"
7093
7219
  },
7094
7220
  "openai/gpt-5.5": {
7095
7221
  providerModelName: "gpt-5.5",
@@ -7155,7 +7281,8 @@ var catalog_default3 = {
7155
7281
  family: "gpt",
7156
7282
  version: "5.5",
7157
7283
  status: "stable",
7158
- active: true
7284
+ active: true,
7285
+ wireSpec: "openai/responses"
7159
7286
  },
7160
7287
  "openai/gpt-5-chat": {
7161
7288
  providerModelName: "gpt-5-chat-latest",
@@ -7203,7 +7330,8 @@ var catalog_default3 = {
7203
7330
  family: "gpt-chat",
7204
7331
  version: "5",
7205
7332
  status: "legacy",
7206
- active: false
7333
+ active: false,
7334
+ wireSpec: "openai/responses"
7207
7335
  },
7208
7336
  "openai/gpt-5.1-chat": {
7209
7337
  providerModelName: "gpt-5.1-chat-latest",
@@ -7251,7 +7379,8 @@ var catalog_default3 = {
7251
7379
  family: "gpt-chat",
7252
7380
  version: "5.1",
7253
7381
  status: "legacy",
7254
- active: false
7382
+ active: false,
7383
+ wireSpec: "openai/responses"
7255
7384
  },
7256
7385
  "openai/gpt-5.2-chat": {
7257
7386
  providerModelName: "gpt-5.2-chat-latest",
@@ -7303,7 +7432,8 @@ var catalog_default3 = {
7303
7432
  deprecation: {
7304
7433
  shutdownDate: "2026-08-10",
7305
7434
  source: "openrouter"
7306
- }
7435
+ },
7436
+ wireSpec: "openai/responses"
7307
7437
  },
7308
7438
  "openai/gpt-5.3-chat": {
7309
7439
  providerModelName: "gpt-5.3-chat-latest",
@@ -7355,7 +7485,8 @@ var catalog_default3 = {
7355
7485
  deprecation: {
7356
7486
  shutdownDate: "2026-08-10",
7357
7487
  source: "openrouter"
7358
- }
7488
+ },
7489
+ wireSpec: "openai/responses"
7359
7490
  },
7360
7491
  "openai/gpt-5-codex": {
7361
7492
  providerModelName: "gpt-5-codex",
@@ -7693,7 +7824,8 @@ var catalog_default3 = {
7693
7824
  family: "gpt-mini",
7694
7825
  version: "4.1",
7695
7826
  status: "legacy",
7696
- active: true
7827
+ active: true,
7828
+ wireSpec: "openai/responses"
7697
7829
  },
7698
7830
  "openai/gpt-5-mini": {
7699
7831
  providerModelName: "gpt-5-mini",
@@ -7742,7 +7874,8 @@ var catalog_default3 = {
7742
7874
  family: "gpt-mini",
7743
7875
  version: "5",
7744
7876
  status: "legacy",
7745
- active: true
7877
+ active: true,
7878
+ wireSpec: "openai/responses"
7746
7879
  },
7747
7880
  "openai/gpt-5.4-mini": {
7748
7881
  providerModelName: "gpt-5.4-mini",
@@ -7808,7 +7941,8 @@ var catalog_default3 = {
7808
7941
  family: "gpt-mini",
7809
7942
  version: "5.4",
7810
7943
  status: "stable",
7811
- active: true
7944
+ active: true,
7945
+ wireSpec: "openai/responses"
7812
7946
  },
7813
7947
  "openai/gpt-4.1-nano": {
7814
7948
  providerModelName: "gpt-4.1-nano",
@@ -7857,7 +7991,8 @@ var catalog_default3 = {
7857
7991
  family: "gpt-nano",
7858
7992
  version: "4.1",
7859
7993
  status: "legacy",
7860
- active: true
7994
+ active: true,
7995
+ wireSpec: "openai/responses"
7861
7996
  },
7862
7997
  "openai/gpt-5-nano": {
7863
7998
  providerModelName: "gpt-5-nano",
@@ -7906,7 +8041,8 @@ var catalog_default3 = {
7906
8041
  family: "gpt-nano",
7907
8042
  version: "5",
7908
8043
  status: "legacy",
7909
- active: true
8044
+ active: true,
8045
+ wireSpec: "openai/responses"
7910
8046
  },
7911
8047
  "openai/gpt-5.4-nano": {
7912
8048
  providerModelName: "gpt-5.4-nano",
@@ -7967,7 +8103,8 @@ var catalog_default3 = {
7967
8103
  family: "gpt-nano",
7968
8104
  version: "5.4",
7969
8105
  status: "stable",
7970
- active: true
8106
+ active: true,
8107
+ wireSpec: "openai/responses"
7971
8108
  },
7972
8109
  "openai/gpt-5-pro": {
7973
8110
  providerModelName: "gpt-5-pro",
@@ -8014,7 +8151,8 @@ var catalog_default3 = {
8014
8151
  family: "gpt-pro",
8015
8152
  version: "5",
8016
8153
  status: "legacy",
8017
- active: true
8154
+ active: true,
8155
+ wireSpec: "openai/responses"
8018
8156
  },
8019
8157
  "openai/gpt-5.2-pro": {
8020
8158
  providerModelName: "gpt-5.2-pro",
@@ -8061,7 +8199,8 @@ var catalog_default3 = {
8061
8199
  family: "gpt-pro",
8062
8200
  version: "5.2",
8063
8201
  status: "legacy",
8064
- active: true
8202
+ active: true,
8203
+ wireSpec: "openai/responses"
8065
8204
  },
8066
8205
  "openai/gpt-5.4-pro": {
8067
8206
  providerModelName: "gpt-5.4-pro",
@@ -8118,7 +8257,8 @@ var catalog_default3 = {
8118
8257
  family: "gpt-pro",
8119
8258
  version: "5.4",
8120
8259
  status: "stable",
8121
- active: true
8260
+ active: true,
8261
+ wireSpec: "openai/responses"
8122
8262
  },
8123
8263
  "openai/gpt-5.5-pro": {
8124
8264
  providerModelName: "gpt-5.5-pro",
@@ -8175,7 +8315,8 @@ var catalog_default3 = {
8175
8315
  family: "gpt-pro",
8176
8316
  version: "5.5",
8177
8317
  status: "stable",
8178
- active: true
8318
+ active: true,
8319
+ wireSpec: "openai/responses"
8179
8320
  },
8180
8321
  "openai/gpt-4o": {
8181
8322
  providerModelName: "gpt-4o",
@@ -8225,7 +8366,8 @@ var catalog_default3 = {
8225
8366
  ],
8226
8367
  family: "gpt-4o",
8227
8368
  version: "4o",
8228
- active: true
8369
+ active: true,
8370
+ wireSpec: "openai/responses"
8229
8371
  },
8230
8372
  "openai/gpt-4o-mini": {
8231
8373
  providerModelName: "gpt-4o-mini",
@@ -8275,7 +8417,8 @@ var catalog_default3 = {
8275
8417
  ],
8276
8418
  family: "gpt-4o",
8277
8419
  version: "4o",
8278
- active: true
8420
+ active: true,
8421
+ wireSpec: "openai/responses"
8279
8422
  },
8280
8423
  "openai/gpt-4o-search": {
8281
8424
  providerModelName: "gpt-4o-search-preview",
@@ -9219,7 +9362,8 @@ var catalog_default3 = {
9219
9362
  ],
9220
9363
  family: "o-series",
9221
9364
  version: "1",
9222
- active: true
9365
+ active: true,
9366
+ wireSpec: "openai/responses"
9223
9367
  },
9224
9368
  "openai/o1-pro": {
9225
9369
  providerModelName: "o1-pro",
@@ -9265,7 +9409,8 @@ var catalog_default3 = {
9265
9409
  ],
9266
9410
  family: "o-series",
9267
9411
  version: "1",
9268
- active: true
9412
+ active: true,
9413
+ wireSpec: "openai/responses"
9269
9414
  },
9270
9415
  "openai/o3": {
9271
9416
  providerModelName: "o3",
@@ -9313,7 +9458,8 @@ var catalog_default3 = {
9313
9458
  ],
9314
9459
  family: "o-series",
9315
9460
  version: "3",
9316
- active: true
9461
+ active: true,
9462
+ wireSpec: "openai/responses"
9317
9463
  },
9318
9464
  "openai/o3-mini": {
9319
9465
  providerModelName: "o3-mini",
@@ -9360,7 +9506,8 @@ var catalog_default3 = {
9360
9506
  ],
9361
9507
  family: "o-series",
9362
9508
  version: "3",
9363
- active: true
9509
+ active: true,
9510
+ wireSpec: "openai/responses"
9364
9511
  },
9365
9512
  "openai/o3-pro": {
9366
9513
  providerModelName: "o3-pro",
@@ -9406,7 +9553,8 @@ var catalog_default3 = {
9406
9553
  ],
9407
9554
  family: "o-series",
9408
9555
  version: "3",
9409
- active: true
9556
+ active: true,
9557
+ wireSpec: "openai/responses"
9410
9558
  },
9411
9559
  "openai/o4-mini": {
9412
9560
  providerModelName: "o4-mini",
@@ -9461,7 +9609,8 @@ var catalog_default3 = {
9461
9609
  ],
9462
9610
  family: "o-series",
9463
9611
  version: "4",
9464
- active: true
9612
+ active: true,
9613
+ wireSpec: "openai/responses"
9465
9614
  },
9466
9615
  "openai/sora-2": {
9467
9616
  providerModelName: "sora-2",
@@ -10386,7 +10535,8 @@ var catalog_default3 = {
10386
10535
  family: "gpt-sol",
10387
10536
  version: "5.6",
10388
10537
  status: "stable",
10389
- active: true
10538
+ active: true,
10539
+ wireSpec: "openai/responses"
10390
10540
  },
10391
10541
  "openai/gpt-5.6-terra": {
10392
10542
  providerModelName: "gpt-5.6-terra",
@@ -10452,7 +10602,8 @@ var catalog_default3 = {
10452
10602
  family: "gpt-terra",
10453
10603
  version: "5.6",
10454
10604
  status: "stable",
10455
- active: true
10605
+ active: true,
10606
+ wireSpec: "openai/responses"
10456
10607
  },
10457
10608
  "openai/gpt-5.6-luna": {
10458
10609
  providerModelName: "gpt-5.6-luna",
@@ -10518,12 +10669,13 @@ var catalog_default3 = {
10518
10669
  family: "gpt-luna",
10519
10670
  version: "5.6",
10520
10671
  status: "stable",
10521
- active: true
10672
+ active: true,
10673
+ wireSpec: "openai/responses"
10522
10674
  }
10523
10675
  };
10524
10676
 
10525
- // src/llm/providers/openrouter/catalog.json
10526
- var catalog_default4 = {
10677
+ // src/catalog/data/openrouter.json
10678
+ var openrouter_default = {
10527
10679
  "openrouter/auto": {
10528
10680
  providerModelName: "openrouter/auto",
10529
10681
  aliases: [
@@ -11057,7 +11209,8 @@ var catalog_default4 = {
11057
11209
  family: "claude-fable",
11058
11210
  version: "5",
11059
11211
  status: "stable",
11060
- active: true
11212
+ active: true,
11213
+ wireSpec: "openai/chat-completions"
11061
11214
  },
11062
11215
  "openrouter/claude-opus-4": {
11063
11216
  providerModelName: "anthropic/claude-opus-4",
@@ -11104,7 +11257,8 @@ var catalog_default4 = {
11104
11257
  family: "claude-opus",
11105
11258
  version: "4",
11106
11259
  status: "legacy",
11107
- active: true
11260
+ active: true,
11261
+ wireSpec: "openai/chat-completions"
11108
11262
  },
11109
11263
  "openrouter/claude-opus-4.1": {
11110
11264
  providerModelName: "anthropic/claude-opus-4.1",
@@ -11151,7 +11305,8 @@ var catalog_default4 = {
11151
11305
  family: "claude-opus",
11152
11306
  version: "4.1",
11153
11307
  status: "legacy",
11154
- active: true
11308
+ active: true,
11309
+ wireSpec: "openai/chat-completions"
11155
11310
  },
11156
11311
  "openrouter/claude-opus-4.5": {
11157
11312
  providerModelName: "anthropic/claude-opus-4.5",
@@ -11198,7 +11353,8 @@ var catalog_default4 = {
11198
11353
  family: "claude-opus",
11199
11354
  version: "4.5",
11200
11355
  status: "legacy",
11201
- active: true
11356
+ active: true,
11357
+ wireSpec: "openai/chat-completions"
11202
11358
  },
11203
11359
  "openrouter/claude-opus-4.6": {
11204
11360
  providerModelName: "anthropic/claude-opus-4.6",
@@ -11245,7 +11401,8 @@ var catalog_default4 = {
11245
11401
  family: "claude-opus",
11246
11402
  version: "4.6",
11247
11403
  status: "stable",
11248
- active: true
11404
+ active: true,
11405
+ wireSpec: "openai/chat-completions"
11249
11406
  },
11250
11407
  "openrouter/claude-opus-4.6-fast": {
11251
11408
  providerModelName: "anthropic/claude-opus-4.6-fast",
@@ -11296,7 +11453,8 @@ var catalog_default4 = {
11296
11453
  deprecation: {
11297
11454
  shutdownDate: "2026-06-29",
11298
11455
  source: "openrouter"
11299
- }
11456
+ },
11457
+ wireSpec: "openai/chat-completions"
11300
11458
  },
11301
11459
  "openrouter/claude-opus-4.7": {
11302
11460
  providerModelName: "anthropic/claude-opus-4.7",
@@ -11343,7 +11501,8 @@ var catalog_default4 = {
11343
11501
  family: "claude-opus",
11344
11502
  version: "4.7",
11345
11503
  status: "stable",
11346
- active: true
11504
+ active: true,
11505
+ wireSpec: "openai/chat-completions"
11347
11506
  },
11348
11507
  "openrouter/claude-opus-4.7-fast": {
11349
11508
  providerModelName: "anthropic/claude-opus-4.7-fast",
@@ -11390,7 +11549,8 @@ var catalog_default4 = {
11390
11549
  family: "claude-opus",
11391
11550
  version: "4.7",
11392
11551
  status: "stable",
11393
- active: true
11552
+ active: true,
11553
+ wireSpec: "openai/chat-completions"
11394
11554
  },
11395
11555
  "openrouter/claude-opus-4.8": {
11396
11556
  providerModelName: "anthropic/claude-opus-4.8",
@@ -11437,7 +11597,8 @@ var catalog_default4 = {
11437
11597
  family: "claude-opus",
11438
11598
  version: "4.8",
11439
11599
  status: "stable",
11440
- active: true
11600
+ active: true,
11601
+ wireSpec: "openai/chat-completions"
11441
11602
  },
11442
11603
  "openrouter/claude-opus-4.8-fast": {
11443
11604
  providerModelName: "anthropic/claude-opus-4.8-fast",
@@ -11484,7 +11645,8 @@ var catalog_default4 = {
11484
11645
  family: "claude-opus",
11485
11646
  version: "4.8",
11486
11647
  status: "stable",
11487
- active: true
11648
+ active: true,
11649
+ wireSpec: "openai/chat-completions"
11488
11650
  },
11489
11651
  "openrouter/claude-sonnet-4": {
11490
11652
  providerModelName: "anthropic/claude-sonnet-4",
@@ -11531,7 +11693,8 @@ var catalog_default4 = {
11531
11693
  family: "claude-sonnet",
11532
11694
  version: "4",
11533
11695
  status: "legacy",
11534
- active: true
11696
+ active: true,
11697
+ wireSpec: "openai/chat-completions"
11535
11698
  },
11536
11699
  "openrouter/claude-sonnet-4.5": {
11537
11700
  providerModelName: "anthropic/claude-sonnet-4.5",
@@ -11578,7 +11741,8 @@ var catalog_default4 = {
11578
11741
  family: "claude-sonnet",
11579
11742
  version: "4.5",
11580
11743
  status: "stable",
11581
- active: true
11744
+ active: true,
11745
+ wireSpec: "openai/chat-completions"
11582
11746
  },
11583
11747
  "openrouter/claude-sonnet-4.6": {
11584
11748
  providerModelName: "anthropic/claude-sonnet-4.6",
@@ -11625,7 +11789,8 @@ var catalog_default4 = {
11625
11789
  family: "claude-sonnet",
11626
11790
  version: "4.6",
11627
11791
  status: "stable",
11628
- active: true
11792
+ active: true,
11793
+ wireSpec: "openai/chat-completions"
11629
11794
  },
11630
11795
  "openrouter/claude-haiku-3": {
11631
11796
  providerModelName: "anthropic/claude-3-haiku",
@@ -11672,7 +11837,8 @@ var catalog_default4 = {
11672
11837
  family: "claude-haiku",
11673
11838
  version: "3",
11674
11839
  status: "legacy",
11675
- active: true
11840
+ active: true,
11841
+ wireSpec: "openai/chat-completions"
11676
11842
  },
11677
11843
  "openrouter/claude-haiku-3.5": {
11678
11844
  providerModelName: "anthropic/claude-3.5-haiku",
@@ -11719,7 +11885,8 @@ var catalog_default4 = {
11719
11885
  family: "claude-haiku",
11720
11886
  version: "3.5",
11721
11887
  status: "legacy",
11722
- active: true
11888
+ active: true,
11889
+ wireSpec: "openai/chat-completions"
11723
11890
  },
11724
11891
  "openrouter/claude-haiku-4.5": {
11725
11892
  providerModelName: "anthropic/claude-haiku-4.5",
@@ -11766,7 +11933,8 @@ var catalog_default4 = {
11766
11933
  family: "claude-haiku",
11767
11934
  version: "4.5",
11768
11935
  status: "stable",
11769
- active: true
11936
+ active: true,
11937
+ wireSpec: "openai/chat-completions"
11770
11938
  },
11771
11939
  "openrouter/gpt-3.5-turbo": {
11772
11940
  providerModelName: "openai/gpt-3.5-turbo",
@@ -11813,7 +11981,8 @@ var catalog_default4 = {
11813
11981
  family: "gpt",
11814
11982
  version: "3.5",
11815
11983
  status: "legacy",
11816
- active: true
11984
+ active: true,
11985
+ wireSpec: "openai/chat-completions"
11817
11986
  },
11818
11987
  "openrouter/gpt-4": {
11819
11988
  providerModelName: "openai/gpt-4",
@@ -11858,7 +12027,8 @@ var catalog_default4 = {
11858
12027
  family: "gpt",
11859
12028
  version: "4",
11860
12029
  status: "legacy",
11861
- active: true
12030
+ active: true,
12031
+ wireSpec: "openai/chat-completions"
11862
12032
  },
11863
12033
  "openrouter/gpt-4-turbo": {
11864
12034
  providerModelName: "openai/gpt-4-turbo",
@@ -11905,7 +12075,8 @@ var catalog_default4 = {
11905
12075
  family: "gpt",
11906
12076
  version: "4",
11907
12077
  status: "legacy",
11908
- active: true
12078
+ active: true,
12079
+ wireSpec: "openai/chat-completions"
11909
12080
  },
11910
12081
  "openrouter/gpt-4.1": {
11911
12082
  providerModelName: "openai/gpt-4.1",
@@ -11952,7 +12123,8 @@ var catalog_default4 = {
11952
12123
  family: "gpt",
11953
12124
  version: "4.1",
11954
12125
  status: "legacy",
11955
- active: true
12126
+ active: true,
12127
+ wireSpec: "openai/chat-completions"
11956
12128
  },
11957
12129
  "openrouter/gpt-5": {
11958
12130
  providerModelName: "openai/gpt-5",
@@ -11999,7 +12171,8 @@ var catalog_default4 = {
11999
12171
  family: "gpt",
12000
12172
  version: "5",
12001
12173
  status: "legacy",
12002
- active: true
12174
+ active: true,
12175
+ wireSpec: "openai/chat-completions"
12003
12176
  },
12004
12177
  "openrouter/gpt-5.1": {
12005
12178
  providerModelName: "openai/gpt-5.1",
@@ -12046,7 +12219,8 @@ var catalog_default4 = {
12046
12219
  family: "gpt",
12047
12220
  version: "5.1",
12048
12221
  status: "legacy",
12049
- active: true
12222
+ active: true,
12223
+ wireSpec: "openai/chat-completions"
12050
12224
  },
12051
12225
  "openrouter/gpt-5.2": {
12052
12226
  providerModelName: "openai/gpt-5.2",
@@ -12093,7 +12267,8 @@ var catalog_default4 = {
12093
12267
  family: "gpt",
12094
12268
  version: "5.2",
12095
12269
  status: "stable",
12096
- active: true
12270
+ active: true,
12271
+ wireSpec: "openai/chat-completions"
12097
12272
  },
12098
12273
  "openrouter/gpt-5.4": {
12099
12274
  providerModelName: "openai/gpt-5.4",
@@ -12140,7 +12315,8 @@ var catalog_default4 = {
12140
12315
  family: "gpt",
12141
12316
  version: "5.4",
12142
12317
  status: "stable",
12143
- active: true
12318
+ active: true,
12319
+ wireSpec: "openai/chat-completions"
12144
12320
  },
12145
12321
  "openrouter/gpt-5.5": {
12146
12322
  providerModelName: "openai/gpt-5.5",
@@ -12187,7 +12363,8 @@ var catalog_default4 = {
12187
12363
  family: "gpt",
12188
12364
  version: "5.5",
12189
12365
  status: "stable",
12190
- active: true
12366
+ active: true,
12367
+ wireSpec: "openai/chat-completions"
12191
12368
  },
12192
12369
  "openrouter/gpt-5-chat": {
12193
12370
  providerModelName: "openai/gpt-5-chat",
@@ -12234,7 +12411,8 @@ var catalog_default4 = {
12234
12411
  family: "gpt-chat",
12235
12412
  version: "5",
12236
12413
  status: "legacy",
12237
- active: true
12414
+ active: true,
12415
+ wireSpec: "openai/chat-completions"
12238
12416
  },
12239
12417
  "openrouter/gpt-5.1-chat": {
12240
12418
  providerModelName: "openai/gpt-5.1-chat",
@@ -12281,7 +12459,8 @@ var catalog_default4 = {
12281
12459
  family: "gpt-chat",
12282
12460
  version: "5.1",
12283
12461
  status: "legacy",
12284
- active: true
12462
+ active: true,
12463
+ wireSpec: "openai/chat-completions"
12285
12464
  },
12286
12465
  "openrouter/gpt-5.2-chat": {
12287
12466
  providerModelName: "openai/gpt-5.2-chat",
@@ -12332,7 +12511,8 @@ var catalog_default4 = {
12332
12511
  deprecation: {
12333
12512
  shutdownDate: "2026-08-10",
12334
12513
  source: "openrouter"
12335
- }
12514
+ },
12515
+ wireSpec: "openai/chat-completions"
12336
12516
  },
12337
12517
  "openrouter/gpt-5.3-chat": {
12338
12518
  providerModelName: "openai/gpt-5.3-chat",
@@ -12383,7 +12563,8 @@ var catalog_default4 = {
12383
12563
  deprecation: {
12384
12564
  shutdownDate: "2026-08-10",
12385
12565
  source: "openrouter"
12386
- }
12566
+ },
12567
+ wireSpec: "openai/chat-completions"
12387
12568
  },
12388
12569
  "openrouter/gpt-5-codex": {
12389
12570
  providerModelName: "openai/gpt-5-codex",
@@ -12712,7 +12893,8 @@ var catalog_default4 = {
12712
12893
  family: "gpt-mini",
12713
12894
  version: "4.1",
12714
12895
  status: "legacy",
12715
- active: true
12896
+ active: true,
12897
+ wireSpec: "openai/chat-completions"
12716
12898
  },
12717
12899
  "openrouter/gpt-5-mini": {
12718
12900
  providerModelName: "openai/gpt-5-mini",
@@ -12759,7 +12941,8 @@ var catalog_default4 = {
12759
12941
  family: "gpt-mini",
12760
12942
  version: "5",
12761
12943
  status: "legacy",
12762
- active: true
12944
+ active: true,
12945
+ wireSpec: "openai/chat-completions"
12763
12946
  },
12764
12947
  "openrouter/gpt-5.4-mini": {
12765
12948
  providerModelName: "openai/gpt-5.4-mini",
@@ -12806,7 +12989,8 @@ var catalog_default4 = {
12806
12989
  family: "gpt-mini",
12807
12990
  version: "5.4",
12808
12991
  status: "stable",
12809
- active: true
12992
+ active: true,
12993
+ wireSpec: "openai/chat-completions"
12810
12994
  },
12811
12995
  "openrouter/gpt-4.1-nano": {
12812
12996
  providerModelName: "openai/gpt-4.1-nano",
@@ -12853,7 +13037,8 @@ var catalog_default4 = {
12853
13037
  family: "gpt-nano",
12854
13038
  version: "4.1",
12855
13039
  status: "legacy",
12856
- active: true
13040
+ active: true,
13041
+ wireSpec: "openai/chat-completions"
12857
13042
  },
12858
13043
  "openrouter/gpt-5-nano": {
12859
13044
  providerModelName: "openai/gpt-5-nano",
@@ -12900,7 +13085,8 @@ var catalog_default4 = {
12900
13085
  family: "gpt-nano",
12901
13086
  version: "5",
12902
13087
  status: "legacy",
12903
- active: true
13088
+ active: true,
13089
+ wireSpec: "openai/chat-completions"
12904
13090
  },
12905
13091
  "openrouter/gpt-5.4-nano": {
12906
13092
  providerModelName: "openai/gpt-5.4-nano",
@@ -12947,7 +13133,8 @@ var catalog_default4 = {
12947
13133
  family: "gpt-nano",
12948
13134
  version: "5.4",
12949
13135
  status: "stable",
12950
- active: true
13136
+ active: true,
13137
+ wireSpec: "openai/chat-completions"
12951
13138
  },
12952
13139
  "openrouter/gpt-5-pro": {
12953
13140
  providerModelName: "openai/gpt-5-pro",
@@ -12993,7 +13180,8 @@ var catalog_default4 = {
12993
13180
  family: "gpt-pro",
12994
13181
  version: "5",
12995
13182
  status: "legacy",
12996
- active: true
13183
+ active: true,
13184
+ wireSpec: "openai/chat-completions"
12997
13185
  },
12998
13186
  "openrouter/gpt-5.2-pro": {
12999
13187
  providerModelName: "openai/gpt-5.2-pro",
@@ -13039,7 +13227,8 @@ var catalog_default4 = {
13039
13227
  family: "gpt-pro",
13040
13228
  version: "5.2",
13041
13229
  status: "legacy",
13042
- active: true
13230
+ active: true,
13231
+ wireSpec: "openai/chat-completions"
13043
13232
  },
13044
13233
  "openrouter/gpt-5.4-pro": {
13045
13234
  providerModelName: "openai/gpt-5.4-pro",
@@ -13085,7 +13274,8 @@ var catalog_default4 = {
13085
13274
  family: "gpt-pro",
13086
13275
  version: "5.4",
13087
13276
  status: "stable",
13088
- active: true
13277
+ active: true,
13278
+ wireSpec: "openai/chat-completions"
13089
13279
  },
13090
13280
  "openrouter/gpt-5.5-pro": {
13091
13281
  providerModelName: "openai/gpt-5.5-pro",
@@ -13131,7 +13321,8 @@ var catalog_default4 = {
13131
13321
  family: "gpt-pro",
13132
13322
  version: "5.5",
13133
13323
  status: "stable",
13134
- active: true
13324
+ active: true,
13325
+ wireSpec: "openai/chat-completions"
13135
13326
  },
13136
13327
  "openrouter/gpt-4o": {
13137
13328
  providerModelName: "openai/gpt-4o",
@@ -13180,7 +13371,8 @@ var catalog_default4 = {
13180
13371
  ],
13181
13372
  family: "gpt-4o",
13182
13373
  version: "4o",
13183
- active: true
13374
+ active: true,
13375
+ wireSpec: "openai/chat-completions"
13184
13376
  },
13185
13377
  "openrouter/gpt-4o-mini": {
13186
13378
  providerModelName: "openai/gpt-4o-mini",
@@ -13228,7 +13420,8 @@ var catalog_default4 = {
13228
13420
  ],
13229
13421
  family: "gpt-4o",
13230
13422
  version: "4o",
13231
- active: true
13423
+ active: true,
13424
+ wireSpec: "openai/chat-completions"
13232
13425
  },
13233
13426
  "openrouter/gpt-4o-search": {
13234
13427
  providerModelName: "openai/gpt-4o-search-preview",
@@ -13580,7 +13773,8 @@ var catalog_default4 = {
13580
13773
  family: "gpt-oss",
13581
13774
  version: "1",
13582
13775
  status: "stable",
13583
- active: true
13776
+ active: true,
13777
+ wireSpec: "openai/chat-completions"
13584
13778
  },
13585
13779
  "openrouter/gpt-oss-120b": {
13586
13780
  providerModelName: "openai/gpt-oss-120b",
@@ -13626,7 +13820,8 @@ var catalog_default4 = {
13626
13820
  family: "gpt-oss",
13627
13821
  version: "1",
13628
13822
  status: "stable",
13629
- active: true
13823
+ active: true,
13824
+ wireSpec: "openai/chat-completions"
13630
13825
  },
13631
13826
  "openrouter/gpt-oss-safeguard-20b": {
13632
13827
  providerModelName: "openai/gpt-oss-safeguard-20b",
@@ -13810,7 +14005,8 @@ var catalog_default4 = {
13810
14005
  ],
13811
14006
  family: "o-series",
13812
14007
  version: "1",
13813
- active: true
14008
+ active: true,
14009
+ wireSpec: "openai/chat-completions"
13814
14010
  },
13815
14011
  "openrouter/o1-pro": {
13816
14012
  providerModelName: "openai/o1-pro",
@@ -13855,7 +14051,8 @@ var catalog_default4 = {
13855
14051
  ],
13856
14052
  family: "o-series",
13857
14053
  version: "1",
13858
- active: true
14054
+ active: true,
14055
+ wireSpec: "openai/chat-completions"
13859
14056
  },
13860
14057
  "openrouter/o3": {
13861
14058
  providerModelName: "openai/o3",
@@ -13901,7 +14098,8 @@ var catalog_default4 = {
13901
14098
  ],
13902
14099
  family: "o-series",
13903
14100
  version: "3",
13904
- active: true
14101
+ active: true,
14102
+ wireSpec: "openai/chat-completions"
13905
14103
  },
13906
14104
  "openrouter/o3-mini": {
13907
14105
  providerModelName: "openai/o3-mini",
@@ -13947,7 +14145,8 @@ var catalog_default4 = {
13947
14145
  ],
13948
14146
  family: "o-series",
13949
14147
  version: "3",
13950
- active: true
14148
+ active: true,
14149
+ wireSpec: "openai/chat-completions"
13951
14150
  },
13952
14151
  "openrouter/o3-pro": {
13953
14152
  providerModelName: "openai/o3-pro",
@@ -13992,7 +14191,8 @@ var catalog_default4 = {
13992
14191
  ],
13993
14192
  family: "o-series",
13994
14193
  version: "3",
13995
- active: true
14194
+ active: true,
14195
+ wireSpec: "openai/chat-completions"
13996
14196
  },
13997
14197
  "openrouter/o3-deep-research": {
13998
14198
  providerModelName: "openai/o3-deep-research",
@@ -14038,7 +14238,8 @@ var catalog_default4 = {
14038
14238
  ],
14039
14239
  family: "o-series",
14040
14240
  version: "3",
14041
- active: true
14241
+ active: true,
14242
+ wireSpec: "openai/chat-completions"
14042
14243
  },
14043
14244
  "openrouter/o4-mini": {
14044
14245
  providerModelName: "openai/o4-mini",
@@ -14085,7 +14286,8 @@ var catalog_default4 = {
14085
14286
  ],
14086
14287
  family: "o-series",
14087
14288
  version: "4",
14088
- active: true
14289
+ active: true,
14290
+ wireSpec: "openai/chat-completions"
14089
14291
  },
14090
14292
  "openrouter/o4-mini-deep-research": {
14091
14293
  providerModelName: "openai/o4-mini-deep-research",
@@ -14131,7 +14333,8 @@ var catalog_default4 = {
14131
14333
  ],
14132
14334
  family: "o-series",
14133
14335
  version: "4",
14134
- active: true
14336
+ active: true,
14337
+ wireSpec: "openai/chat-completions"
14135
14338
  },
14136
14339
  "openrouter/gpt-3.5-turbo-instruct": {
14137
14340
  providerModelName: "openai/gpt-3.5-turbo-instruct",
@@ -14225,7 +14428,8 @@ var catalog_default4 = {
14225
14428
  family: "gemini-pro",
14226
14429
  version: "2.5",
14227
14430
  status: "stable",
14228
- active: true
14431
+ active: true,
14432
+ wireSpec: "openai/chat-completions"
14229
14433
  },
14230
14434
  "openrouter/gemini-3.1-pro": {
14231
14435
  providerModelName: "google/gemini-3.1-pro-preview",
@@ -14273,7 +14477,8 @@ var catalog_default4 = {
14273
14477
  family: "gemini-pro",
14274
14478
  version: "3.1",
14275
14479
  status: "preview",
14276
- active: true
14480
+ active: true,
14481
+ wireSpec: "openai/chat-completions"
14277
14482
  },
14278
14483
  "openrouter/gemini-3.1-pro-customtools": {
14279
14484
  providerModelName: "google/gemini-3.1-pro-preview-customtools",
@@ -14321,7 +14526,8 @@ var catalog_default4 = {
14321
14526
  family: "gemini-pro",
14322
14527
  version: "3.1",
14323
14528
  status: "preview",
14324
- active: true
14529
+ active: true,
14530
+ wireSpec: "openai/chat-completions"
14325
14531
  },
14326
14532
  "openrouter/gemini-2.5-flash": {
14327
14533
  providerModelName: "google/gemini-2.5-flash",
@@ -14369,7 +14575,8 @@ var catalog_default4 = {
14369
14575
  family: "gemini-flash",
14370
14576
  version: "2.5",
14371
14577
  status: "stable",
14372
- active: true
14578
+ active: true,
14579
+ wireSpec: "openai/chat-completions"
14373
14580
  },
14374
14581
  "openrouter/gemini-3-flash": {
14375
14582
  providerModelName: "google/gemini-3-flash-preview",
@@ -14417,7 +14624,8 @@ var catalog_default4 = {
14417
14624
  family: "gemini-flash",
14418
14625
  version: "3",
14419
14626
  status: "preview",
14420
- active: true
14627
+ active: true,
14628
+ wireSpec: "openai/chat-completions"
14421
14629
  },
14422
14630
  "openrouter/gemini-3.5-flash": {
14423
14631
  providerModelName: "google/gemini-3.5-flash",
@@ -14465,7 +14673,8 @@ var catalog_default4 = {
14465
14673
  family: "gemini-flash",
14466
14674
  version: "3.5",
14467
14675
  status: "stable",
14468
- active: true
14676
+ active: true,
14677
+ wireSpec: "openai/chat-completions"
14469
14678
  },
14470
14679
  "openrouter/gemini-2.5-flash-lite": {
14471
14680
  providerModelName: "google/gemini-2.5-flash-lite",
@@ -14514,7 +14723,8 @@ var catalog_default4 = {
14514
14723
  family: "gemini-flash-lite",
14515
14724
  version: "2.5",
14516
14725
  status: "stable",
14517
- active: true
14726
+ active: true,
14727
+ wireSpec: "openai/chat-completions"
14518
14728
  },
14519
14729
  "openrouter/gemini-3.1-flash-lite": {
14520
14730
  providerModelName: "google/gemini-3.1-flash-lite",
@@ -14563,7 +14773,8 @@ var catalog_default4 = {
14563
14773
  family: "gemini-flash-lite",
14564
14774
  version: "3.1",
14565
14775
  status: "stable",
14566
- active: true
14776
+ active: true,
14777
+ wireSpec: "openai/chat-completions"
14567
14778
  },
14568
14779
  "openrouter/gemini-2.5-flash-image": {
14569
14780
  providerModelName: "google/gemini-2.5-flash-image",
@@ -14825,7 +15036,8 @@ var catalog_default4 = {
14825
15036
  family: "gemma",
14826
15037
  version: "2",
14827
15038
  status: "legacy",
14828
- active: true
15039
+ active: true,
15040
+ wireSpec: "openai/chat-completions"
14829
15041
  },
14830
15042
  "openrouter/gemma-3-4b": {
14831
15043
  providerModelName: "google/gemma-3-4b-it",
@@ -14871,7 +15083,8 @@ var catalog_default4 = {
14871
15083
  family: "gemma",
14872
15084
  version: "3",
14873
15085
  status: "legacy",
14874
- active: true
15086
+ active: true,
15087
+ wireSpec: "openai/chat-completions"
14875
15088
  },
14876
15089
  "openrouter/gemma-3-12b": {
14877
15090
  providerModelName: "google/gemma-3-12b-it",
@@ -14917,7 +15130,8 @@ var catalog_default4 = {
14917
15130
  family: "gemma",
14918
15131
  version: "3",
14919
15132
  status: "legacy",
14920
- active: true
15133
+ active: true,
15134
+ wireSpec: "openai/chat-completions"
14921
15135
  },
14922
15136
  "openrouter/gemma-3-27b": {
14923
15137
  providerModelName: "google/gemma-3-27b-it",
@@ -14964,7 +15178,8 @@ var catalog_default4 = {
14964
15178
  family: "gemma",
14965
15179
  version: "3",
14966
15180
  status: "legacy",
14967
- active: true
15181
+ active: true,
15182
+ wireSpec: "openai/chat-completions"
14968
15183
  },
14969
15184
  "openrouter/gemma-3n-e4b": {
14970
15185
  providerModelName: "google/gemma-3n-e4b-it",
@@ -15008,7 +15223,8 @@ var catalog_default4 = {
15008
15223
  family: "gemma",
15009
15224
  version: "3",
15010
15225
  status: "legacy",
15011
- active: true
15226
+ active: true,
15227
+ wireSpec: "openai/chat-completions"
15012
15228
  },
15013
15229
  "openrouter/gemma-4-26b-a4b": {
15014
15230
  providerModelName: "google/gemma-4-26b-a4b-it",
@@ -15055,7 +15271,8 @@ var catalog_default4 = {
15055
15271
  family: "gemma",
15056
15272
  version: "4",
15057
15273
  status: "stable",
15058
- active: true
15274
+ active: true,
15275
+ wireSpec: "openai/chat-completions"
15059
15276
  },
15060
15277
  "openrouter/gemma-4-31b": {
15061
15278
  providerModelName: "google/gemma-4-31b-it",
@@ -15103,7 +15320,8 @@ var catalog_default4 = {
15103
15320
  family: "gemma",
15104
15321
  version: "4",
15105
15322
  status: "stable",
15106
- active: true
15323
+ active: true,
15324
+ wireSpec: "openai/chat-completions"
15107
15325
  },
15108
15326
  "openrouter/lyria-3-clip": {
15109
15327
  providerModelName: "google/lyria-3-clip-preview",
@@ -15241,7 +15459,8 @@ var catalog_default4 = {
15241
15459
  family: "grok",
15242
15460
  version: "4.20",
15243
15461
  status: "stable",
15244
- active: true
15462
+ active: true,
15463
+ wireSpec: "openai/chat-completions"
15245
15464
  },
15246
15465
  "openrouter/grok-4.20-multi-agent": {
15247
15466
  providerModelName: "x-ai/grok-4.20-multi-agent",
@@ -15287,7 +15506,8 @@ var catalog_default4 = {
15287
15506
  family: "grok",
15288
15507
  version: "4.20",
15289
15508
  status: "stable",
15290
- active: true
15509
+ active: true,
15510
+ wireSpec: "openai/chat-completions"
15291
15511
  },
15292
15512
  "openrouter/grok-4.3": {
15293
15513
  providerModelName: "x-ai/grok-4.3",
@@ -15333,7 +15553,8 @@ var catalog_default4 = {
15333
15553
  family: "grok",
15334
15554
  version: "4.3",
15335
15555
  status: "stable",
15336
- active: true
15556
+ active: true,
15557
+ wireSpec: "openai/chat-completions"
15337
15558
  },
15338
15559
  "openrouter/grok-build-0.1": {
15339
15560
  providerModelName: "x-ai/grok-build-0.1",
@@ -15424,7 +15645,8 @@ var catalog_default4 = {
15424
15645
  family: "deepseek-chat",
15425
15646
  version: "3",
15426
15647
  status: "stable",
15427
- active: true
15648
+ active: true,
15649
+ wireSpec: "openai/chat-completions"
15428
15650
  },
15429
15651
  "openrouter/deepseek-v3": {
15430
15652
  providerModelName: "deepseek/deepseek-chat-v3-0324",
@@ -15470,7 +15692,8 @@ var catalog_default4 = {
15470
15692
  family: "deepseek-chat",
15471
15693
  version: "3",
15472
15694
  status: "legacy",
15473
- active: true
15695
+ active: true,
15696
+ wireSpec: "openai/chat-completions"
15474
15697
  },
15475
15698
  "openrouter/deepseek-v3.1": {
15476
15699
  providerModelName: "deepseek/deepseek-chat-v3.1",
@@ -15517,7 +15740,8 @@ var catalog_default4 = {
15517
15740
  family: "deepseek-chat",
15518
15741
  version: "3.1",
15519
15742
  status: "stable",
15520
- active: true
15743
+ active: true,
15744
+ wireSpec: "openai/chat-completions"
15521
15745
  },
15522
15746
  "openrouter/deepseek-v3.2": {
15523
15747
  providerModelName: "deepseek/deepseek-v3.2",
@@ -15564,7 +15788,8 @@ var catalog_default4 = {
15564
15788
  family: "deepseek-chat",
15565
15789
  version: "3.2",
15566
15790
  status: "stable",
15567
- active: true
15791
+ active: true,
15792
+ wireSpec: "openai/chat-completions"
15568
15793
  },
15569
15794
  "openrouter/deepseek-v4-flash": {
15570
15795
  providerModelName: "deepseek/deepseek-v4-flash",
@@ -15609,7 +15834,8 @@ var catalog_default4 = {
15609
15834
  family: "deepseek-chat",
15610
15835
  version: "4",
15611
15836
  status: "stable",
15612
- active: true
15837
+ active: true,
15838
+ wireSpec: "openai/chat-completions"
15613
15839
  },
15614
15840
  "openrouter/deepseek-v4-pro": {
15615
15841
  providerModelName: "deepseek/deepseek-v4-pro",
@@ -15655,7 +15881,8 @@ var catalog_default4 = {
15655
15881
  family: "deepseek-chat",
15656
15882
  version: "4",
15657
15883
  status: "stable",
15658
- active: true
15884
+ active: true,
15885
+ wireSpec: "openai/chat-completions"
15659
15886
  },
15660
15887
  "openrouter/deepseek-r1": {
15661
15888
  providerModelName: "deepseek/deepseek-r1",
@@ -15701,7 +15928,8 @@ var catalog_default4 = {
15701
15928
  family: "deepseek-r1",
15702
15929
  version: "1",
15703
15930
  status: "stable",
15704
- active: true
15931
+ active: true,
15932
+ wireSpec: "openai/chat-completions"
15705
15933
  },
15706
15934
  "openrouter/deepseek-r1-distill-llama-70b": {
15707
15935
  providerModelName: "deepseek/deepseek-r1-distill-llama-70b",
@@ -15746,7 +15974,8 @@ var catalog_default4 = {
15746
15974
  family: "deepseek-r1",
15747
15975
  version: "1",
15748
15976
  status: "stable",
15749
- active: true
15977
+ active: true,
15978
+ wireSpec: "openai/chat-completions"
15750
15979
  },
15751
15980
  "openrouter/deepseek-r1-distill-qwen-32b": {
15752
15981
  providerModelName: "deepseek/deepseek-r1-distill-qwen-32b",
@@ -15791,7 +16020,8 @@ var catalog_default4 = {
15791
16020
  family: "deepseek-r1",
15792
16021
  version: "1",
15793
16022
  status: "stable",
15794
- active: true
16023
+ active: true,
16024
+ wireSpec: "openai/chat-completions"
15795
16025
  },
15796
16026
  "openrouter/qwen-2.5-7b": {
15797
16027
  providerModelName: "qwen/qwen-2.5-7b-instruct",
@@ -15836,7 +16066,8 @@ var catalog_default4 = {
15836
16066
  family: "qwen",
15837
16067
  version: "2.5",
15838
16068
  status: "legacy",
15839
- active: true
16069
+ active: true,
16070
+ wireSpec: "openai/chat-completions"
15840
16071
  },
15841
16072
  "openrouter/qwen-2.5-72b": {
15842
16073
  providerModelName: "qwen/qwen-2.5-72b-instruct",
@@ -15881,7 +16112,8 @@ var catalog_default4 = {
15881
16112
  family: "qwen",
15882
16113
  version: "2.5",
15883
16114
  status: "legacy",
15884
- active: true
16115
+ active: true,
16116
+ wireSpec: "openai/chat-completions"
15885
16117
  },
15886
16118
  "openrouter/qwen-2.5-vl-72b": {
15887
16119
  providerModelName: "qwen/qwen2.5-vl-72b-instruct",
@@ -15974,7 +16206,8 @@ var catalog_default4 = {
15974
16206
  family: "qwen",
15975
16207
  version: "3",
15976
16208
  status: "stable",
15977
- active: true
16209
+ active: true,
16210
+ wireSpec: "openai/chat-completions"
15978
16211
  },
15979
16212
  "openrouter/qwen-3-14b": {
15980
16213
  providerModelName: "qwen/qwen3-14b",
@@ -16019,7 +16252,8 @@ var catalog_default4 = {
16019
16252
  family: "qwen",
16020
16253
  version: "3",
16021
16254
  status: "stable",
16022
- active: true
16255
+ active: true,
16256
+ wireSpec: "openai/chat-completions"
16023
16257
  },
16024
16258
  "openrouter/qwen-3-30b-a3b": {
16025
16259
  providerModelName: "qwen/qwen3-30b-a3b",
@@ -16066,7 +16300,8 @@ var catalog_default4 = {
16066
16300
  family: "qwen",
16067
16301
  version: "3",
16068
16302
  status: "stable",
16069
- active: true
16303
+ active: true,
16304
+ wireSpec: "openai/chat-completions"
16070
16305
  },
16071
16306
  "openrouter/qwen-3-32b": {
16072
16307
  providerModelName: "qwen/qwen3-32b",
@@ -16111,7 +16346,8 @@ var catalog_default4 = {
16111
16346
  family: "qwen",
16112
16347
  version: "3",
16113
16348
  status: "stable",
16114
- active: true
16349
+ active: true,
16350
+ wireSpec: "openai/chat-completions"
16115
16351
  },
16116
16352
  "openrouter/qwen-3-235b-a22b": {
16117
16353
  providerModelName: "qwen/qwen3-235b-a22b",
@@ -16158,7 +16394,8 @@ var catalog_default4 = {
16158
16394
  family: "qwen",
16159
16395
  version: "3",
16160
16396
  status: "stable",
16161
- active: true
16397
+ active: true,
16398
+ wireSpec: "openai/chat-completions"
16162
16399
  },
16163
16400
  "openrouter/qwen-3-next-80b-a3b": {
16164
16401
  providerModelName: "qwen/qwen3-next-80b-a3b-instruct",
@@ -16206,7 +16443,8 @@ var catalog_default4 = {
16206
16443
  family: "qwen",
16207
16444
  version: "3",
16208
16445
  status: "stable",
16209
- active: true
16446
+ active: true,
16447
+ wireSpec: "openai/chat-completions"
16210
16448
  },
16211
16449
  "openrouter/qwen-3.5-9b": {
16212
16450
  providerModelName: "qwen/qwen3.5-9b",
@@ -16252,7 +16490,8 @@ var catalog_default4 = {
16252
16490
  family: "qwen",
16253
16491
  version: "3.5",
16254
16492
  status: "stable",
16255
- active: true
16493
+ active: true,
16494
+ wireSpec: "openai/chat-completions"
16256
16495
  },
16257
16496
  "openrouter/qwen-3.5-27b": {
16258
16497
  providerModelName: "qwen/qwen3.5-27b",
@@ -16298,7 +16537,8 @@ var catalog_default4 = {
16298
16537
  family: "qwen",
16299
16538
  version: "3.5",
16300
16539
  status: "stable",
16301
- active: true
16540
+ active: true,
16541
+ wireSpec: "openai/chat-completions"
16302
16542
  },
16303
16543
  "openrouter/qwen-3.5-35b-a3b": {
16304
16544
  providerModelName: "qwen/qwen3.5-35b-a3b",
@@ -16345,7 +16585,8 @@ var catalog_default4 = {
16345
16585
  family: "qwen",
16346
16586
  version: "3.5",
16347
16587
  status: "stable",
16348
- active: true
16588
+ active: true,
16589
+ wireSpec: "openai/chat-completions"
16349
16590
  },
16350
16591
  "openrouter/qwen-3.5-122b-a10b": {
16351
16592
  providerModelName: "qwen/qwen3.5-122b-a10b",
@@ -16391,7 +16632,8 @@ var catalog_default4 = {
16391
16632
  family: "qwen",
16392
16633
  version: "3.5",
16393
16634
  status: "stable",
16394
- active: true
16635
+ active: true,
16636
+ wireSpec: "openai/chat-completions"
16395
16637
  },
16396
16638
  "openrouter/qwen-3.5-397b-a17b": {
16397
16639
  providerModelName: "qwen/qwen3.5-397b-a17b",
@@ -16438,7 +16680,8 @@ var catalog_default4 = {
16438
16680
  family: "qwen",
16439
16681
  version: "3.5",
16440
16682
  status: "stable",
16441
- active: true
16683
+ active: true,
16684
+ wireSpec: "openai/chat-completions"
16442
16685
  },
16443
16686
  "openrouter/qwen-3.6-27b": {
16444
16687
  providerModelName: "qwen/qwen3.6-27b",
@@ -16485,7 +16728,8 @@ var catalog_default4 = {
16485
16728
  family: "qwen",
16486
16729
  version: "3.6",
16487
16730
  status: "stable",
16488
- active: true
16731
+ active: true,
16732
+ wireSpec: "openai/chat-completions"
16489
16733
  },
16490
16734
  "openrouter/qwen-3.6-35b-a3b": {
16491
16735
  providerModelName: "qwen/qwen3.6-35b-a3b",
@@ -16532,7 +16776,8 @@ var catalog_default4 = {
16532
16776
  family: "qwen",
16533
16777
  version: "3.6",
16534
16778
  status: "stable",
16535
- active: true
16779
+ active: true,
16780
+ wireSpec: "openai/chat-completions"
16536
16781
  },
16537
16782
  "openrouter/qwen-plus": {
16538
16783
  providerModelName: "qwen/qwen-plus",
@@ -16580,7 +16825,8 @@ var catalog_default4 = {
16580
16825
  family: "qwen-plus",
16581
16826
  version: "1",
16582
16827
  status: "legacy",
16583
- active: true
16828
+ active: true,
16829
+ wireSpec: "openai/chat-completions"
16584
16830
  },
16585
16831
  "openrouter/qwen-3.5-plus": {
16586
16832
  providerModelName: "qwen/qwen3.5-plus-20260420",
@@ -16627,7 +16873,8 @@ var catalog_default4 = {
16627
16873
  family: "qwen-plus",
16628
16874
  version: "3.5",
16629
16875
  status: "stable",
16630
- active: true
16876
+ active: true,
16877
+ wireSpec: "openai/chat-completions"
16631
16878
  },
16632
16879
  "openrouter/qwen-3.6-plus": {
16633
16880
  providerModelName: "qwen/qwen3.6-plus",
@@ -16673,7 +16920,8 @@ var catalog_default4 = {
16673
16920
  family: "qwen-plus",
16674
16921
  version: "3.6",
16675
16922
  status: "stable",
16676
- active: true
16923
+ active: true,
16924
+ wireSpec: "openai/chat-completions"
16677
16925
  },
16678
16926
  "openrouter/qwen-3.7-plus": {
16679
16927
  providerModelName: "qwen/qwen3.7-plus",
@@ -16720,7 +16968,8 @@ var catalog_default4 = {
16720
16968
  family: "qwen-plus",
16721
16969
  version: "3.7",
16722
16970
  status: "stable",
16723
- active: true
16971
+ active: true,
16972
+ wireSpec: "openai/chat-completions"
16724
16973
  },
16725
16974
  "openrouter/qwen-3-max": {
16726
16975
  providerModelName: "qwen/qwen3-max",
@@ -16767,7 +17016,8 @@ var catalog_default4 = {
16767
17016
  family: "qwen-max",
16768
17017
  version: "3",
16769
17018
  status: "stable",
16770
- active: true
17019
+ active: true,
17020
+ wireSpec: "openai/chat-completions"
16771
17021
  },
16772
17022
  "openrouter/qwen-3.6-max": {
16773
17023
  providerModelName: "qwen/qwen3.6-max-preview",
@@ -16812,7 +17062,8 @@ var catalog_default4 = {
16812
17062
  family: "qwen-max",
16813
17063
  version: "3.6",
16814
17064
  status: "preview",
16815
- active: true
17065
+ active: true,
17066
+ wireSpec: "openai/chat-completions"
16816
17067
  },
16817
17068
  "openrouter/qwen-3.7-max": {
16818
17069
  providerModelName: "qwen/qwen3.7-max",
@@ -16858,7 +17109,8 @@ var catalog_default4 = {
16858
17109
  family: "qwen-max",
16859
17110
  version: "3.7",
16860
17111
  status: "stable",
16861
- active: true
17112
+ active: true,
17113
+ wireSpec: "openai/chat-completions"
16862
17114
  },
16863
17115
  "openrouter/qwen-3.5-flash": {
16864
17116
  providerModelName: "qwen/qwen3.5-flash-02-23",
@@ -16904,7 +17156,8 @@ var catalog_default4 = {
16904
17156
  family: "qwen-flash",
16905
17157
  version: "3.5",
16906
17158
  status: "stable",
16907
- active: true
17159
+ active: true,
17160
+ wireSpec: "openai/chat-completions"
16908
17161
  },
16909
17162
  "openrouter/qwen-3.6-flash": {
16910
17163
  providerModelName: "qwen/qwen3.6-flash",
@@ -16950,7 +17203,8 @@ var catalog_default4 = {
16950
17203
  family: "qwen-flash",
16951
17204
  version: "3.6",
16952
17205
  status: "stable",
16953
- active: true
17206
+ active: true,
17207
+ wireSpec: "openai/chat-completions"
16954
17208
  },
16955
17209
  "openrouter/qwen-2.5-coder-32b": {
16956
17210
  providerModelName: "qwen/qwen-2.5-coder-32b-instruct",
@@ -17322,7 +17576,8 @@ var catalog_default4 = {
17322
17576
  family: "llama",
17323
17577
  version: "3",
17324
17578
  status: "legacy",
17325
- active: true
17579
+ active: true,
17580
+ wireSpec: "openai/chat-completions"
17326
17581
  },
17327
17582
  "openrouter/llama-3-70b": {
17328
17583
  providerModelName: "meta-llama/llama-3-70b-instruct",
@@ -17371,7 +17626,8 @@ var catalog_default4 = {
17371
17626
  deprecation: {
17372
17627
  shutdownDate: "2026-06-19",
17373
17628
  source: "openrouter"
17374
- }
17629
+ },
17630
+ wireSpec: "openai/chat-completions"
17375
17631
  },
17376
17632
  "openrouter/llama-3.1-8b": {
17377
17633
  providerModelName: "meta-llama/llama-3.1-8b-instruct",
@@ -17417,7 +17673,8 @@ var catalog_default4 = {
17417
17673
  family: "llama",
17418
17674
  version: "3.1",
17419
17675
  status: "legacy",
17420
- active: true
17676
+ active: true,
17677
+ wireSpec: "openai/chat-completions"
17421
17678
  },
17422
17679
  "openrouter/llama-3.1-70b": {
17423
17680
  providerModelName: "meta-llama/llama-3.1-70b-instruct",
@@ -17462,7 +17719,8 @@ var catalog_default4 = {
17462
17719
  family: "llama",
17463
17720
  version: "3.1",
17464
17721
  status: "legacy",
17465
- active: true
17722
+ active: true,
17723
+ wireSpec: "openai/chat-completions"
17466
17724
  },
17467
17725
  "openrouter/llama-3.2-1b": {
17468
17726
  providerModelName: "meta-llama/llama-3.2-1b-instruct",
@@ -17507,7 +17765,8 @@ var catalog_default4 = {
17507
17765
  family: "llama",
17508
17766
  version: "3.2",
17509
17767
  status: "legacy",
17510
- active: true
17768
+ active: true,
17769
+ wireSpec: "openai/chat-completions"
17511
17770
  },
17512
17771
  "openrouter/llama-3.2-3b": {
17513
17772
  providerModelName: "meta-llama/llama-3.2-3b-instruct",
@@ -17553,7 +17812,8 @@ var catalog_default4 = {
17553
17812
  family: "llama",
17554
17813
  version: "3.2",
17555
17814
  status: "legacy",
17556
- active: true
17815
+ active: true,
17816
+ wireSpec: "openai/chat-completions"
17557
17817
  },
17558
17818
  "openrouter/llama-3.2-11b-vision": {
17559
17819
  providerModelName: "meta-llama/llama-3.2-11b-vision-instruct",
@@ -17649,7 +17909,8 @@ var catalog_default4 = {
17649
17909
  family: "llama",
17650
17910
  version: "3.3",
17651
17911
  status: "stable",
17652
- active: true
17912
+ active: true,
17913
+ wireSpec: "openai/chat-completions"
17653
17914
  },
17654
17915
  "openrouter/llama-4-scout": {
17655
17916
  providerModelName: "meta-llama/llama-4-scout",
@@ -17695,7 +17956,8 @@ var catalog_default4 = {
17695
17956
  family: "llama",
17696
17957
  version: "4",
17697
17958
  status: "stable",
17698
- active: true
17959
+ active: true,
17960
+ wireSpec: "openai/chat-completions"
17699
17961
  },
17700
17962
  "openrouter/llama-4-maverick": {
17701
17963
  providerModelName: "meta-llama/llama-4-maverick",
@@ -17741,7 +18003,8 @@ var catalog_default4 = {
17741
18003
  family: "llama",
17742
18004
  version: "4",
17743
18005
  status: "stable",
17744
- active: true
18006
+ active: true,
18007
+ wireSpec: "openai/chat-completions"
17745
18008
  },
17746
18009
  "openrouter/llama-guard-3-8b": {
17747
18010
  providerModelName: "meta-llama/llama-guard-3-8b",
@@ -17876,7 +18139,8 @@ var catalog_default4 = {
17876
18139
  family: "mistral",
17877
18140
  version: "2",
17878
18141
  status: "stable",
17879
- active: true
18142
+ active: true,
18143
+ wireSpec: "openai/chat-completions"
17880
18144
  },
17881
18145
  "openrouter/mistral-medium-3": {
17882
18146
  providerModelName: "mistralai/mistral-medium-3",
@@ -17924,7 +18188,8 @@ var catalog_default4 = {
17924
18188
  family: "mistral",
17925
18189
  version: "3",
17926
18190
  status: "stable",
17927
- active: true
18191
+ active: true,
18192
+ wireSpec: "openai/chat-completions"
17928
18193
  },
17929
18194
  "openrouter/mistral-small": {
17930
18195
  providerModelName: "mistralai/mistral-small-24b-instruct-2501",
@@ -17972,7 +18237,8 @@ var catalog_default4 = {
17972
18237
  family: "mistral",
17973
18238
  version: "3",
17974
18239
  status: "stable",
17975
- active: true
18240
+ active: true,
18241
+ wireSpec: "openai/chat-completions"
17976
18242
  },
17977
18243
  "openrouter/ministral-3b": {
17978
18244
  providerModelName: "mistralai/ministral-3b-2512",
@@ -18019,7 +18285,8 @@ var catalog_default4 = {
18019
18285
  family: "mistral",
18020
18286
  version: "1",
18021
18287
  status: "stable",
18022
- active: true
18288
+ active: true,
18289
+ wireSpec: "openai/chat-completions"
18023
18290
  },
18024
18291
  "openrouter/ministral-8b": {
18025
18292
  providerModelName: "mistralai/ministral-8b-2512",
@@ -18066,7 +18333,8 @@ var catalog_default4 = {
18066
18333
  family: "mistral",
18067
18334
  version: "1",
18068
18335
  status: "stable",
18069
- active: true
18336
+ active: true,
18337
+ wireSpec: "openai/chat-completions"
18070
18338
  },
18071
18339
  "openrouter/ministral-14b": {
18072
18340
  providerModelName: "mistralai/ministral-14b-2512",
@@ -18113,7 +18381,8 @@ var catalog_default4 = {
18113
18381
  family: "mistral",
18114
18382
  version: "1",
18115
18383
  status: "stable",
18116
- active: true
18384
+ active: true,
18385
+ wireSpec: "openai/chat-completions"
18117
18386
  },
18118
18387
  "openrouter/mistral-nemo": {
18119
18388
  providerModelName: "mistralai/mistral-nemo",
@@ -18157,7 +18426,8 @@ var catalog_default4 = {
18157
18426
  family: "mistral",
18158
18427
  version: "1",
18159
18428
  status: "legacy",
18160
- active: true
18429
+ active: true,
18430
+ wireSpec: "openai/chat-completions"
18161
18431
  },
18162
18432
  "openrouter/mistral-saba": {
18163
18433
  providerModelName: "mistralai/mistral-saba",
@@ -18202,7 +18472,8 @@ var catalog_default4 = {
18202
18472
  family: "mistral",
18203
18473
  version: "1",
18204
18474
  status: "stable",
18205
- active: true
18475
+ active: true,
18476
+ wireSpec: "openai/chat-completions"
18206
18477
  },
18207
18478
  "openrouter/mixtral-8x22b": {
18208
18479
  providerModelName: "mistralai/mixtral-8x22b-instruct",
@@ -18248,7 +18519,8 @@ var catalog_default4 = {
18248
18519
  family: "mistral",
18249
18520
  version: "1",
18250
18521
  status: "legacy",
18251
- active: true
18522
+ active: true,
18523
+ wireSpec: "openai/chat-completions"
18252
18524
  },
18253
18525
  "openrouter/voxtral-small-24b": {
18254
18526
  providerModelName: "mistralai/voxtral-small-24b-2507",
@@ -18432,7 +18704,8 @@ var catalog_default4 = {
18432
18704
  family: "kimi",
18433
18705
  version: "2",
18434
18706
  status: "stable",
18435
- active: true
18707
+ active: true,
18708
+ wireSpec: "openai/chat-completions"
18436
18709
  },
18437
18710
  "openrouter/kimi-k2.5": {
18438
18711
  providerModelName: "moonshotai/kimi-k2.5",
@@ -18479,7 +18752,8 @@ var catalog_default4 = {
18479
18752
  family: "kimi",
18480
18753
  version: "2.5",
18481
18754
  status: "stable",
18482
- active: true
18755
+ active: true,
18756
+ wireSpec: "openai/chat-completions"
18483
18757
  },
18484
18758
  "openrouter/kimi-k2.6": {
18485
18759
  providerModelName: "moonshotai/kimi-k2.6",
@@ -18526,7 +18800,8 @@ var catalog_default4 = {
18526
18800
  family: "kimi",
18527
18801
  version: "2.6",
18528
18802
  status: "stable",
18529
- active: true
18803
+ active: true,
18804
+ wireSpec: "openai/chat-completions"
18530
18805
  },
18531
18806
  "openrouter/glm-4.5": {
18532
18807
  providerModelName: "z-ai/glm-4.5",
@@ -18578,7 +18853,8 @@ var catalog_default4 = {
18578
18853
  deprecation: {
18579
18854
  shutdownDate: "2026-12-31",
18580
18855
  source: "openrouter"
18581
- }
18856
+ },
18857
+ wireSpec: "openai/chat-completions"
18582
18858
  },
18583
18859
  "openrouter/glm-4.6": {
18584
18860
  providerModelName: "z-ai/glm-4.6",
@@ -18625,7 +18901,8 @@ var catalog_default4 = {
18625
18901
  family: "glm",
18626
18902
  version: "4.6",
18627
18903
  status: "stable",
18628
- active: true
18904
+ active: true,
18905
+ wireSpec: "openai/chat-completions"
18629
18906
  },
18630
18907
  "openrouter/glm-4.7": {
18631
18908
  providerModelName: "z-ai/glm-4.7",
@@ -18672,7 +18949,8 @@ var catalog_default4 = {
18672
18949
  family: "glm",
18673
18950
  version: "4.7",
18674
18951
  status: "stable",
18675
- active: true
18952
+ active: true,
18953
+ wireSpec: "openai/chat-completions"
18676
18954
  },
18677
18955
  "openrouter/glm-5": {
18678
18956
  providerModelName: "z-ai/glm-5",
@@ -18719,7 +18997,8 @@ var catalog_default4 = {
18719
18997
  family: "glm",
18720
18998
  version: "5",
18721
18999
  status: "stable",
18722
- active: true
19000
+ active: true,
19001
+ wireSpec: "openai/chat-completions"
18723
19002
  },
18724
19003
  "openrouter/glm-5.1": {
18725
19004
  providerModelName: "z-ai/glm-5.1",
@@ -18765,7 +19044,8 @@ var catalog_default4 = {
18765
19044
  version: "5.1",
18766
19045
  status: "stable",
18767
19046
  active: true,
18768
- maxOutput: 128e3
19047
+ maxOutput: 128e3,
19048
+ wireSpec: "openai/chat-completions"
18769
19049
  },
18770
19050
  "openrouter/minimax-01": {
18771
19051
  providerModelName: "minimax/minimax-01",
@@ -18811,7 +19091,8 @@ var catalog_default4 = {
18811
19091
  family: "minimax",
18812
19092
  version: "1",
18813
19093
  status: "legacy",
18814
- active: true
19094
+ active: true,
19095
+ wireSpec: "openai/chat-completions"
18815
19096
  },
18816
19097
  "openrouter/minimax-m1": {
18817
19098
  providerModelName: "minimax/minimax-m1",
@@ -18856,7 +19137,8 @@ var catalog_default4 = {
18856
19137
  family: "minimax",
18857
19138
  version: "1",
18858
19139
  status: "legacy",
18859
- active: true
19140
+ active: true,
19141
+ wireSpec: "openai/chat-completions"
18860
19142
  },
18861
19143
  "openrouter/minimax-m2": {
18862
19144
  providerModelName: "minimax/minimax-m2",
@@ -18904,7 +19186,8 @@ var catalog_default4 = {
18904
19186
  family: "minimax",
18905
19187
  version: "2",
18906
19188
  status: "stable",
18907
- active: true
19189
+ active: true,
19190
+ wireSpec: "openai/chat-completions"
18908
19191
  },
18909
19192
  "openrouter/minimax-m2.5": {
18910
19193
  providerModelName: "minimax/minimax-m2.5",
@@ -18950,7 +19233,8 @@ var catalog_default4 = {
18950
19233
  family: "minimax",
18951
19234
  version: "2.5",
18952
19235
  status: "stable",
18953
- active: true
19236
+ active: true,
19237
+ wireSpec: "openai/chat-completions"
18954
19238
  },
18955
19239
  "openrouter/minimax-m2.7": {
18956
19240
  providerModelName: "minimax/minimax-m2.7",
@@ -18996,7 +19280,8 @@ var catalog_default4 = {
18996
19280
  family: "minimax",
18997
19281
  version: "2.7",
18998
19282
  status: "stable",
18999
- active: true
19283
+ active: true,
19284
+ wireSpec: "openai/chat-completions"
19000
19285
  },
19001
19286
  "openrouter/minimax-m3": {
19002
19287
  providerModelName: "minimax/minimax-m3",
@@ -19043,7 +19328,8 @@ var catalog_default4 = {
19043
19328
  family: "minimax",
19044
19329
  version: "3",
19045
19330
  status: "stable",
19046
- active: true
19331
+ active: true,
19332
+ wireSpec: "openai/chat-completions"
19047
19333
  },
19048
19334
  "openrouter/nemotron-nano-9b-v2": {
19049
19335
  providerModelName: "nvidia/nemotron-nano-9b-v2:free",
@@ -19087,7 +19373,8 @@ var catalog_default4 = {
19087
19373
  family: "nemotron",
19088
19374
  version: "2",
19089
19375
  status: "stable",
19090
- active: true
19376
+ active: true,
19377
+ wireSpec: "openai/chat-completions"
19091
19378
  },
19092
19379
  "openrouter/nemotron-nano-12b-v2-vl": {
19093
19380
  providerModelName: "nvidia/nemotron-nano-12b-v2-vl:free",
@@ -19182,7 +19469,8 @@ var catalog_default4 = {
19182
19469
  deprecation: {
19183
19470
  shutdownDate: "2026-07-17",
19184
19471
  source: "openrouter"
19185
- }
19472
+ },
19473
+ wireSpec: "openai/chat-completions"
19186
19474
  },
19187
19475
  "openrouter/nemotron-3-nano-30b-a3b": {
19188
19476
  providerModelName: "nvidia/nemotron-3-nano-30b-a3b",
@@ -19229,7 +19517,8 @@ var catalog_default4 = {
19229
19517
  family: "nemotron",
19230
19518
  version: "3",
19231
19519
  status: "stable",
19232
- active: true
19520
+ active: true,
19521
+ wireSpec: "openai/chat-completions"
19233
19522
  },
19234
19523
  "openrouter/nemotron-3-super-120b-a12b": {
19235
19524
  providerModelName: "nvidia/nemotron-3-super-120b-a12b",
@@ -19274,7 +19563,8 @@ var catalog_default4 = {
19274
19563
  family: "nemotron",
19275
19564
  version: "3",
19276
19565
  status: "stable",
19277
- active: true
19566
+ active: true,
19567
+ wireSpec: "openai/chat-completions"
19278
19568
  },
19279
19569
  "openrouter/nemotron-3-ultra-550b-a55b": {
19280
19570
  providerModelName: "nvidia/nemotron-3-ultra-550b-a55b",
@@ -19321,7 +19611,8 @@ var catalog_default4 = {
19321
19611
  family: "nemotron",
19322
19612
  version: "3",
19323
19613
  status: "stable",
19324
- active: true
19614
+ active: true,
19615
+ wireSpec: "openai/chat-completions"
19325
19616
  },
19326
19617
  "openrouter/nemotron-3.5-content-safety": {
19327
19618
  providerModelName: "nvidia/nemotron-3.5-content-safety:free",
@@ -19412,7 +19703,8 @@ var catalog_default4 = {
19412
19703
  family: "nova",
19413
19704
  version: "1",
19414
19705
  status: "stable",
19415
- active: true
19706
+ active: true,
19707
+ wireSpec: "openai/chat-completions"
19416
19708
  },
19417
19709
  "openrouter/nova-lite": {
19418
19710
  providerModelName: "amazon/nova-lite-v1",
@@ -19458,7 +19750,8 @@ var catalog_default4 = {
19458
19750
  family: "nova",
19459
19751
  version: "1",
19460
19752
  status: "stable",
19461
- active: true
19753
+ active: true,
19754
+ wireSpec: "openai/chat-completions"
19462
19755
  },
19463
19756
  "openrouter/nova-2-lite": {
19464
19757
  providerModelName: "amazon/nova-2-lite-v1",
@@ -19504,7 +19797,8 @@ var catalog_default4 = {
19504
19797
  family: "nova",
19505
19798
  version: "2",
19506
19799
  status: "stable",
19507
- active: true
19800
+ active: true,
19801
+ wireSpec: "openai/chat-completions"
19508
19802
  },
19509
19803
  "openrouter/nova-pro": {
19510
19804
  providerModelName: "amazon/nova-pro-v1",
@@ -19550,7 +19844,8 @@ var catalog_default4 = {
19550
19844
  family: "nova",
19551
19845
  version: "1",
19552
19846
  status: "stable",
19553
- active: true
19847
+ active: true,
19848
+ wireSpec: "openai/chat-completions"
19554
19849
  },
19555
19850
  "openrouter/nova-premier": {
19556
19851
  providerModelName: "amazon/nova-premier-v1",
@@ -19597,7 +19892,8 @@ var catalog_default4 = {
19597
19892
  family: "nova",
19598
19893
  version: "1",
19599
19894
  status: "stable",
19600
- active: true
19895
+ active: true,
19896
+ wireSpec: "openai/chat-completions"
19601
19897
  },
19602
19898
  "openrouter/command-r7b": {
19603
19899
  providerModelName: "cohere/command-r7b-12-2024",
@@ -19642,7 +19938,8 @@ var catalog_default4 = {
19642
19938
  family: "command",
19643
19939
  version: "1",
19644
19940
  status: "stable",
19645
- active: true
19941
+ active: true,
19942
+ wireSpec: "openai/chat-completions"
19646
19943
  },
19647
19944
  "openrouter/command-r": {
19648
19945
  providerModelName: "cohere/command-r-08-2024",
@@ -19687,7 +19984,8 @@ var catalog_default4 = {
19687
19984
  family: "command",
19688
19985
  version: "1",
19689
19986
  status: "legacy",
19690
- active: true
19987
+ active: true,
19988
+ wireSpec: "openai/chat-completions"
19691
19989
  },
19692
19990
  "openrouter/command-r-plus": {
19693
19991
  providerModelName: "cohere/command-r-plus-08-2024",
@@ -19732,7 +20030,8 @@ var catalog_default4 = {
19732
20030
  family: "command",
19733
20031
  version: "1",
19734
20032
  status: "legacy",
19735
- active: true
20033
+ active: true,
20034
+ wireSpec: "openai/chat-completions"
19736
20035
  },
19737
20036
  "openrouter/command-a": {
19738
20037
  providerModelName: "cohere/command-a",
@@ -19777,7 +20076,8 @@ var catalog_default4 = {
19777
20076
  family: "command",
19778
20077
  version: "1",
19779
20078
  status: "stable",
19780
- active: true
20079
+ active: true,
20080
+ wireSpec: "openai/chat-completions"
19781
20081
  },
19782
20082
  "openrouter/phi-4": {
19783
20083
  providerModelName: "microsoft/phi-4",
@@ -19822,7 +20122,8 @@ var catalog_default4 = {
19822
20122
  family: "phi",
19823
20123
  version: "4",
19824
20124
  status: "stable",
19825
- active: true
20125
+ active: true,
20126
+ wireSpec: "openai/chat-completions"
19826
20127
  },
19827
20128
  "openrouter/phi-4-mini": {
19828
20129
  providerModelName: "microsoft/phi-4-mini-instruct",
@@ -19868,7 +20169,8 @@ var catalog_default4 = {
19868
20169
  family: "phi",
19869
20170
  version: "4",
19870
20171
  status: "stable",
19871
- active: true
20172
+ active: true,
20173
+ wireSpec: "openai/chat-completions"
19872
20174
  },
19873
20175
  "openrouter/wizardlm-2-8x22b": {
19874
20176
  providerModelName: "microsoft/wizardlm-2-8x22b",
@@ -19912,7 +20214,8 @@ var catalog_default4 = {
19912
20214
  ],
19913
20215
  family: "wizardlm",
19914
20216
  version: "2",
19915
- active: true
20217
+ active: true,
20218
+ wireSpec: "openai/chat-completions"
19916
20219
  },
19917
20220
  "openrouter/sonar": {
19918
20221
  providerModelName: "perplexity/sonar",
@@ -20142,7 +20445,8 @@ var catalog_default4 = {
20142
20445
  family: "hermes",
20143
20446
  version: "3",
20144
20447
  status: "legacy",
20145
- active: true
20448
+ active: true,
20449
+ wireSpec: "openai/chat-completions"
20146
20450
  },
20147
20451
  "openrouter/hermes-3-405b": {
20148
20452
  providerModelName: "nousresearch/hermes-3-llama-3.1-405b",
@@ -20188,7 +20492,8 @@ var catalog_default4 = {
20188
20492
  family: "hermes",
20189
20493
  version: "3",
20190
20494
  status: "legacy",
20191
- active: true
20495
+ active: true,
20496
+ wireSpec: "openai/chat-completions"
20192
20497
  },
20193
20498
  "openrouter/hermes-4-70b": {
20194
20499
  providerModelName: "nousresearch/hermes-4-70b",
@@ -20232,7 +20537,8 @@ var catalog_default4 = {
20232
20537
  family: "hermes",
20233
20538
  version: "4",
20234
20539
  status: "stable",
20235
- active: true
20540
+ active: true,
20541
+ wireSpec: "openai/chat-completions"
20236
20542
  },
20237
20543
  "openrouter/hermes-4-405b": {
20238
20544
  providerModelName: "nousresearch/hermes-4-405b",
@@ -20276,7 +20582,8 @@ var catalog_default4 = {
20276
20582
  family: "hermes",
20277
20583
  version: "4",
20278
20584
  status: "stable",
20279
- active: true
20585
+ active: true,
20586
+ wireSpec: "openai/chat-completions"
20280
20587
  },
20281
20588
  "openrouter/seed-1.6": {
20282
20589
  providerModelName: "bytedance-seed/seed-1.6",
@@ -20323,7 +20630,8 @@ var catalog_default4 = {
20323
20630
  family: "seed",
20324
20631
  version: "1.6",
20325
20632
  status: "stable",
20326
- active: true
20633
+ active: true,
20634
+ wireSpec: "openai/chat-completions"
20327
20635
  },
20328
20636
  "openrouter/seed-2.0-lite": {
20329
20637
  providerModelName: "bytedance-seed/seed-2.0-lite",
@@ -20369,7 +20677,8 @@ var catalog_default4 = {
20369
20677
  family: "seed",
20370
20678
  version: "2.0",
20371
20679
  status: "stable",
20372
- active: true
20680
+ active: true,
20681
+ wireSpec: "openai/chat-completions"
20373
20682
  },
20374
20683
  "openrouter/seed-2.0-mini": {
20375
20684
  providerModelName: "bytedance-seed/seed-2.0-mini",
@@ -20415,7 +20724,8 @@ var catalog_default4 = {
20415
20724
  family: "seed",
20416
20725
  version: "2.0",
20417
20726
  status: "stable",
20418
- active: true
20727
+ active: true,
20728
+ wireSpec: "openai/chat-completions"
20419
20729
  },
20420
20730
  "openrouter/ui-tars-1.5-7b": {
20421
20731
  providerModelName: "bytedance/ui-tars-1.5-7b",
@@ -20507,7 +20817,8 @@ var catalog_default4 = {
20507
20817
  family: "jamba",
20508
20818
  version: "1.7",
20509
20819
  status: "stable",
20510
- active: true
20820
+ active: true,
20821
+ wireSpec: "openai/chat-completions"
20511
20822
  },
20512
20823
  "openrouter/aion-1.0": {
20513
20824
  providerModelName: "aion-labs/aion-1.0",
@@ -20553,7 +20864,8 @@ var catalog_default4 = {
20553
20864
  family: "aion",
20554
20865
  version: "1.0",
20555
20866
  status: "legacy",
20556
- active: true
20867
+ active: true,
20868
+ wireSpec: "openai/chat-completions"
20557
20869
  },
20558
20870
  "openrouter/aion-2.0": {
20559
20871
  providerModelName: "aion-labs/aion-2.0",
@@ -20599,7 +20911,8 @@ var catalog_default4 = {
20599
20911
  family: "aion",
20600
20912
  version: "2.0",
20601
20913
  status: "stable",
20602
- active: true
20914
+ active: true,
20915
+ wireSpec: "openai/chat-completions"
20603
20916
  },
20604
20917
  "openrouter/olmo-3-32b-think": {
20605
20918
  providerModelName: "allenai/olmo-3-32b-think",
@@ -20644,7 +20957,8 @@ var catalog_default4 = {
20644
20957
  family: "olmo",
20645
20958
  version: "3",
20646
20959
  status: "stable",
20647
- active: true
20960
+ active: true,
20961
+ wireSpec: "openai/chat-completions"
20648
20962
  },
20649
20963
  "openrouter/trinity-large-thinking": {
20650
20964
  providerModelName: "arcee-ai/trinity-large-thinking",
@@ -20690,7 +21004,8 @@ var catalog_default4 = {
20690
21004
  family: "trinity",
20691
21005
  version: "1",
20692
21006
  status: "stable",
20693
- active: true
21007
+ active: true,
21008
+ wireSpec: "openai/chat-completions"
20694
21009
  },
20695
21010
  "openrouter/trinity-mini": {
20696
21011
  providerModelName: "arcee-ai/trinity-mini",
@@ -20735,7 +21050,8 @@ var catalog_default4 = {
20735
21050
  family: "trinity",
20736
21051
  version: "1",
20737
21052
  status: "stable",
20738
- active: true
21053
+ active: true,
21054
+ wireSpec: "openai/chat-completions"
20739
21055
  },
20740
21056
  "openrouter/virtuoso-large": {
20741
21057
  providerModelName: "arcee-ai/virtuoso-large",
@@ -20780,7 +21096,8 @@ var catalog_default4 = {
20780
21096
  family: "virtuoso",
20781
21097
  version: "1",
20782
21098
  status: "stable",
20783
- active: true
21099
+ active: true,
21100
+ wireSpec: "openai/chat-completions"
20784
21101
  },
20785
21102
  "openrouter/coder-large": {
20786
21103
  providerModelName: "arcee-ai/coder-large",
@@ -20914,7 +21231,8 @@ var catalog_default4 = {
20914
21231
  family: "cogito",
20915
21232
  version: "2.1",
20916
21233
  status: "stable",
20917
- active: true
21234
+ active: true,
21235
+ wireSpec: "openai/chat-completions"
20918
21236
  },
20919
21237
  "openrouter/rnj-1": {
20920
21238
  providerModelName: "essentialai/rnj-1-instruct",
@@ -20958,7 +21276,8 @@ var catalog_default4 = {
20958
21276
  family: "rnj",
20959
21277
  version: "1",
20960
21278
  status: "stable",
20961
- active: true
21279
+ active: true,
21280
+ wireSpec: "openai/chat-completions"
20962
21281
  },
20963
21282
  "openrouter/granite-4.0-h-micro": {
20964
21283
  providerModelName: "ibm-granite/granite-4.0-h-micro",
@@ -21003,7 +21322,8 @@ var catalog_default4 = {
21003
21322
  family: "granite",
21004
21323
  version: "4.0",
21005
21324
  status: "stable",
21006
- active: true
21325
+ active: true,
21326
+ wireSpec: "openai/chat-completions"
21007
21327
  },
21008
21328
  "openrouter/granite-4.1-8b": {
21009
21329
  providerModelName: "ibm-granite/granite-4.1-8b",
@@ -21049,7 +21369,8 @@ var catalog_default4 = {
21049
21369
  family: "granite",
21050
21370
  version: "4.1",
21051
21371
  status: "stable",
21052
- active: true
21372
+ active: true,
21373
+ wireSpec: "openai/chat-completions"
21053
21374
  },
21054
21375
  "openrouter/mercury-2": {
21055
21376
  providerModelName: "inception/mercury-2",
@@ -21095,7 +21416,8 @@ var catalog_default4 = {
21095
21416
  family: "mercury",
21096
21417
  version: "2",
21097
21418
  status: "stable",
21098
- active: true
21419
+ active: true,
21420
+ wireSpec: "openai/chat-completions"
21099
21421
  },
21100
21422
  "openrouter/ling-2.6-1t": {
21101
21423
  providerModelName: "inclusionai/ling-2.6-1t",
@@ -21141,7 +21463,8 @@ var catalog_default4 = {
21141
21463
  family: "ling",
21142
21464
  version: "2.6",
21143
21465
  status: "stable",
21144
- active: true
21466
+ active: true,
21467
+ wireSpec: "openai/chat-completions"
21145
21468
  },
21146
21469
  "openrouter/ling-2.6-flash": {
21147
21470
  providerModelName: "inclusionai/ling-2.6-flash",
@@ -21187,7 +21510,8 @@ var catalog_default4 = {
21187
21510
  family: "ling",
21188
21511
  version: "2.6",
21189
21512
  status: "stable",
21190
- active: true
21513
+ active: true,
21514
+ wireSpec: "openai/chat-completions"
21191
21515
  },
21192
21516
  "openrouter/ring-2.6-1t": {
21193
21517
  providerModelName: "inclusionai/ring-2.6-1t",
@@ -21233,7 +21557,8 @@ var catalog_default4 = {
21233
21557
  family: "ring",
21234
21558
  version: "2.6",
21235
21559
  status: "stable",
21236
- active: true
21560
+ active: true,
21561
+ wireSpec: "openai/chat-completions"
21237
21562
  },
21238
21563
  "openrouter/inflection-3-pi": {
21239
21564
  providerModelName: "inflection/inflection-3-pi",
@@ -21278,7 +21603,8 @@ var catalog_default4 = {
21278
21603
  family: "inflection",
21279
21604
  version: "3",
21280
21605
  status: "stable",
21281
- active: true
21606
+ active: true,
21607
+ wireSpec: "openai/chat-completions"
21282
21608
  },
21283
21609
  "openrouter/inflection-3-productivity": {
21284
21610
  providerModelName: "inflection/inflection-3-productivity",
@@ -21323,7 +21649,8 @@ var catalog_default4 = {
21323
21649
  family: "inflection",
21324
21650
  version: "3",
21325
21651
  status: "stable",
21326
- active: true
21652
+ active: true,
21653
+ wireSpec: "openai/chat-completions"
21327
21654
  },
21328
21655
  "openrouter/lfm-2-24b-a2b": {
21329
21656
  providerModelName: "liquid/lfm-2-24b-a2b",
@@ -21367,7 +21694,8 @@ var catalog_default4 = {
21367
21694
  family: "lfm",
21368
21695
  version: "2",
21369
21696
  status: "stable",
21370
- active: true
21697
+ active: true,
21698
+ wireSpec: "openai/chat-completions"
21371
21699
  },
21372
21700
  "openrouter/lfm-2.5-1.2b": {
21373
21701
  providerModelName: "liquid/lfm-2.5-1.2b-instruct:free",
@@ -21412,7 +21740,8 @@ var catalog_default4 = {
21412
21740
  family: "lfm",
21413
21741
  version: "2.5",
21414
21742
  status: "stable",
21415
- active: true
21743
+ active: true,
21744
+ wireSpec: "openai/chat-completions"
21416
21745
  },
21417
21746
  "openrouter/perceptron-mk1": {
21418
21747
  providerModelName: "perceptron/perceptron-mk1",
@@ -21458,7 +21787,8 @@ var catalog_default4 = {
21458
21787
  family: "perceptron",
21459
21788
  version: "1",
21460
21789
  status: "stable",
21461
- active: true
21790
+ active: true,
21791
+ wireSpec: "openai/chat-completions"
21462
21792
  },
21463
21793
  "openrouter/intellect-3": {
21464
21794
  providerModelName: "prime-intellect/intellect-3",
@@ -21503,7 +21833,8 @@ var catalog_default4 = {
21503
21833
  family: "intellect",
21504
21834
  version: "3",
21505
21835
  status: "stable",
21506
- active: true
21836
+ active: true,
21837
+ wireSpec: "openai/chat-completions"
21507
21838
  },
21508
21839
  "openrouter/reka-edge": {
21509
21840
  providerModelName: "rekaai/reka-edge",
@@ -21549,7 +21880,8 @@ var catalog_default4 = {
21549
21880
  family: "reka",
21550
21881
  version: "1",
21551
21882
  status: "legacy",
21552
- active: true
21883
+ active: true,
21884
+ wireSpec: "openai/chat-completions"
21553
21885
  },
21554
21886
  "openrouter/reka-flash-3": {
21555
21887
  providerModelName: "rekaai/reka-flash-3",
@@ -21594,7 +21926,8 @@ var catalog_default4 = {
21594
21926
  family: "reka",
21595
21927
  version: "3",
21596
21928
  status: "stable",
21597
- active: true
21929
+ active: true,
21930
+ wireSpec: "openai/chat-completions"
21598
21931
  },
21599
21932
  "openrouter/step-3.5-flash": {
21600
21933
  providerModelName: "stepfun/step-3.5-flash",
@@ -21640,7 +21973,8 @@ var catalog_default4 = {
21640
21973
  family: "step",
21641
21974
  version: "3.5",
21642
21975
  status: "stable",
21643
- active: true
21976
+ active: true,
21977
+ wireSpec: "openai/chat-completions"
21644
21978
  },
21645
21979
  "openrouter/step-3.7-flash": {
21646
21980
  providerModelName: "stepfun/step-3.7-flash",
@@ -21687,7 +22021,8 @@ var catalog_default4 = {
21687
22021
  family: "step",
21688
22022
  version: "3.7",
21689
22023
  status: "stable",
21690
- active: true
22024
+ active: true,
22025
+ wireSpec: "openai/chat-completions"
21691
22026
  },
21692
22027
  "openrouter/hunyuan-a13b": {
21693
22028
  providerModelName: "tencent/hunyuan-a13b-instruct",
@@ -21732,7 +22067,8 @@ var catalog_default4 = {
21732
22067
  family: "hunyuan",
21733
22068
  version: "1",
21734
22069
  status: "stable",
21735
- active: true
22070
+ active: true,
22071
+ wireSpec: "openai/chat-completions"
21736
22072
  },
21737
22073
  "openrouter/hunyuan-hy3": {
21738
22074
  providerModelName: "tencent/hy3",
@@ -21779,7 +22115,8 @@ var catalog_default4 = {
21779
22115
  family: "hunyuan",
21780
22116
  version: "3",
21781
22117
  status: "preview",
21782
- active: true
22118
+ active: true,
22119
+ wireSpec: "openai/chat-completions"
21783
22120
  },
21784
22121
  "openrouter/solar-pro-3": {
21785
22122
  providerModelName: "upstage/solar-pro-3",
@@ -21824,7 +22161,8 @@ var catalog_default4 = {
21824
22161
  family: "solar",
21825
22162
  version: "3",
21826
22163
  status: "stable",
21827
- active: true
22164
+ active: true,
22165
+ wireSpec: "openai/chat-completions"
21828
22166
  },
21829
22167
  "openrouter/palmyra-x5": {
21830
22168
  providerModelName: "writer/palmyra-x5",
@@ -21869,7 +22207,8 @@ var catalog_default4 = {
21869
22207
  family: "palmyra",
21870
22208
  version: "5",
21871
22209
  status: "stable",
21872
- active: true
22210
+ active: true,
22211
+ wireSpec: "openai/chat-completions"
21873
22212
  },
21874
22213
  "openrouter/mimo-v2-flash": {
21875
22214
  providerModelName: "xiaomi/mimo-v2-flash",
@@ -21915,7 +22254,8 @@ var catalog_default4 = {
21915
22254
  family: "mimo",
21916
22255
  version: "2",
21917
22256
  status: "stable",
21918
- active: true
22257
+ active: true,
22258
+ wireSpec: "openai/chat-completions"
21919
22259
  },
21920
22260
  "openrouter/mimo-v2.5": {
21921
22261
  providerModelName: "xiaomi/mimo-v2.5",
@@ -21963,7 +22303,8 @@ var catalog_default4 = {
21963
22303
  family: "mimo",
21964
22304
  version: "2.5",
21965
22305
  status: "stable",
21966
- active: true
22306
+ active: true,
22307
+ wireSpec: "openai/chat-completions"
21967
22308
  },
21968
22309
  "openrouter/mimo-v2.5-pro": {
21969
22310
  providerModelName: "xiaomi/mimo-v2.5-pro",
@@ -22009,7 +22350,8 @@ var catalog_default4 = {
22009
22350
  family: "mimo",
22010
22351
  version: "2.5",
22011
22352
  status: "stable",
22012
- active: true
22353
+ active: true,
22354
+ wireSpec: "openai/chat-completions"
22013
22355
  },
22014
22356
  "openrouter/nex-n2-pro": {
22015
22357
  providerModelName: "nex-agi/nex-n2-pro:free",
@@ -22057,7 +22399,8 @@ var catalog_default4 = {
22057
22399
  family: "nex",
22058
22400
  version: "2",
22059
22401
  status: "stable",
22060
- active: true
22402
+ active: true,
22403
+ wireSpec: "openai/chat-completions"
22061
22404
  },
22062
22405
  "openrouter/kat-coder-pro-v2": {
22063
22406
  providerModelName: "kwaipilot/kat-coder-pro-v2",
@@ -22243,7 +22586,8 @@ var catalog_default4 = {
22243
22586
  family: "roleplay-finetunes",
22244
22587
  version: "1",
22245
22588
  status: "stable",
22246
- active: true
22589
+ active: true,
22590
+ wireSpec: "openai/chat-completions"
22247
22591
  },
22248
22592
  "openrouter/magnum-v4-72b": {
22249
22593
  providerModelName: "anthracite-org/magnum-v4-72b",
@@ -22288,7 +22632,8 @@ var catalog_default4 = {
22288
22632
  family: "roleplay-finetunes",
22289
22633
  version: "4",
22290
22634
  status: "stable",
22291
- active: true
22635
+ active: true,
22636
+ wireSpec: "openai/chat-completions"
22292
22637
  },
22293
22638
  "openrouter/dolphin-mistral-24b-venice": {
22294
22639
  providerModelName: "cognitivecomputations/dolphin-mistral-24b-venice-edition:free",
@@ -22338,7 +22683,8 @@ var catalog_default4 = {
22338
22683
  shutdownDate: "2026-07-19",
22339
22684
  source: "openrouter"
22340
22685
  },
22341
- maxOutput: 8192
22686
+ maxOutput: 8192,
22687
+ wireSpec: "openai/chat-completions"
22342
22688
  },
22343
22689
  "openrouter/mythomax-l2-13b": {
22344
22690
  providerModelName: "gryphe/mythomax-l2-13b",
@@ -22383,7 +22729,8 @@ var catalog_default4 = {
22383
22729
  family: "roleplay-finetunes",
22384
22730
  version: "2",
22385
22731
  status: "legacy",
22386
- active: true
22732
+ active: true,
22733
+ wireSpec: "openai/chat-completions"
22387
22734
  },
22388
22735
  "openrouter/weaver": {
22389
22736
  providerModelName: "mancer/weaver",
@@ -22428,7 +22775,8 @@ var catalog_default4 = {
22428
22775
  family: "roleplay-finetunes",
22429
22776
  version: "1",
22430
22777
  status: "legacy",
22431
- active: true
22778
+ active: true,
22779
+ wireSpec: "openai/chat-completions"
22432
22780
  },
22433
22781
  "openrouter/lunaris-8b": {
22434
22782
  providerModelName: "sao10k/l3-lunaris-8b",
@@ -22473,7 +22821,8 @@ var catalog_default4 = {
22473
22821
  family: "roleplay-finetunes",
22474
22822
  version: "3",
22475
22823
  status: "stable",
22476
- active: true
22824
+ active: true,
22825
+ wireSpec: "openai/chat-completions"
22477
22826
  },
22478
22827
  "openrouter/euryale-70b": {
22479
22828
  providerModelName: "sao10k/l3.1-euryale-70b",
@@ -22520,7 +22869,8 @@ var catalog_default4 = {
22520
22869
  family: "roleplay-finetunes",
22521
22870
  version: "3.1",
22522
22871
  status: "stable",
22523
- active: true
22872
+ active: true,
22873
+ wireSpec: "openai/chat-completions"
22524
22874
  },
22525
22875
  "openrouter/cydonia-24b-v4.1": {
22526
22876
  providerModelName: "thedrummer/cydonia-24b-v4.1",
@@ -22566,7 +22916,8 @@ var catalog_default4 = {
22566
22916
  family: "roleplay-finetunes",
22567
22917
  version: "4.1",
22568
22918
  status: "stable",
22569
- active: true
22919
+ active: true,
22920
+ wireSpec: "openai/chat-completions"
22570
22921
  },
22571
22922
  "openrouter/rocinante-12b": {
22572
22923
  providerModelName: "thedrummer/rocinante-12b",
@@ -22611,7 +22962,8 @@ var catalog_default4 = {
22611
22962
  family: "roleplay-finetunes",
22612
22963
  version: "1",
22613
22964
  status: "stable",
22614
- active: true
22965
+ active: true,
22966
+ wireSpec: "openai/chat-completions"
22615
22967
  },
22616
22968
  "openrouter/skyfall-36b-v2": {
22617
22969
  providerModelName: "thedrummer/skyfall-36b-v2",
@@ -22657,7 +23009,8 @@ var catalog_default4 = {
22657
23009
  family: "roleplay-finetunes",
22658
23010
  version: "2",
22659
23011
  status: "stable",
22660
- active: true
23012
+ active: true,
23013
+ wireSpec: "openai/chat-completions"
22661
23014
  },
22662
23015
  "openrouter/unslopnemo-12b": {
22663
23016
  providerModelName: "thedrummer/unslopnemo-12b",
@@ -22702,7 +23055,8 @@ var catalog_default4 = {
22702
23055
  family: "roleplay-finetunes",
22703
23056
  version: "1",
22704
23057
  status: "stable",
22705
- active: true
23058
+ active: true,
23059
+ wireSpec: "openai/chat-completions"
22706
23060
  },
22707
23061
  "openrouter/remm-slerp-l2-13b": {
22708
23062
  providerModelName: "undi95/remm-slerp-l2-13b",
@@ -22747,7 +23101,8 @@ var catalog_default4 = {
22747
23101
  family: "roleplay-finetunes",
22748
23102
  version: "2",
22749
23103
  status: "legacy",
22750
- active: true
23104
+ active: true,
23105
+ wireSpec: "openai/chat-completions"
22751
23106
  },
22752
23107
  "openrouter/claude-sonnet-5": {
22753
23108
  providerModelName: "anthropic/claude-sonnet-5",
@@ -22794,7 +23149,8 @@ var catalog_default4 = {
22794
23149
  family: "claude-sonnet",
22795
23150
  version: "5",
22796
23151
  status: "stable",
22797
- active: true
23152
+ active: true,
23153
+ wireSpec: "openai/chat-completions"
22798
23154
  },
22799
23155
  "openrouter/gpt-5.6-luna": {
22800
23156
  providerModelName: "openai/gpt-5.6-luna",
@@ -22841,7 +23197,8 @@ var catalog_default4 = {
22841
23197
  family: "gpt",
22842
23198
  version: "5.6",
22843
23199
  status: "stable",
22844
- active: true
23200
+ active: true,
23201
+ wireSpec: "openai/chat-completions"
22845
23202
  },
22846
23203
  "openrouter/gpt-5.6-terra": {
22847
23204
  providerModelName: "openai/gpt-5.6-terra",
@@ -22888,7 +23245,8 @@ var catalog_default4 = {
22888
23245
  family: "gpt",
22889
23246
  version: "5.6",
22890
23247
  status: "stable",
22891
- active: true
23248
+ active: true,
23249
+ wireSpec: "openai/chat-completions"
22892
23250
  },
22893
23251
  "openrouter/gpt-5.6-sol": {
22894
23252
  providerModelName: "openai/gpt-5.6-sol",
@@ -22935,7 +23293,8 @@ var catalog_default4 = {
22935
23293
  family: "gpt",
22936
23294
  version: "5.6",
22937
23295
  status: "stable",
22938
- active: true
23296
+ active: true,
23297
+ wireSpec: "openai/chat-completions"
22939
23298
  },
22940
23299
  "openrouter/gpt-5.6-luna-pro": {
22941
23300
  providerModelName: "openai/gpt-5.6-luna-pro",
@@ -22982,7 +23341,8 @@ var catalog_default4 = {
22982
23341
  family: "gpt-pro",
22983
23342
  version: "5.6",
22984
23343
  status: "stable",
22985
- active: true
23344
+ active: true,
23345
+ wireSpec: "openai/chat-completions"
22986
23346
  },
22987
23347
  "openrouter/gpt-5.6-terra-pro": {
22988
23348
  providerModelName: "openai/gpt-5.6-terra-pro",
@@ -23029,7 +23389,8 @@ var catalog_default4 = {
23029
23389
  family: "gpt-pro",
23030
23390
  version: "5.6",
23031
23391
  status: "stable",
23032
- active: true
23392
+ active: true,
23393
+ wireSpec: "openai/chat-completions"
23033
23394
  },
23034
23395
  "openrouter/gpt-5.6-sol-pro": {
23035
23396
  providerModelName: "openai/gpt-5.6-sol-pro",
@@ -23076,7 +23437,8 @@ var catalog_default4 = {
23076
23437
  family: "gpt-pro",
23077
23438
  version: "5.6",
23078
23439
  status: "stable",
23079
- active: true
23440
+ active: true,
23441
+ wireSpec: "openai/chat-completions"
23080
23442
  },
23081
23443
  "openrouter/gemini-3.1-flash-lite-image": {
23082
23444
  providerModelName: "google/gemini-3.1-flash-lite-image",
@@ -23193,7 +23555,8 @@ var catalog_default4 = {
23193
23555
  family: "grok",
23194
23556
  version: "4.5",
23195
23557
  status: "stable",
23196
- active: true
23558
+ active: true,
23559
+ wireSpec: "openai/chat-completions"
23197
23560
  },
23198
23561
  "openrouter/glm-5.2": {
23199
23562
  providerModelName: "z-ai/glm-5.2",
@@ -23239,7 +23602,8 @@ var catalog_default4 = {
23239
23602
  family: "glm",
23240
23603
  version: "5.2",
23241
23604
  status: "stable",
23242
- active: true
23605
+ active: true,
23606
+ wireSpec: "openai/chat-completions"
23243
23607
  },
23244
23608
  "openrouter/glm-5v-turbo": {
23245
23609
  providerModelName: "z-ai/glm-5v-turbo",
@@ -23336,7 +23700,8 @@ var catalog_default4 = {
23336
23700
  family: "aion",
23337
23701
  version: "3.0",
23338
23702
  status: "stable",
23339
- active: true
23703
+ active: true,
23704
+ wireSpec: "openai/chat-completions"
23340
23705
  },
23341
23706
  "openrouter/aion-3.0": {
23342
23707
  providerModelName: "aion-labs/aion-3.0",
@@ -23382,7 +23747,8 @@ var catalog_default4 = {
23382
23747
  family: "aion",
23383
23748
  version: "3.0",
23384
23749
  status: "stable",
23385
- active: true
23750
+ active: true,
23751
+ wireSpec: "openai/chat-completions"
23386
23752
  },
23387
23753
  "openrouter/nex-n2-mini": {
23388
23754
  providerModelName: "nex-agi/nex-n2-mini",
@@ -23429,7 +23795,8 @@ var catalog_default4 = {
23429
23795
  family: "nex",
23430
23796
  version: "2",
23431
23797
  status: "stable",
23432
- active: true
23798
+ active: true,
23799
+ wireSpec: "openai/chat-completions"
23433
23800
  },
23434
23801
  "openrouter/laguna-xs.2.1": {
23435
23802
  providerModelName: "poolside/laguna-xs-2.1",
@@ -23524,7 +23891,8 @@ var catalog_default4 = {
23524
23891
  family: "fugu",
23525
23892
  version: "1",
23526
23893
  status: "stable",
23527
- active: true
23894
+ active: true,
23895
+ wireSpec: "openai/chat-completions"
23528
23896
  },
23529
23897
  "openrouter/north-mini-code": {
23530
23898
  providerModelName: "cohere/north-mini-code:free",
@@ -23707,7 +24075,8 @@ var catalog_default4 = {
23707
24075
  family: "claude-opus",
23708
24076
  version: "5",
23709
24077
  status: "stable",
23710
- active: true
24078
+ active: true,
24079
+ wireSpec: "openai/chat-completions"
23711
24080
  },
23712
24081
  "openrouter/claude-opus-5": {
23713
24082
  providerModelName: "anthropic/claude-opus-5",
@@ -23754,7 +24123,8 @@ var catalog_default4 = {
23754
24123
  family: "claude-opus",
23755
24124
  version: "5",
23756
24125
  status: "stable",
23757
- active: true
24126
+ active: true,
24127
+ wireSpec: "openai/chat-completions"
23758
24128
  },
23759
24129
  "openrouter/gemini-3.6-flash": {
23760
24130
  providerModelName: "google/gemini-3.6-flash",
@@ -23802,7 +24172,8 @@ var catalog_default4 = {
23802
24172
  family: "gemini-flash",
23803
24173
  version: "3.6",
23804
24174
  status: "stable",
23805
- active: true
24175
+ active: true,
24176
+ wireSpec: "openai/chat-completions"
23806
24177
  },
23807
24178
  "openrouter/gemini-3.5-flash-lite": {
23808
24179
  providerModelName: "google/gemini-3.5-flash-lite",
@@ -23850,7 +24221,8 @@ var catalog_default4 = {
23850
24221
  family: "gemini-flash-lite",
23851
24222
  version: "3.5",
23852
24223
  status: "stable",
23853
- active: true
24224
+ active: true,
24225
+ wireSpec: "openai/chat-completions"
23854
24226
  },
23855
24227
  "openrouter/kimi-k3": {
23856
24228
  providerModelName: "moonshotai/kimi-k3",
@@ -23896,7 +24268,8 @@ var catalog_default4 = {
23896
24268
  family: "kimi",
23897
24269
  version: "3",
23898
24270
  status: "stable",
23899
- active: true
24271
+ active: true,
24272
+ wireSpec: "openai/chat-completions"
23900
24273
  },
23901
24274
  "openrouter/ling-3.0-flash": {
23902
24275
  providerModelName: "inclusionai/ling-3.0-flash:free",
@@ -23941,7 +24314,8 @@ var catalog_default4 = {
23941
24314
  family: "ling",
23942
24315
  version: "3.0",
23943
24316
  status: "stable",
23944
- active: true
24317
+ active: true,
24318
+ wireSpec: "openai/chat-completions"
23945
24319
  },
23946
24320
  "openrouter/kat-coder-air-v2.5": {
23947
24321
  providerModelName: "kwaipilot/kat-coder-air-v2.5",
@@ -24126,7 +24500,8 @@ var catalog_default4 = {
24126
24500
  family: "longcat",
24127
24501
  version: "2.0",
24128
24502
  status: "stable",
24129
- active: true
24503
+ active: true,
24504
+ wireSpec: "openai/chat-completions"
24130
24505
  },
24131
24506
  "openrouter/inkling": {
24132
24507
  providerModelName: "thinkingmachines/inkling",
@@ -24173,7 +24548,8 @@ var catalog_default4 = {
24173
24548
  family: "inkling",
24174
24549
  version: "1",
24175
24550
  status: "stable",
24176
- active: true
24551
+ active: true,
24552
+ wireSpec: "openai/chat-completions"
24177
24553
  },
24178
24554
  "openrouter/muse-spark-1.1": {
24179
24555
  providerModelName: "meta/muse-spark-1.1",
@@ -24250,8 +24626,8 @@ var catalog_default4 = {
24250
24626
  }
24251
24627
  };
24252
24628
 
24253
- // src/llm/providers/xai/catalog.json
24254
- var catalog_default5 = {
24629
+ // src/catalog/data/xai.json
24630
+ var xai_default = {
24255
24631
  "xai/grok-4.20": {
24256
24632
  providerModelName: "grok-4.20-0309-reasoning",
24257
24633
  aliases: [
@@ -24305,7 +24681,8 @@ var catalog_default5 = {
24305
24681
  family: "grok",
24306
24682
  version: "4.20",
24307
24683
  status: "stable",
24308
- active: true
24684
+ active: true,
24685
+ wireSpec: "openai/responses"
24309
24686
  },
24310
24687
  "xai/grok-4.20-non-reasoning": {
24311
24688
  providerModelName: "grok-4.20-0309-non-reasoning",
@@ -24359,7 +24736,8 @@ var catalog_default5 = {
24359
24736
  version: "4.20",
24360
24737
  status: "stable",
24361
24738
  active: true,
24362
- contextWindow: 2e6
24739
+ contextWindow: 2e6,
24740
+ wireSpec: "openai/responses"
24363
24741
  },
24364
24742
  "xai/grok-4.20-multi-agent": {
24365
24743
  providerModelName: "grok-4.20-multi-agent-0309",
@@ -24412,7 +24790,8 @@ var catalog_default5 = {
24412
24790
  family: "grok",
24413
24791
  version: "4.20",
24414
24792
  status: "stable",
24415
- active: true
24793
+ active: true,
24794
+ wireSpec: "openai/responses"
24416
24795
  },
24417
24796
  "xai/grok-4.3": {
24418
24797
  providerModelName: "grok-4.3",
@@ -24467,7 +24846,8 @@ var catalog_default5 = {
24467
24846
  family: "grok",
24468
24847
  version: "4.3",
24469
24848
  status: "stable",
24470
- active: true
24849
+ active: true,
24850
+ wireSpec: "openai/responses"
24471
24851
  },
24472
24852
  "xai/grok-build-0.1": {
24473
24853
  providerModelName: "grok-build-0.1",
@@ -24875,11 +25255,12 @@ var catalog_default5 = {
24875
25255
  family: "grok",
24876
25256
  version: "4.5",
24877
25257
  status: "stable",
24878
- active: true
25258
+ active: true,
25259
+ wireSpec: "openai/responses"
24879
25260
  }
24880
25261
  };
24881
25262
 
24882
- // src/llm/providers/builtin-tools.ts
25263
+ // src/catalog/builtin-tools.ts
24883
25264
  var PROVIDER_BUILTIN_TOOLS = {
24884
25265
  anthropic: ["web_search", "web_fetch", "code_interpreter"],
24885
25266
  openai: ["web_search", "code_interpreter"],
@@ -24888,13 +25269,13 @@ var PROVIDER_BUILTIN_TOOLS = {
24888
25269
  openrouter: ["web_search"]
24889
25270
  };
24890
25271
 
24891
- // src/plugins/model-catalog/catalog.ts
25272
+ // src/catalog/catalog.ts
24892
25273
  var PROVIDER_DEFAULT_CATALOGS = [
24893
- catalog_default,
24894
- catalog_default3,
24895
- catalog_default2,
24896
- catalog_default5,
24897
- catalog_default4
25274
+ anthropic_default,
25275
+ openai_default,
25276
+ google_default,
25277
+ xai_default,
25278
+ openrouter_default
24898
25279
  ];
24899
25280
  var PROVIDER_STATE = {
24900
25281
  // OpenAI/xAI: previous_response_id survives most model swaps but can break at
@@ -24956,6 +25337,8 @@ var ModelCatalog = class {
24956
25337
  tokenizer: info.tokenizer,
24957
25338
  requiresDedicatedClient: info.requiresDedicatedClient,
24958
25339
  supportsPreviousResponseId: info.supportsPreviousResponseId,
25340
+ wire: info.wire,
25341
+ wireSpec: info.wireSpec,
24959
25342
  stateRetentionDuration: info.stateRetentionDuration,
24960
25343
  stateModelBound: info.stateModelBound,
24961
25344
  providerModelName: info.providerModelName,
@@ -25489,9 +25872,9 @@ function buildContext(client, options) {
25489
25872
  ...provided,
25490
25873
  sessionId: provided.sessionId ?? client.sessionId,
25491
25874
  clientId: provided.clientId ?? client.id,
25492
- queueName: provided.queueName ?? client.queueName,
25493
- configName: options.configName ?? provided.configName ?? client.configName,
25494
- cacheName: options.cacheName ?? provided.cacheName ?? client.cacheName,
25875
+ queueName: provided.queueName ?? client.routing.queueName,
25876
+ configName: options.configName ?? provided.configName ?? client.routing.configName,
25877
+ cacheName: options.cacheName ?? provided.cacheName ?? client.routing.cacheName,
25495
25878
  cacheKey: options.cacheKey ?? provided.cacheKey
25496
25879
  };
25497
25880
  if (!ctx.callId) ctx.callId = `call_${crypto.randomUUID().slice(0, 8)}`;
@@ -25544,6 +25927,9 @@ var LLMClient = class {
25544
25927
  queueName;
25545
25928
  configName;
25546
25929
  cacheName;
25930
+ /** The routing names this client was configured with, exposed so context
25931
+ * building does not have to cast into the privates above. */
25932
+ routing;
25547
25933
  cacheKeyFn;
25548
25934
  catalog;
25549
25935
  constructor(config) {
@@ -25573,6 +25959,11 @@ var LLMClient = class {
25573
25959
  this.queueName = config.queueName ?? `${config.provider}/${config.model}`;
25574
25960
  this.configName = config.configName ?? `${config.provider}/${config.model}`;
25575
25961
  this.cacheName = config.cacheName ?? "default";
25962
+ this.routing = Object.freeze({
25963
+ queueName: this.queueName,
25964
+ configName: this.configName,
25965
+ cacheName: this.cacheName
25966
+ });
25576
25967
  this.cacheKeyFn = config.cacheKeyFn;
25577
25968
  this.catalog = config.catalog ?? new ModelCatalog();
25578
25969
  this.hooks.emitSync("onClientCreate", {
@@ -25666,6 +26057,7 @@ var LLMClient = class {
25666
26057
  const ctx = buildContext(this, options);
25667
26058
  const normalized = {
25668
26059
  model: this.model,
26060
+ wire: this.catalog.get(this.provider, this.model)?.wire,
25669
26061
  messages,
25670
26062
  system: composedSystem,
25671
26063
  maxTokens: options.maxTokens,
@@ -25838,6 +26230,7 @@ var LLMClient = class {
25838
26230
  const ctx = buildContext(this, options);
25839
26231
  const normalized = {
25840
26232
  model: this.model,
26233
+ wire: this.catalog.get(this.provider, this.model)?.wire,
25841
26234
  messages,
25842
26235
  system: composedSystem,
25843
26236
  maxTokens: options.maxTokens,
@@ -26026,7 +26419,7 @@ var DEFAULT_ANTHROPIC_THINKING_BUDGET = 2048;
26026
26419
  var ANTHROPIC_ADAPTIVE_THINKING_MIN = { major: 4, minor: 6 };
26027
26420
  function anthropicThinkingShape(model) {
26028
26421
  const id = model.toLowerCase().replace(/^anthropic\//, "");
26029
- const modern = /^claude-[a-z]+-(\d+)(?:[-.](\d+))?/.exec(id);
26422
+ const modern = /^claude-[a-z]+-(\d+)(?:[-.](\d{1,2})(?!\d))?/.exec(id);
26030
26423
  if (modern) {
26031
26424
  const major = Number(modern[1]);
26032
26425
  const minor = modern[2] === void 0 ? 0 : Number(modern[2]);
@@ -26273,6 +26666,11 @@ function extractFinishReason(hasToolCalls, providerReason, reasonMap) {
26273
26666
  return (providerReason !== void 0 ? reasonMap[providerReason] : void 0) ?? "stop";
26274
26667
  }
26275
26668
 
26669
+ // src/llm/providers/_shared/sse.ts
26670
+ function sseJson(event) {
26671
+ return JSON.parse(event.data);
26672
+ }
26673
+
26276
26674
  // src/llm/providers/anthropic/messages.ts
26277
26675
  var ANTHROPIC_REQUEST_TIER = {
26278
26676
  auto: "auto",
@@ -26363,7 +26761,7 @@ var AnthropicAdapter = class {
26363
26761
  }
26364
26762
  if (req.temperature !== void 0) body.temperature = req.temperature;
26365
26763
  if (req.topP !== void 0) body.top_p = req.topP;
26366
- if (req.topK !== void 0 && anthropicAcceptsTopK(req.model)) body.top_k = req.topK;
26764
+ if (req.topK !== void 0 && (req.wire?.topK ?? anthropicAcceptsTopK(req.model))) body.top_k = req.topK;
26367
26765
  if (req.stop) body.stop_sequences = req.stop;
26368
26766
  const tier = anthropicRequestTier(req.serviceTier);
26369
26767
  if (tier) body.service_tier = tier;
@@ -26417,7 +26815,7 @@ var AnthropicAdapter = class {
26417
26815
  }
26418
26816
  if (req.thinking) {
26419
26817
  if (req.thinking.mode === "off") {
26420
- } else if (anthropicThinkingShape(req.model) === "adaptive") {
26818
+ } else if ((req.wire?.thinking ?? anthropicThinkingShape(req.model)) === "adaptive") {
26421
26819
  const thinking = { type: "adaptive" };
26422
26820
  if (req.thinking.visibility === "hidden") thinking.display = "omitted";
26423
26821
  body.thinking = thinking;
@@ -26592,7 +26990,7 @@ var AnthropicAdapter = class {
26592
26990
  }
26593
26991
  streamEvents(event, state) {
26594
26992
  if (event.event === "ping") return [];
26595
- const data = JSON.parse(event.data);
26993
+ const data = sseJson(event);
26596
26994
  const type = data.type;
26597
26995
  if (type === "content_block_delta") {
26598
26996
  const delta = data.delta;
@@ -26804,6 +27202,11 @@ var GoogleBatchAdapter = class {
26804
27202
 
26805
27203
  // src/llm/providers/google/files.ts
26806
27204
  var FORTY_EIGHT_HOURS = 48 * 60 * 60 * 1e3;
27205
+ function googleFileName(remoteId) {
27206
+ if (remoteId.includes("/files/")) return remoteId.split("/files/").pop() ?? remoteId;
27207
+ if (remoteId.startsWith("files/")) return remoteId.slice("files/".length);
27208
+ return remoteId;
27209
+ }
26807
27210
  var GoogleFileAdapter = class {
26808
27211
  name = "google";
26809
27212
  expiresAfter = FORTY_EIGHT_HOURS;
@@ -26868,7 +27271,7 @@ var GoogleFileAdapter = class {
26868
27271
  };
26869
27272
  }
26870
27273
  async delete(remoteId, fetch2) {
26871
- const name = remoteId.includes("/files/") ? remoteId.split("/files/").pop() : remoteId;
27274
+ const name = googleFileName(remoteId);
26872
27275
  await fetch2({
26873
27276
  url: `${this.baseURL}/v1beta/files/${name}?key=${this.apiKey}`,
26874
27277
  method: "DELETE",
@@ -26880,7 +27283,7 @@ var GoogleFileAdapter = class {
26880
27283
  });
26881
27284
  }
26882
27285
  async getInfo(remoteId, fetch2) {
26883
- const name = remoteId.includes("/files/") ? remoteId.split("/files/").pop() : remoteId;
27286
+ const name = googleFileName(remoteId);
26884
27287
  const res = await fetch2({
26885
27288
  url: `${this.baseURL}/v1beta/files/${name}?key=${this.apiKey}`,
26886
27289
  method: "GET",
@@ -27030,7 +27433,30 @@ var GoogleAdapter = class {
27030
27433
  functionDeclarations: fnTools.map((t) => ({
27031
27434
  name: t.name,
27032
27435
  description: t.description,
27033
- parameters: t.parameters
27436
+ // `parametersJsonSchema`, NOT `parameters`. The two are mutually exclusive
27437
+ // (sending both is a 400) and accept different things:
27438
+ //
27439
+ // parameters a narrow OpenAPI subset. Anything outside it is
27440
+ // rejected outright with `Unknown name "<keyword>"` —
27441
+ // measured: additionalProperties (at any depth),
27442
+ // $schema, $ref, $defs, definitions, const, examples,
27443
+ // exclusiveMinimum/Maximum, multipleOf, uniqueItems,
27444
+ // patternProperties, propertyNames, if/then,
27445
+ // readOnly, deprecated, and `type` as an array.
27446
+ // parametersJsonSchema full JSON Schema.
27447
+ //
27448
+ // We passed callers' schemas straight into `parameters`, so any tool defined
27449
+ // with `additionalProperties: false` — which OpenAI's strict mode requires —
27450
+ // failed on EVERY Gemini model. A consuming app had to delete it from its
27451
+ // manifest, degrading its OpenAI schema to keep Google working.
27452
+ //
27453
+ // Sanitising into the subset was the obvious fix and is the wrong one: it
27454
+ // silently drops constraints and cannot express a `$ref` at all. Verified on
27455
+ // every tool-capable model we ship (2.5 pro/flash/flash-lite, 3-flash,
27456
+ // 3.1-pro incl. customtools, 3.1-flash-lite, 3.5-flash/-lite, 3.6-flash,
27457
+ // gemma-4-26b/-31b) that this field takes the schema unchanged and the model
27458
+ // still calls the tool.
27459
+ parametersJsonSchema: t.parameters
27034
27460
  }))
27035
27461
  });
27036
27462
  }
@@ -27054,7 +27480,8 @@ var GoogleAdapter = class {
27054
27480
  const thinkingConfig = {
27055
27481
  includeThoughts: req.thinking.visibility !== "hidden"
27056
27482
  };
27057
- if (googleUsesThinkingBudget(req.model)) {
27483
+ const usesBudget = req.wire?.thinking ? req.wire.thinking === "budget" : googleUsesThinkingBudget(req.model);
27484
+ if (usesBudget) {
27058
27485
  thinkingConfig.thinkingBudget = GOOGLE_THINKING_BUDGETS[effort] ?? GOOGLE_THINKING_BUDGETS.high;
27059
27486
  } else {
27060
27487
  thinkingConfig.thinkingLevel = GOOGLE_THINKING_LEVELS[effort] ?? "HIGH";
@@ -27281,7 +27708,7 @@ var GoogleAdapter = class {
27281
27708
  return (event) => this.streamEvents(event, state);
27282
27709
  }
27283
27710
  streamEvents(event, state) {
27284
- const data = JSON.parse(event.data);
27711
+ const data = sseJson(event);
27285
27712
  const candidates = data.candidates ?? [];
27286
27713
  const candidate = candidates[0];
27287
27714
  if (!candidate) {
@@ -27622,7 +28049,7 @@ var GoogleInteractionsAdapter = class {
27622
28049
  * function call's `arguments_delta` carries no id, so we correlate it to the
27623
28050
  * currently-open call id held in `state`. */
27624
28051
  streamEvents(event, state) {
27625
- const data = JSON.parse(event.data);
28052
+ const data = sseJson(event);
27626
28053
  const type = data.event_type ?? data.type;
27627
28054
  const events = [];
27628
28055
  if (type === "step.start") {
@@ -27716,7 +28143,7 @@ function sniffImageMime(b) {
27716
28143
  return void 0;
27717
28144
  }
27718
28145
 
27719
- // src/plugins/media/source-image.ts
28146
+ // src/util/source-image.ts
27720
28147
  function mimeFromBase64Prefix(b64) {
27721
28148
  try {
27722
28149
  const n = Math.min(24, b64.length - b64.length % 4);
@@ -27852,42 +28279,103 @@ var GoogleMediaAdapter = class {
27852
28279
  audioStreaming: false
27853
28280
  };
27854
28281
  }
27855
- async generateImage(req, fetch2) {
27856
- const model = req.model ?? "imagen-4.0-generate-001";
27857
- if (!model.startsWith("imagen")) {
27858
- const generationConfig = { responseModalities: ["IMAGE"] };
27859
- const image = {};
27860
- if (req.params?.aspectRatio) image.aspectRatio = req.params.aspectRatio;
27861
- if (req.params?.imageSize) image.imageSize = req.params.imageSize;
27862
- if (Object.keys(image).length) generationConfig.imageConfig = image;
27863
- const { items, usage } = await this.generateContentMedia(
27864
- model,
27865
- req.prompt,
27866
- generationConfig,
27867
- fetch2
27868
- );
27869
- return items.map((m, i) => ({
27870
- data: base64ToBytes(m.data),
27871
- mimeType: m.mimeType ?? "image/png",
27872
- usage: i === 0 ? usage : void 0
27873
- }));
27874
- }
28282
+ // ─── request builders ────────────────────────────────────────────────
28283
+ //
28284
+ // Split out from the methods that fetch and parse, so a request can be built,
28285
+ // inspected and asserted without performing it. Everything above this line
28286
+ // used to construct its request inline, which meant the only way to see what
28287
+ // the adapter would send was to intercept the network.
28288
+ /** Imagen image generation: the Vertex-style `:predict` envelope. */
28289
+ buildImagenRequest(req, model = req.model ?? "imagen-4.0-generate-001") {
27875
28290
  const parameters = { sampleCount: req.params?.n ?? 1 };
27876
28291
  if (req.params?.aspectRatio) parameters.aspectRatio = req.params.aspectRatio;
27877
28292
  if (req.params?.imageSize) parameters.sampleImageSize = req.params.imageSize;
27878
- const body = {
27879
- instances: [{ prompt: req.prompt }],
27880
- parameters
27881
- };
27882
- const res = await fetch2({
28293
+ return {
27883
28294
  url: `${this.baseURL}/v1beta/models/${model}:predict?key=${this.apiKey}`,
27884
28295
  method: "POST",
27885
28296
  headers: { "content-type": "application/json" },
27886
- body,
28297
+ body: { instances: [{ prompt: req.prompt }], parameters },
28298
+ provider: "google",
28299
+ model,
28300
+ responseType: "json"
28301
+ };
28302
+ }
28303
+ /** The inline-media path shared by gemini image generation, editing and TTS. */
28304
+ buildGenerateContentRequest(model, text, generationConfig, extraParts = []) {
28305
+ return {
28306
+ url: `${this.baseURL}/v1beta/models/${model}:generateContent?key=${this.apiKey}`,
28307
+ method: "POST",
28308
+ headers: { "content-type": "application/json" },
28309
+ body: { contents: [{ parts: [{ text }, ...extraParts] }], generationConfig },
27887
28310
  provider: "google",
27888
28311
  model,
27889
28312
  responseType: "json"
28313
+ };
28314
+ }
28315
+ /** Veo video submission — a long-running operation, hence the endpoint. */
28316
+ buildVideoRequest(req, model = req.model ?? "veo-3.1-generate-preview") {
28317
+ const instance = { prompt: req.prompt };
28318
+ if (req.sourceImage) instance.image = googleVeoImage(normalizeImageSource(req.sourceImage));
28319
+ const parameters = {};
28320
+ if (req.params?.duration) parameters.durationSeconds = req.params.duration;
28321
+ if (req.params?.aspectRatio) parameters.aspectRatio = req.params.aspectRatio;
28322
+ if (req.params?.resolution) parameters.resolution = req.params.resolution;
28323
+ return {
28324
+ url: `${this.baseURL}/v1beta/models/${model}:predictLongRunning?key=${this.apiKey}`,
28325
+ method: "POST",
28326
+ headers: { "content-type": "application/json" },
28327
+ body: { instances: [instance], parameters },
28328
+ provider: "google",
28329
+ model,
28330
+ responseType: "json"
28331
+ };
28332
+ }
28333
+ /** `generationConfig` for the gemini image paths — generation and editing take
28334
+ * the same one. */
28335
+ imageGenerationConfig(params) {
28336
+ const generationConfig = { responseModalities: ["IMAGE"] };
28337
+ const image = {};
28338
+ if (params?.aspectRatio) image.aspectRatio = params.aspectRatio;
28339
+ if (params?.imageSize) image.imageSize = params.imageSize;
28340
+ if (Object.keys(image).length) generationConfig.imageConfig = image;
28341
+ return generationConfig;
28342
+ }
28343
+ /** The complete image request, whichever of the two Google image paths applies:
28344
+ * Imagen models use `:predict`, gemini-* models generate inline via
28345
+ * `:generateContent` steered by responseModalities. */
28346
+ buildImageRequest(req, model = req.model ?? "imagen-4.0-generate-001") {
28347
+ return model.startsWith("imagen") ? this.buildImagenRequest(req, model) : this.buildGenerateContentRequest(model, req.prompt, this.imageGenerationConfig(req.params));
28348
+ }
28349
+ /** Gemini TTS: the same inline path with an AUDIO modality and a speechConfig. */
28350
+ buildAudioRequest(req, model = req.model ?? "gemini-2.5-flash-preview-tts") {
28351
+ const voiceName = resolveVoice("google", req.params?.voice) ?? "Kore";
28352
+ return this.buildGenerateContentRequest(model, req.input, {
28353
+ responseModalities: ["AUDIO"],
28354
+ speechConfig: { voiceConfig: { prebuiltVoiceConfig: { voiceName } } }
27890
28355
  });
28356
+ }
28357
+ /** Image-to-image edit: image generation plus the source image as a second part. */
28358
+ buildEditImageRequest(req, model = req.model ?? "gemini-2.5-flash-image") {
28359
+ return this.buildGenerateContentRequest(
28360
+ model,
28361
+ req.prompt,
28362
+ this.imageGenerationConfig(req.params),
28363
+ [googleImagePart(normalizeImageSource(req.sourceImage))]
28364
+ );
28365
+ }
28366
+ async generateImage(req, fetch2) {
28367
+ const model = req.model ?? "imagen-4.0-generate-001";
28368
+ if (!model.startsWith("imagen")) {
28369
+ const { items, usage } = await this.parseGenerateContent(
28370
+ await fetch2(this.buildImageRequest(req, model))
28371
+ );
28372
+ return items.map((m, i) => ({
28373
+ data: base64ToBytes(m.data),
28374
+ mimeType: m.mimeType ?? "image/png",
28375
+ usage: i === 0 ? usage : void 0
28376
+ }));
28377
+ }
28378
+ const res = await fetch2(this.buildImagenRequest(req, model));
27891
28379
  const data = res.body;
27892
28380
  const predictions = data.predictions ?? [];
27893
28381
  return predictions.map((pred) => {
@@ -27899,17 +28387,7 @@ var GoogleMediaAdapter = class {
27899
28387
  });
27900
28388
  }
27901
28389
  async generateAudio(req, fetch2) {
27902
- const model = req.model ?? "gemini-2.5-flash-preview-tts";
27903
- const voiceName = resolveVoice("google", req.params?.voice) ?? "Kore";
27904
- const media = await this.generateContentMedia(
27905
- model,
27906
- req.input,
27907
- {
27908
- responseModalities: ["AUDIO"],
27909
- speechConfig: { voiceConfig: { prebuiltVoiceConfig: { voiceName } } }
27910
- },
27911
- fetch2
27912
- );
28390
+ const media = await this.parseGenerateContent(await fetch2(this.buildAudioRequest(req)));
27913
28391
  const first = media.items[0];
27914
28392
  if (!first) throw new Error("Google TTS: no audio returned by generateContent");
27915
28393
  const playable = ensurePlayableAudio(base64ToBytes(first.data), first.mimeType ?? "audio/wav");
@@ -27918,19 +28396,8 @@ var GoogleMediaAdapter = class {
27918
28396
  /** Image-to-image edit: gemini generateContent with the source image as an
27919
28397
  * extra inline/file part next to the instruction. */
27920
28398
  async editImage(req, fetch2) {
27921
- const model = req.model ?? "gemini-2.5-flash-image";
27922
- const generationConfig = { responseModalities: ["IMAGE"] };
27923
- const image = {};
27924
- if (req.params?.aspectRatio) image.aspectRatio = req.params.aspectRatio;
27925
- if (req.params?.imageSize) image.imageSize = req.params.imageSize;
27926
- if (Object.keys(image).length) generationConfig.imageConfig = image;
27927
- const imagePart = googleImagePart(normalizeImageSource(req.sourceImage));
27928
- const { items, usage } = await this.generateContentMedia(
27929
- model,
27930
- req.prompt,
27931
- generationConfig,
27932
- fetch2,
27933
- [imagePart]
28399
+ const { items, usage } = await this.parseGenerateContent(
28400
+ await fetch2(this.buildEditImageRequest(req))
27934
28401
  );
27935
28402
  return items.map((m, i) => ({
27936
28403
  data: base64ToBytes(m.data),
@@ -27938,18 +28405,10 @@ var GoogleMediaAdapter = class {
27938
28405
  usage: i === 0 ? usage : void 0
27939
28406
  }));
27940
28407
  }
27941
- /** Shared inline-media path: POST :generateContent and collect inlineData
27942
- * parts + the reported token usage (token-priced media). */
27943
- async generateContentMedia(model, text, generationConfig, fetch2, extraParts = []) {
27944
- const res = await fetch2({
27945
- url: `${this.baseURL}/v1beta/models/${model}:generateContent?key=${this.apiKey}`,
27946
- method: "POST",
27947
- headers: { "content-type": "application/json" },
27948
- body: { contents: [{ parts: [{ text }, ...extraParts] }], generationConfig },
27949
- provider: "google",
27950
- model,
27951
- responseType: "json"
27952
- });
28408
+ /** Collect inlineData parts + reported usage from a `:generateContent`
28409
+ * response. The request half is `buildGenerateContentRequest`; keeping the two
28410
+ * apart is what lets a request be asserted without performing it. */
28411
+ parseGenerateContent(res) {
27953
28412
  const data = res.body;
27954
28413
  const parts2 = data.candidates?.[0]?.content?.parts ?? [];
27955
28414
  const items = parts2.filter((p) => p.inlineData?.data).map((p) => ({ mimeType: p.inlineData?.mimeType, data: p.inlineData?.data }));
@@ -27957,22 +28416,7 @@ var GoogleMediaAdapter = class {
27957
28416
  }
27958
28417
  async submitVideo(req, fetch2) {
27959
28418
  const model = req.model ?? "veo-3.1-generate-preview";
27960
- const instance = { prompt: req.prompt };
27961
- if (req.sourceImage) instance.image = googleVeoImage(normalizeImageSource(req.sourceImage));
27962
- const parameters = {};
27963
- if (req.params?.duration) parameters.durationSeconds = req.params.duration;
27964
- if (req.params?.aspectRatio) parameters.aspectRatio = req.params.aspectRatio;
27965
- if (req.params?.resolution) parameters.resolution = req.params.resolution;
27966
- const body = { instances: [instance], parameters };
27967
- const res = await fetch2({
27968
- url: `${this.baseURL}/v1beta/models/${model}:predictLongRunning?key=${this.apiKey}`,
27969
- method: "POST",
27970
- headers: { "content-type": "application/json" },
27971
- body,
27972
- provider: "google",
27973
- model,
27974
- responseType: "json"
27975
- });
28419
+ const res = await fetch2(this.buildVideoRequest(req, model));
27976
28420
  const data = res.body;
27977
28421
  return data.name ?? "";
27978
28422
  }
@@ -28108,48 +28552,61 @@ var GoogleRealtimeAdapter = class {
28108
28552
  this.apiKey = config.apiKey;
28109
28553
  this.base = (config.baseURL ?? GOOGLE_WS_BASE).replace(/^http/, "ws").replace(/\/$/, "");
28110
28554
  }
28111
- connect(config, connect) {
28555
+ /** The WebSocket descriptor. Separated from `connect` so it can be asserted
28556
+ * without opening a socket. Gemini authenticates with a query-string key and
28557
+ * does NOT name the model in the URL — that goes in the setup frame. */
28558
+ buildConnectRequest(config) {
28112
28559
  const url = `${this.base}/ws/google.ai.generativelanguage.${API_VERSION}.GenerativeService.BidiGenerateContent?key=${this.apiKey}`;
28113
- const req = { url, provider: "google", model: config.model };
28114
- return new GoogleRealtimeSession(connect(req), config);
28560
+ return { url, provider: "google", model: config.model };
28561
+ }
28562
+ connect(config, connect) {
28563
+ return new GoogleRealtimeSession(connect(this.buildConnectRequest(config)), config);
28115
28564
  }
28116
28565
  };
28117
28566
  function toResponseModalities(mods) {
28118
28567
  return (mods ?? ["text"]).map((m) => m === "audio" ? "AUDIO" : "TEXT");
28119
28568
  }
28569
+ function buildGoogleSetupFrame(config) {
28570
+ const voice = config.voice;
28571
+ const setup = {
28572
+ model: config.model.startsWith("models/") ? config.model : `models/${config.model}`,
28573
+ generationConfig: {
28574
+ responseModalities: toResponseModalities(config.modalities),
28575
+ ...voice ? { speechConfig: { voiceConfig: { prebuiltVoiceConfig: { voiceName: voice } } } } : {}
28576
+ }
28577
+ };
28578
+ if (config.instructions) {
28579
+ setup.systemInstruction = { parts: [{ text: config.instructions }] };
28580
+ }
28581
+ return { setup };
28582
+ }
28583
+ function buildGoogleTurnFrames(input, opts) {
28584
+ const parts2 = [];
28585
+ if (input.text != null) parts2.push({ text: input.text });
28586
+ if (input.audio) {
28587
+ parts2.push({ inlineData: { mimeType: "audio/pcm", data: bytesToBase64(input.audio) } });
28588
+ }
28589
+ return [
28590
+ {
28591
+ clientContent: {
28592
+ turns: [{ role: "user", parts: parts2 }],
28593
+ turnComplete: opts?.turnComplete !== false
28594
+ }
28595
+ }
28596
+ ];
28597
+ }
28120
28598
  var GoogleRealtimeSession = class extends BaseRealtimeSession {
28121
28599
  setupFrame;
28122
28600
  constructor(conn, config) {
28123
28601
  super(conn);
28124
- const voice = config.voice;
28125
- const setup = {
28126
- model: config.model.startsWith("models/") ? config.model : `models/${config.model}`,
28127
- generationConfig: {
28128
- responseModalities: toResponseModalities(config.modalities),
28129
- ...voice ? { speechConfig: { voiceConfig: { prebuiltVoiceConfig: { voiceName: voice } } } } : {}
28130
- }
28131
- };
28132
- if (config.instructions) {
28133
- setup.systemInstruction = { parts: [{ text: config.instructions }] };
28134
- }
28135
- this.setupFrame = { setup };
28602
+ this.setupFrame = buildGoogleSetupFrame(config);
28136
28603
  }
28137
28604
  onOpen() {
28138
28605
  this.sendJSON(this.setupFrame);
28139
28606
  }
28140
28607
  send(input, opts) {
28141
28608
  this.whenReady(() => {
28142
- const parts2 = [];
28143
- if (input.text != null) parts2.push({ text: input.text });
28144
- if (input.audio) {
28145
- parts2.push({ inlineData: { mimeType: "audio/pcm", data: bytesToBase64(input.audio) } });
28146
- }
28147
- this.sendJSON({
28148
- clientContent: {
28149
- turns: [{ role: "user", parts: parts2 }],
28150
- turnComplete: opts?.turnComplete !== false
28151
- }
28152
- });
28609
+ for (const frame of buildGoogleTurnFrames(input, opts)) this.sendJSON(frame);
28153
28610
  });
28154
28611
  }
28155
28612
  onFrame(frame) {
@@ -28642,7 +29099,7 @@ var OpenAIAdapter = class {
28642
29099
  };
28643
29100
  }
28644
29101
  parseStreamEvent(event, state) {
28645
- const data = JSON.parse(event.data);
29102
+ const data = sseJson(event);
28646
29103
  if (data.moderation) {
28647
29104
  const report = parseNativeModeration(data.moderation);
28648
29105
  const out = [];
@@ -28844,8 +29301,14 @@ var OpenAIMediaAdapter = class {
28844
29301
  authHeaders() {
28845
29302
  return { authorization: `Bearer ${this.apiKey}`, "content-type": "application/json" };
28846
29303
  }
28847
- async generateImage(req, fetch2) {
28848
- const model = req.model ?? "gpt-image-1";
29304
+ // ─── request builders ──────────────────────────────────────────────────
29305
+ //
29306
+ // Separated from the methods that fetch and parse, so a request can be built
29307
+ // and asserted without performing it. Every method below used to assemble its
29308
+ // request inline, which meant the only way to see what the adapter would send
29309
+ // was to intercept the network.
29310
+ /** Text-to-image. */
29311
+ buildGenerateImageRequest(req, model = req.model ?? "gpt-image-1") {
28849
29312
  const body = {
28850
29313
  model,
28851
29314
  prompt: req.prompt,
@@ -28859,7 +29322,7 @@ var OpenAIMediaAdapter = class {
28859
29322
  if (req.params?.style) body.style = req.params.style;
28860
29323
  if (req.params?.background) body.background = req.params.background;
28861
29324
  if (req.params?.outputFormat) body.output_format = req.params.outputFormat;
28862
- const res = await fetch2({
29325
+ return {
28863
29326
  url: `${this.baseURL}/v1/images/generations`,
28864
29327
  method: "POST",
28865
29328
  headers: this.authHeaders(),
@@ -28867,25 +29330,11 @@ var OpenAIMediaAdapter = class {
28867
29330
  provider: "openai",
28868
29331
  model,
28869
29332
  responseType: "json"
28870
- });
28871
- return this.parseImages(res.body);
28872
- }
28873
- /** Parse `/v1/images/{generations,edits}` response → RawMediaResult[], with
28874
- * the request-level usage attached to the first item (billed once). */
28875
- parseImages(data) {
28876
- const items = data.data ?? [];
28877
- const usage = mapOpenAIImageUsage(data.usage);
28878
- return items.map((item, i) => ({
28879
- data: base64ToBytes(item.b64_json ?? ""),
28880
- mimeType: "image/png",
28881
- revisedPrompt: item.revised_prompt,
28882
- usage: i === 0 ? usage : void 0
28883
- }));
29333
+ };
28884
29334
  }
28885
- /** Image-to-image edit via `/v1/images/edits` (JSON, base64 data-URL or
28886
- * file_id references). */
28887
- async editImage(req, fetch2) {
28888
- const model = req.model ?? "gpt-image-1";
29335
+ /** Image-to-image edit. Generation's field set minus `style`, plus the source
29336
+ * image and an optional mask. */
29337
+ buildEditImageRequest(req, model = req.model ?? "gpt-image-1") {
28889
29338
  const body = {
28890
29339
  model,
28891
29340
  prompt: req.prompt,
@@ -28897,7 +29346,7 @@ var OpenAIMediaAdapter = class {
28897
29346
  if (req.params?.quality) body.quality = req.params.quality;
28898
29347
  if (req.params?.background) body.background = req.params.background;
28899
29348
  if (req.params?.outputFormat) body.output_format = req.params.outputFormat;
28900
- const res = await fetch2({
29349
+ return {
28901
29350
  url: `${this.baseURL}/v1/images/edits`,
28902
29351
  method: "POST",
28903
29352
  headers: this.authHeaders(),
@@ -28905,12 +29354,10 @@ var OpenAIMediaAdapter = class {
28905
29354
  provider: "openai",
28906
29355
  model,
28907
29356
  responseType: "json"
28908
- });
28909
- return this.parseImages(res.body);
29357
+ };
28910
29358
  }
28911
- async generateAudio(req, fetch2) {
28912
- const model = req.model;
28913
- if (!model) throw new Error('OpenAI TTS requires a model (e.g. "tts-1", "gpt-4o-mini-tts")');
29359
+ /** TTS. `responseType` is arraybuffer because the response is audio bytes. */
29360
+ buildAudioRequest(req, model) {
28914
29361
  const body = {
28915
29362
  model,
28916
29363
  input: req.input,
@@ -28919,7 +29366,7 @@ var OpenAIMediaAdapter = class {
28919
29366
  if (req.params?.format) body.response_format = req.params.format;
28920
29367
  if (req.params?.speed) body.speed = req.params.speed;
28921
29368
  if (req.params?.instructions) body.instructions = req.params.instructions;
28922
- const res = await fetch2({
29369
+ return {
28923
29370
  url: `${this.baseURL}/v1/audio/speech`,
28924
29371
  method: "POST",
28925
29372
  headers: this.authHeaders(),
@@ -28927,29 +29374,17 @@ var OpenAIMediaAdapter = class {
28927
29374
  provider: "openai",
28928
29375
  model,
28929
29376
  responseType: "arraybuffer"
28930
- });
28931
- const buffer = res.body;
28932
- const format = req.params?.format ?? "mp3";
28933
- const mimeMap = {
28934
- mp3: "audio/mp3",
28935
- wav: "audio/wav",
28936
- pcm: "audio/pcm",
28937
- opus: "audio/opus",
28938
- aac: "audio/aac",
28939
- flac: "audio/flac"
28940
29377
  };
28941
- return { data: buffer, mimeType: mimeMap[format] ?? "audio/mp3" };
28942
29378
  }
28943
- // ─── Sora video (async: create poll download) ──────────────────────
28944
- async submitVideo(req, fetch2) {
28945
- const model = req.model ?? "sora-2";
29379
+ /** Sora video submission. `seconds` goes on the wire as a string. */
29380
+ buildVideoRequest(req, model = req.model ?? "sora-2") {
28946
29381
  const body = { model, prompt: req.prompt };
28947
29382
  if (req.params?.duration) body.seconds = String(req.params.duration);
28948
29383
  if (req.params?.size) body.size = req.params.size;
28949
29384
  if (req.sourceImage) {
28950
29385
  body.input_reference = openaiImageRef(normalizeImageSource(req.sourceImage));
28951
29386
  }
28952
- const res = await fetch2({
29387
+ return {
28953
29388
  url: `${this.baseURL}/v1/videos`,
28954
29389
  method: "POST",
28955
29390
  headers: this.authHeaders(),
@@ -28957,7 +29392,49 @@ var OpenAIMediaAdapter = class {
28957
29392
  provider: "openai",
28958
29393
  model,
28959
29394
  responseType: "json"
28960
- });
29395
+ };
29396
+ }
29397
+ async generateImage(req, fetch2) {
29398
+ const res = await fetch2(this.buildGenerateImageRequest(req));
29399
+ return this.parseImages(res.body);
29400
+ }
29401
+ /** Parse `/v1/images/{generations,edits}` response → RawMediaResult[], with
29402
+ * the request-level usage attached to the first item (billed once). */
29403
+ parseImages(data) {
29404
+ const items = data.data ?? [];
29405
+ const usage = mapOpenAIImageUsage(data.usage);
29406
+ return items.map((item, i) => ({
29407
+ data: base64ToBytes(item.b64_json ?? ""),
29408
+ mimeType: "image/png",
29409
+ revisedPrompt: item.revised_prompt,
29410
+ usage: i === 0 ? usage : void 0
29411
+ }));
29412
+ }
29413
+ /** Image-to-image edit via `/v1/images/edits` (JSON, base64 data-URL or
29414
+ * file_id references). */
29415
+ async editImage(req, fetch2) {
29416
+ const res = await fetch2(this.buildEditImageRequest(req));
29417
+ return this.parseImages(res.body);
29418
+ }
29419
+ async generateAudio(req, fetch2) {
29420
+ const model = req.model;
29421
+ if (!model) throw new Error('OpenAI TTS requires a model (e.g. "tts-1", "gpt-4o-mini-tts")');
29422
+ const res = await fetch2(this.buildAudioRequest(req, model));
29423
+ const buffer = res.body;
29424
+ const format = req.params?.format ?? "mp3";
29425
+ const mimeMap = {
29426
+ mp3: "audio/mp3",
29427
+ wav: "audio/wav",
29428
+ pcm: "audio/pcm",
29429
+ opus: "audio/opus",
29430
+ aac: "audio/aac",
29431
+ flac: "audio/flac"
29432
+ };
29433
+ return { data: buffer, mimeType: mimeMap[format] ?? "audio/mp3" };
29434
+ }
29435
+ // ─── Sora video (async: create → poll → download) ──────────────────────
29436
+ async submitVideo(req, fetch2) {
29437
+ const res = await fetch2(this.buildVideoRequest(req));
28961
29438
  const data = res.body;
28962
29439
  return data.id ?? "";
28963
29440
  }
@@ -29129,19 +29606,44 @@ var OpenAIRealtimeAdapter = class {
29129
29606
  this.apiKey = config.apiKey;
29130
29607
  this.baseURL = config.baseURL ?? "https://api.openai.com";
29131
29608
  }
29132
- connect(config, connect) {
29609
+ /** The WebSocket descriptor. Separated from `connect` so it can be asserted
29610
+ * without opening a socket. Note the auth: OpenAI carries the key in a
29611
+ * SUBPROTOCOL, not a header or query param, because browsers cannot set
29612
+ * WebSocket headers. */
29613
+ buildConnectRequest(config) {
29133
29614
  const url = new URL(`${this.baseURL.replace(/\/$/, "")}/v1/realtime`);
29134
29615
  url.protocol = "wss";
29135
29616
  url.searchParams.set("model", config.model);
29136
- const req = {
29617
+ return {
29137
29618
  url: url.toString(),
29138
29619
  protocols: ["realtime", `openai-insecure-api-key.${this.apiKey}`],
29139
29620
  provider: "openai",
29140
29621
  model: config.model
29141
29622
  };
29142
- return new OpenAIRealtimeSession(connect(req), config);
29623
+ }
29624
+ connect(config, connect) {
29625
+ return new OpenAIRealtimeSession(connect(this.buildConnectRequest(config)), config);
29143
29626
  }
29144
29627
  };
29628
+ function buildOpenAISessionUpdate(config) {
29629
+ const session = {
29630
+ type: "realtime",
29631
+ output_modalities: config.modalities ?? ["text"]
29632
+ };
29633
+ if (config.instructions) session.instructions = config.instructions;
29634
+ if (config.voice) session.audio = { output: { voice: config.voice } };
29635
+ return { type: "session.update", session };
29636
+ }
29637
+ function buildOpenAITurnFrames(input, opts) {
29638
+ const content = [];
29639
+ if (input.text != null) content.push({ type: "input_text", text: input.text });
29640
+ if (input.audio) content.push({ type: "input_audio", audio: bytesToBase64(input.audio) });
29641
+ const frames = [
29642
+ { type: "conversation.item.create", item: { type: "message", role: "user", content } }
29643
+ ];
29644
+ if (opts?.turnComplete !== false) frames.push({ type: "response.create" });
29645
+ return frames;
29646
+ }
29145
29647
  var OpenAIRealtimeSession = class extends BaseRealtimeSession {
29146
29648
  modalities;
29147
29649
  instructions;
@@ -29153,25 +29655,18 @@ var OpenAIRealtimeSession = class extends BaseRealtimeSession {
29153
29655
  this.voice = config.voice;
29154
29656
  }
29155
29657
  onOpen() {
29156
- const session = {
29157
- type: "realtime",
29158
- output_modalities: this.modalities
29159
- };
29160
- if (this.instructions) session.instructions = this.instructions;
29161
- if (this.voice) session.audio = { output: { voice: this.voice } };
29162
- this.sendJSON({ type: "session.update", session });
29658
+ this.sendJSON(
29659
+ buildOpenAISessionUpdate({
29660
+ modalities: this.modalities,
29661
+ instructions: this.instructions,
29662
+ voice: this.voice
29663
+ })
29664
+ );
29163
29665
  this.markReady();
29164
29666
  }
29165
29667
  send(input, opts) {
29166
29668
  this.whenReady(() => {
29167
- const content = [];
29168
- if (input.text != null) content.push({ type: "input_text", text: input.text });
29169
- if (input.audio) content.push({ type: "input_audio", audio: bytesToBase64(input.audio) });
29170
- this.sendJSON({
29171
- type: "conversation.item.create",
29172
- item: { type: "message", role: "user", content }
29173
- });
29174
- if (opts?.turnComplete !== false) this.sendJSON({ type: "response.create" });
29669
+ for (const frame of buildOpenAITurnFrames(input, opts)) this.sendJSON(frame);
29175
29670
  });
29176
29671
  }
29177
29672
  onFrame(frame) {
@@ -29681,7 +30176,7 @@ var OpenAIResponsesAdapter = class {
29681
30176
  };
29682
30177
  }
29683
30178
  parseStreamEvent(event, phaseByItem) {
29684
- const data = JSON.parse(event.data);
30179
+ const data = sseJson(event);
29685
30180
  const type = data.type;
29686
30181
  const events = [];
29687
30182
  if (type === "response.output_text.delta") {
@@ -29964,7 +30459,24 @@ var OpenRouterResponsesAdapter = class extends OpenAIResponsesAdapter {
29964
30459
  }
29965
30460
  };
29966
30461
 
30462
+ // src/util/hash.ts
30463
+ function fnv1a322(input) {
30464
+ let h = 2166136261;
30465
+ for (let i = 0; i < input.length; i++) {
30466
+ h ^= input.charCodeAt(i);
30467
+ h = Math.imul(h, 16777619) >>> 0;
30468
+ }
30469
+ return h >>> 0;
30470
+ }
30471
+ function fnv1a32Hex(input) {
30472
+ return fnv1a322(input).toString(16).padStart(8, "0");
30473
+ }
30474
+
29967
30475
  // src/llm/providers/xai/batch.ts
30476
+ function batchName(requests) {
30477
+ const digest = fnv1a32Hex(requests.map((r) => r.customId).join("\0"));
30478
+ return `batch_${requests.length}_${digest}`;
30479
+ }
29968
30480
  var XAIBatchAdapter = class {
29969
30481
  name = "xai";
29970
30482
  apiKey;
@@ -29981,7 +30493,7 @@ var XAIBatchAdapter = class {
29981
30493
  url: `${this.baseURL}/v1/batches`,
29982
30494
  method: "POST",
29983
30495
  headers: { ...this.bearer(), "content-type": "application/json" },
29984
- body: { name: `batch_${Date.now()}` },
30496
+ body: { name: batchName(requests) },
29985
30497
  provider: "xai",
29986
30498
  model: "batch",
29987
30499
  responseType: "json"
@@ -30100,7 +30612,7 @@ var XAIAdapter = class extends OpenAIAdapter {
30100
30612
  parseStreamEvent(event, state) {
30101
30613
  const events = super.parseStreamEvent(event, state);
30102
30614
  try {
30103
- const data = JSON.parse(event.data);
30615
+ const data = sseJson(event);
30104
30616
  const choices = data.choices ?? [];
30105
30617
  const delta = choices[0]?.delta ?? {};
30106
30618
  if (delta.reasoning_content) {
@@ -32012,6 +32524,123 @@ var AgentLoop = class _AgentLoop {
32012
32524
  this._stopRequested = true;
32013
32525
  this._abortController?.abort();
32014
32526
  }
32527
+ // ─── shared run scaffolding ─────────────────────────────────────────────
32528
+ //
32529
+ // `complete()` and `stream()` are the same loop with different plumbing, and
32530
+ // they had drifted into near-duplicates: 167 identical lines across ~560. The
32531
+ // three pieces below are what was copied verbatim — how a run's error is
32532
+ // recorded, how its final text is decided, and how its final response is
32533
+ // shaped. Sharing them means a fix to one path cannot silently miss the other.
32534
+ /** Record a thrown error onto the run: emit `onRunError` and return the parts
32535
+ * the caller assigns. Both paths report `phase: 'llm_call'`. */
32536
+ async recordRunError(e, args) {
32537
+ await this.hooks.emit("onRunError", {
32538
+ runId: args.runId,
32539
+ agentId: this.id,
32540
+ step: args.stepCount,
32541
+ error: e instanceof Error ? e : new Error(String(e)),
32542
+ phase: "llm_call",
32543
+ trace: args.runTrace
32544
+ });
32545
+ return { errorMsg: e instanceof Error ? e.message : String(e), caughtError: e };
32546
+ }
32547
+ /** The run's final text.
32548
+ *
32549
+ * `finalAnswerText` strips `phase: 'commentary'` parts: a codex-family model
32550
+ * narrates before it answers and `response.text` concatenates both, so an
32551
+ * agent's final output used to include its own thinking-out-loud. Falls back
32552
+ * to `.text` when the content carries no text parts, and is identical to
32553
+ * `.text` for every model that reports no phase.
32554
+ *
32555
+ * The streaming path passes what it accumulated; the non-streaming path lets
32556
+ * the last response decide. Both share the guardrail / max-steps overrides. */
32557
+ resolveFinalText(args) {
32558
+ if (args.reason === "guardrail") return args.guardrailTripReason ?? "";
32559
+ if (args.reason === "max_steps") return `stopped: reached maxSteps (${this._maxSteps})`;
32560
+ if (args.streamedText !== void 0) return args.streamedText;
32561
+ const last = args.lastResponse;
32562
+ return last ? finalAnswerText(last.content ?? []) || (last.text ?? "") : "";
32563
+ }
32564
+ /** Compose the run's CompletionResponse. `media` and `raw` are parameters
32565
+ * because the two paths genuinely differ: the streaming path has already
32566
+ * emitted media as events and never holds a raw provider payload. */
32567
+ buildFinalResponse(args) {
32568
+ const last = args.lastResponse;
32569
+ const reason = args.reason;
32570
+ return {
32571
+ id: last?.id ?? `agent-${args.runId}`,
32572
+ model: this.client.model,
32573
+ content: args.finalContent,
32574
+ finishReason: reason === "done" ? (
32575
+ // Ended because the model requested no tools — surface the provider's
32576
+ // actual reason (stop / content_filter / length), not a flat 'stop'.
32577
+ last?.finishReason ?? "stop"
32578
+ ) : reason === "stopped" ? "stop" : reason === "guardrail" ? "stop" : reason === "max_steps" ? "length" : "error",
32579
+ usage: args.totalUsage,
32580
+ text: args.finalText,
32581
+ toolCalls: last?.toolCalls ?? [],
32582
+ thinking: last?.thinking ?? null,
32583
+ media: args.media,
32584
+ // Propagate hosted-tool file outputs + inline-moderation result from the
32585
+ // final LLM response (e.g. code-execution files produced during the run).
32586
+ ...last?.files ? { files: last.files } : {},
32587
+ ...last?.builtinToolCalls ? { builtinToolCalls: last.builtinToolCalls } : {},
32588
+ ...last?.moderation ? { moderation: last.moderation } : {},
32589
+ latencyMs: performance.now() - args.startPerf,
32590
+ raw: args.raw
32591
+ };
32592
+ }
32593
+ /** Close out a run: write the report, then surface a failure.
32594
+ *
32595
+ * The order matters and is the reason this is one function rather than two
32596
+ * calls at each site — a failed run must still emit its metrics and hooks
32597
+ * before the error propagates, or a crash silently loses the run's telemetry.
32598
+ * A failed run throws rather than returning empty text, matching the raw
32599
+ * client. */
32600
+ async settleRun(args) {
32601
+ await this.finalizeRun(args);
32602
+ if (args.reason === "error") {
32603
+ throw args.caughtError ?? new Error(args.error ?? "agent run failed");
32604
+ }
32605
+ }
32606
+ /** Per-step options for the underlying LLM call: loop defaults, then the
32607
+ * caller's overrides, then the run's trace.
32608
+ *
32609
+ * `complete()` and `stream()` duplicated this verbatim, differing only in the
32610
+ * name of the local holding the composed system prompt. That is a bad place
32611
+ * for a copy: the ctx block below is what stops one conversation arriving at
32612
+ * the collector as several unrelated traces, and a fix applied to one path
32613
+ * would have left the other silently splitting. */
32614
+ buildStepOptions(options, composedSystem, runTrace) {
32615
+ return {
32616
+ ...options,
32617
+ system: composedSystem,
32618
+ history: options.history ?? this._history,
32619
+ maxTokens: options.maxTokens ?? this._maxTokens,
32620
+ temperature: options.temperature ?? this._temperature,
32621
+ thinking: options.thinking ?? this._thinking,
32622
+ cache: options.cache ?? this._cache,
32623
+ tools: this.toolDefinitions(options),
32624
+ ctx: {
32625
+ // The RUN's trace, handed down to every LLM call it makes.
32626
+ //
32627
+ // Without this the agent kept `runTrace` to itself: its own spans used it
32628
+ // while each `client.complete()` fell through to mint-if-absent and
32629
+ // invented a fresh `requestId`. Since the trace id is `sessionId:requestId`,
32630
+ // one conversation arrived at the backend as SEVERAL unrelated traces —
32631
+ // measured against a real collector: a single turn with one tool call
32632
+ // produced six. Correlation is the whole point of a trace id, so this is
32633
+ // the one thing it must not get wrong.
32634
+ ...runTrace,
32635
+ conversationId: this._history.id,
32636
+ // A caller's explicit ctx wins over all of the above: an app that already
32637
+ // owns a request id or a conversation id has better information than we do,
32638
+ // and silently overwriting it is how its telemetry stops joining up.
32639
+ ...options.ctx
32640
+ },
32641
+ signal: options.signal ?? this._abortController?.signal
32642
+ };
32643
+ }
32015
32644
  // ─── complete (non-streaming) ───────────────────────────────────────────
32016
32645
  async complete(input, options = {}) {
32017
32646
  const { runId, startedAt, startPerf, userMessageText, runTrace } = await this.beginRun(input, options.ctx);
@@ -32058,32 +32687,7 @@ var AgentLoop = class _AgentLoop {
32058
32687
  break;
32059
32688
  }
32060
32689
  lastResponse = await this.client.complete(this._history.messages(), {
32061
- ...options,
32062
- system: composedSystemStr,
32063
- history: options.history ?? this._history,
32064
- maxTokens: options.maxTokens ?? this._maxTokens,
32065
- temperature: options.temperature ?? this._temperature,
32066
- thinking: options.thinking ?? this._thinking,
32067
- cache: options.cache ?? this._cache,
32068
- tools: this.toolDefinitions(options),
32069
- ctx: {
32070
- // The RUN's trace, handed down to every LLM call it makes.
32071
- //
32072
- // Without this the agent kept `runTrace` to itself: its own spans used it
32073
- // while each `client.complete()` fell through to mint-if-absent and
32074
- // invented a fresh `requestId`. Since the trace id is `sessionId:requestId`,
32075
- // one conversation arrived at the backend as SEVERAL unrelated traces —
32076
- // measured against a real collector: a single turn with one tool call
32077
- // produced six. Correlation is the whole point of a trace id, so this is
32078
- // the one thing it must not get wrong.
32079
- ...runTrace,
32080
- conversationId: this._history.id,
32081
- // A caller's explicit ctx wins over all of the above: an app that already
32082
- // owns a request id or a conversation id has better information than we do,
32083
- // and silently overwriting it is how its telemetry stops joining up.
32084
- ...options.ctx
32085
- },
32086
- signal: options.signal ?? this._abortController?.signal
32690
+ ...this.buildStepOptions(options, composedSystemStr, runTrace)
32087
32691
  });
32088
32692
  const stepLatency = performance.now() - stepStart;
32089
32693
  totalLlmTimeMs += stepLatency;
@@ -32179,45 +32783,25 @@ var AgentLoop = class _AgentLoop {
32179
32783
  }
32180
32784
  } catch (e) {
32181
32785
  reason = "error";
32182
- errorMsg = e instanceof Error ? e.message : String(e);
32183
- caughtError = e;
32184
- await this.hooks.emit("onRunError", {
32185
- runId,
32186
- agentId: this.id,
32187
- step: stepCount,
32188
- error: e instanceof Error ? e : new Error(String(e)),
32189
- phase: "llm_call",
32190
- trace: runTrace
32191
- });
32786
+ ({ errorMsg, caughtError } = await this.recordRunError(e, { runId, stepCount, runTrace }));
32192
32787
  } finally {
32193
32788
  this._running = false;
32194
32789
  this._abortController = null;
32195
32790
  }
32196
- const finalText = reason === "guardrail" ? guardrailTripReason ?? "" : reason === "max_steps" ? `stopped: reached maxSteps (${this._maxSteps})` : lastResponse ? finalAnswerText(lastResponse.content ?? []) || (lastResponse.text ?? "") : "";
32791
+ const finalText = this.resolveFinalText({ reason, guardrailTripReason, lastResponse });
32197
32792
  const finalContent = lastResponse?.content ?? [];
32198
- const finalResponse = {
32199
- id: lastResponse?.id ?? `agent-${runId}`,
32200
- model: this.client.model,
32201
- content: finalContent,
32202
- finishReason: reason === "done" ? (
32203
- // Ended because the model requested no tools — surface the provider's
32204
- // actual reason (stop / content_filter / length), not a flat 'stop'.
32205
- lastResponse?.finishReason ?? "stop"
32206
- ) : reason === "stopped" ? "stop" : reason === "guardrail" ? "stop" : reason === "max_steps" ? "length" : "error",
32207
- usage: totalUsage,
32208
- text: finalText,
32209
- toolCalls: lastResponse?.toolCalls ?? [],
32210
- thinking: lastResponse?.thinking ?? null,
32793
+ const finalResponse = this.buildFinalResponse({
32794
+ runId,
32795
+ startPerf,
32796
+ reason,
32797
+ finalText,
32798
+ finalContent,
32799
+ totalUsage,
32800
+ lastResponse,
32211
32801
  media: lastResponse?.media ?? [],
32212
- // Propagate hosted-tool file outputs + inline-moderation result from the final
32213
- // LLM response (e.g. code-execution files produced during the run).
32214
- ...lastResponse?.files ? { files: lastResponse.files } : {},
32215
- ...lastResponse?.builtinToolCalls ? { builtinToolCalls: lastResponse.builtinToolCalls } : {},
32216
- ...lastResponse?.moderation ? { moderation: lastResponse.moderation } : {},
32217
- latencyMs: performance.now() - startPerf,
32218
32802
  raw: lastResponse?.raw ?? null
32219
- };
32220
- await this.finalizeRun({
32803
+ });
32804
+ await this.settleRun({
32221
32805
  runId,
32222
32806
  startedAt,
32223
32807
  startPerf,
@@ -32226,6 +32810,7 @@ var AgentLoop = class _AgentLoop {
32226
32810
  finalText,
32227
32811
  reason,
32228
32812
  error: errorMsg,
32813
+ caughtError,
32229
32814
  response: finalResponse,
32230
32815
  steps,
32231
32816
  stepCount,
@@ -32235,7 +32820,6 @@ var AgentLoop = class _AgentLoop {
32235
32820
  totalToolTimeMs,
32236
32821
  runTrace
32237
32822
  });
32238
- if (reason === "error") throw caughtError ?? new Error(errorMsg ?? "agent run failed");
32239
32823
  return finalResponse;
32240
32824
  }
32241
32825
  /** Run `complete` with a JSON Schema enforced via `structured`, then
@@ -32298,32 +32882,7 @@ var AgentLoop = class _AgentLoop {
32298
32882
  break;
32299
32883
  }
32300
32884
  for await (const event of this.client.stream(this._history.messages(), {
32301
- ...options,
32302
- system: composedSystemForStream,
32303
- history: options.history ?? this._history,
32304
- maxTokens: options.maxTokens ?? this._maxTokens,
32305
- temperature: options.temperature ?? this._temperature,
32306
- thinking: options.thinking ?? this._thinking,
32307
- cache: options.cache ?? this._cache,
32308
- tools: this.toolDefinitions(options),
32309
- ctx: {
32310
- // The RUN's trace, handed down to every LLM call it makes.
32311
- //
32312
- // Without this the agent kept `runTrace` to itself: its own spans used it
32313
- // while each `client.complete()` fell through to mint-if-absent and
32314
- // invented a fresh `requestId`. Since the trace id is `sessionId:requestId`,
32315
- // one conversation arrived at the backend as SEVERAL unrelated traces —
32316
- // measured against a real collector: a single turn with one tool call
32317
- // produced six. Correlation is the whole point of a trace id, so this is
32318
- // the one thing it must not get wrong.
32319
- ...runTrace,
32320
- conversationId: this._history.id,
32321
- // A caller's explicit ctx wins over all of the above: an app that already
32322
- // owns a request id or a conversation id has better information than we do,
32323
- // and silently overwriting it is how its telemetry stops joining up.
32324
- ...options.ctx
32325
- },
32326
- signal: options.signal ?? this._abortController?.signal
32885
+ ...this.buildStepOptions(options, composedSystemForStream, runTrace)
32327
32886
  })) {
32328
32887
  const toYield = accumulateStreamEvent(event, state);
32329
32888
  if (toYield) yield toYield;
@@ -32408,43 +32967,26 @@ var AgentLoop = class _AgentLoop {
32408
32967
  }
32409
32968
  } catch (e) {
32410
32969
  reason = "error";
32411
- errorMsg = e instanceof Error ? e.message : String(e);
32412
- caughtError = e;
32413
- await this.hooks.emit("onRunError", {
32414
- runId,
32415
- agentId: this.id,
32416
- step: stepCount,
32417
- error: e instanceof Error ? e : new Error(String(e)),
32418
- phase: "llm_call",
32419
- trace: runTrace
32420
- });
32970
+ ({ errorMsg, caughtError } = await this.recordRunError(e, { runId, stepCount, runTrace }));
32421
32971
  } finally {
32422
32972
  this._running = false;
32423
32973
  this._abortController = null;
32424
32974
  }
32425
- if (reason === "guardrail") finalText = guardrailTripReason ?? "";
32426
- if (reason === "max_steps") finalText = `stopped: reached maxSteps (${this._maxSteps})`;
32427
- const finalResponse = {
32428
- id: lastResponse?.id ?? `agent-${runId}`,
32429
- model: this.client.model,
32430
- content: finalContent,
32431
- finishReason: reason === "done" ? (
32432
- // Ended because the model requested no tools — surface the provider's
32433
- // actual reason (stop / content_filter / length), not a flat 'stop'.
32434
- lastResponse?.finishReason ?? "stop"
32435
- ) : reason === "stopped" ? "stop" : reason === "guardrail" ? "stop" : reason === "max_steps" ? "length" : "error",
32436
- usage: totalUsage,
32437
- text: finalText,
32438
- toolCalls: lastResponse?.toolCalls ?? [],
32439
- thinking: lastResponse?.thinking ?? null,
32975
+ finalText = this.resolveFinalText({ reason, guardrailTripReason, streamedText: finalText });
32976
+ const finalResponse = this.buildFinalResponse({
32977
+ runId,
32978
+ startPerf,
32979
+ reason,
32980
+ finalText,
32981
+ finalContent,
32982
+ totalUsage,
32983
+ lastResponse,
32984
+ // The streaming path already emitted media as events, and never holds a
32985
+ // raw provider payload.
32440
32986
  media: [],
32441
- ...lastResponse?.files ? { files: lastResponse.files } : {},
32442
- ...lastResponse?.builtinToolCalls ? { builtinToolCalls: lastResponse.builtinToolCalls } : {},
32443
- ...lastResponse?.moderation ? { moderation: lastResponse.moderation } : {},
32444
- latencyMs: performance.now() - startPerf,
32445
32987
  raw: null
32446
- };
32447
- await this.finalizeRun({
32988
+ });
32989
+ await this.settleRun({
32448
32990
  runId,
32449
32991
  startedAt,
32450
32992
  startPerf,
@@ -32453,6 +32995,7 @@ var AgentLoop = class _AgentLoop {
32453
32995
  finalText,
32454
32996
  reason,
32455
32997
  error: errorMsg,
32998
+ caughtError,
32456
32999
  response: finalResponse,
32457
33000
  steps,
32458
33001
  stepCount,
@@ -32462,7 +33005,6 @@ var AgentLoop = class _AgentLoop {
32462
33005
  totalToolTimeMs,
32463
33006
  runTrace
32464
33007
  });
32465
- if (reason === "error") throw caughtError ?? new Error(errorMsg ?? "agent run failed");
32466
33008
  yield { type: "done", response: finalResponse };
32467
33009
  }
32468
33010
  /** Yield tool_call_start events for all tool calls in this step. */
@@ -34882,286 +35424,6 @@ var HybridTokenCounter = class {
34882
35424
  }
34883
35425
  };
34884
35426
 
34885
- // src/helpers/client-pool.ts
34886
- var ClientPool = class {
34887
- constructor(catalog) {
34888
- this.catalog = catalog;
34889
- }
34890
- catalog;
34891
- clients = /* @__PURE__ */ new Map();
34892
- get(provider, model, config) {
34893
- const key = this.keyFor(provider, model);
34894
- let client = this.clients.get(key);
34895
- if (!client) {
34896
- client = new LLMClient({ ...config, model });
34897
- this.clients.set(key, client);
34898
- }
34899
- return client;
34900
- }
34901
- async destroy() {
34902
- for (const [, client] of this.clients) {
34903
- client.destroy();
34904
- }
34905
- this.clients.clear();
34906
- }
34907
- get size() {
34908
- return this.clients.size;
34909
- }
34910
- keyFor(provider, model) {
34911
- const info = this.catalog?.get(provider, model);
34912
- if (info?.requiresDedicatedClient) {
34913
- return `${provider}/${model}`;
34914
- }
34915
- return provider;
34916
- }
34917
- };
34918
-
34919
- // src/helpers/client-resolver.ts
34920
- function directFetch() {
34921
- return async (req) => {
34922
- const init = {
34923
- method: req.method ?? "POST",
34924
- headers: req.headers,
34925
- body: typeof req.body === "string" ? req.body : JSON.stringify(req.body)
34926
- };
34927
- if (req.signal) init.signal = req.signal;
34928
- const res = await globalThis.fetch(req.url, init);
34929
- const headers = {};
34930
- res.headers.forEach((v, k) => {
34931
- headers[k] = v;
34932
- });
34933
- const body = await res.json().catch(() => null);
34934
- return { status: res.status, headers, body };
34935
- };
34936
- }
34937
- var ClientResolver = class {
34938
- constructor(cfg) {
34939
- this.cfg = cfg;
34940
- this.pool = new ClientPool(cfg.catalog);
34941
- }
34942
- cfg;
34943
- pool;
34944
- /** Turn `"anthropic/claude-haiku-4-5"` → resolved client. */
34945
- resolve(modelId) {
34946
- const [provider, model] = parseModelId(modelId);
34947
- const apiKey = this.cfg.apiKeys[provider];
34948
- if (!apiKey) {
34949
- const known = Object.keys(this.cfg.apiKeys).filter(
34950
- (k) => !!this.cfg.apiKeys[k]
34951
- );
34952
- throw new Error(
34953
- `ClientResolver: no API key for provider "${provider}". Configured providers: [${known.join(", ") || "none"}]`
34954
- );
34955
- }
34956
- const fetchFn = this.cfg.fetch ?? directFetch();
34957
- const client = this.pool.get(provider, model, {
34958
- provider,
34959
- apiKey,
34960
- hooks: this.cfg.hooks,
34961
- model,
34962
- fetch: fetchFn,
34963
- fetchStream: this.cfg.fetchStream,
34964
- ...this.cfg.clientOptions
34965
- });
34966
- return { client, provider, model };
34967
- }
34968
- availableProviders() {
34969
- return Object.keys(this.cfg.apiKeys).filter((p) => !!this.cfg.apiKeys[p]);
34970
- }
34971
- async destroy() {
34972
- await this.pool.destroy();
34973
- }
34974
- get size() {
34975
- return this.pool.size;
34976
- }
34977
- };
34978
- function parseModelId(modelId) {
34979
- const slash = modelId.indexOf("/");
34980
- if (slash <= 0 || slash === modelId.length - 1) {
34981
- throw new Error(`Invalid model id "${modelId}" \u2014 expected format "provider/model"`);
34982
- }
34983
- const provider = modelId.slice(0, slash);
34984
- const model = modelId.slice(slash + 1);
34985
- return [provider, model];
34986
- }
34987
- function isNamespacedModelId(modelId) {
34988
- const slash = modelId.indexOf("/");
34989
- return slash > 0 && slash < modelId.length - 1;
34990
- }
34991
- function resolveModel(model, provider, label) {
34992
- if (isNamespacedModelId(model)) {
34993
- const [p, m] = parseModelId(model);
34994
- return { provider: p, model: m };
34995
- }
34996
- if (!provider) {
34997
- throw new Error(
34998
- `${label}: bare model "${model}" requires a provider \u2014 pass it explicitly or use "provider/model".`
34999
- );
35000
- }
35001
- return { provider, model };
35002
- }
35003
- var TIER_SUFFIXES = /* @__PURE__ */ new Set(["auto", "standard", "priority", "flex", "scale"]);
35004
- function parseModelTier(modelId) {
35005
- const colon = modelId.lastIndexOf(":");
35006
- if (colon <= 0) return { modelId };
35007
- const suffix = modelId.slice(colon + 1);
35008
- if (!TIER_SUFFIXES.has(suffix)) return { modelId };
35009
- return { modelId: modelId.slice(0, colon), serviceTier: suffix };
35010
- }
35011
-
35012
- // src/helpers/engine.ts
35013
- function createEngine(config = {}) {
35014
- const sessionId = config.sessionId ?? `sess_${crypto.randomUUID().slice(0, 12)}`;
35015
- const hooks = config.hooks ?? new HookBus();
35016
- const bus = config.bus ?? new AgentBus();
35017
- const persistence = resolvePersistence(config.persistence);
35018
- const cache2 = resolveCache(config.cache);
35019
- const catalog = resolveCatalog(config.catalog);
35020
- const network = new NetworkEngine({ hooks, fetch: config.fetch, retry: config.retry, queues: config.queues });
35021
- const fetchBound = (req, options) => network.fetch(req, options);
35022
- const fetchStreamBound = (req, options) => network.fetchStream(req, options);
35023
- const connectBound = (req) => network.connect(req);
35024
- const cost = new CostCollector({ hooks, catalog });
35025
- const telemetry = config.telemetry ? new TelemetryAdapter(hooks, config.telemetry) : null;
35026
- const handle = {
35027
- sessionId,
35028
- hooks,
35029
- bus,
35030
- persistence,
35031
- cache: cache2,
35032
- network,
35033
- fetch: fetchBound,
35034
- fetchStream: fetchStreamBound,
35035
- connect: connectBound,
35036
- catalog,
35037
- cost,
35038
- telemetry,
35039
- apiKeys: config.apiKeys ?? {},
35040
- destroy() {
35041
- cost.destroy();
35042
- telemetry?.destroy();
35043
- network.destroy();
35044
- }
35045
- };
35046
- if (config.registerAsDefault !== false) {
35047
- coreRegistry.set(handle);
35048
- }
35049
- return handle;
35050
- }
35051
- function resolveCatalog(config) {
35052
- const c = new ModelCatalog();
35053
- if (!config) return c;
35054
- if (config instanceof ModelCatalog) return config;
35055
- if (config === true || config === "defaults") {
35056
- c.loadProviderDefaults();
35057
- return c;
35058
- }
35059
- if (typeof config === "object" && "entries" in config) {
35060
- c.load(config.entries);
35061
- return c;
35062
- }
35063
- return c;
35064
- }
35065
- function resolvePersistence(config) {
35066
- if (!config) return new MemoryPersistence();
35067
- if (typeof config.get === "function") {
35068
- return config;
35069
- }
35070
- const c = config;
35071
- if (c.type === "memory") return new MemoryPersistence();
35072
- if (c.type === "file") {
35073
- if (!c.dir) {
35074
- throw new Error('createEngine: persistence type "file" requires a `dir` field');
35075
- }
35076
- return new FilePersistence(c.dir);
35077
- }
35078
- throw new Error(`createEngine: unknown persistence type "${c.type}"`);
35079
- }
35080
- function resolveCache(config) {
35081
- if (!config) return null;
35082
- if (config instanceof Cache) return config;
35083
- const c = config;
35084
- if (c.type === "memory") return new Cache({ store: new MemoryCacheStore() });
35085
- throw new Error(`createEngine: unknown cache type "${c.type}"`);
35086
- }
35087
- var CoreRegistry = class {
35088
- current = null;
35089
- /** Get the current default engine, creating a bare one on first read. */
35090
- get() {
35091
- if (!this.current) this.current = createEngine();
35092
- return this.current;
35093
- }
35094
- /** Set the default engine. Throws if one is already set unless replace=true.
35095
- * When replacing, the previous engine is destroyed AFTER the pointer
35096
- * swap so engine.destroy callbacks can safely query the registry. */
35097
- set(engine, opts = {}) {
35098
- if (this.current && !opts.replace) {
35099
- throw new Error(
35100
- "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."
35101
- );
35102
- }
35103
- const previous = this.current;
35104
- this.current = engine;
35105
- if (previous && opts.replace) {
35106
- previous.destroy();
35107
- }
35108
- }
35109
- /** Clear the default engine. */
35110
- clear() {
35111
- this.current?.destroy();
35112
- this.current = null;
35113
- }
35114
- has() {
35115
- return this.current !== null;
35116
- }
35117
- };
35118
- var coreRegistry = new CoreRegistry();
35119
-
35120
- // src/helpers/llm.ts
35121
- function createLLM(opts) {
35122
- const engine = opts.engine ?? coreRegistry.get();
35123
- const { provider, model } = resolveModel(opts.model, opts.provider, "createLLM");
35124
- const sendModel = engine.catalog.resolveModelId(provider, model);
35125
- const apiKey = opts.apiKey ?? engine.apiKeys[provider];
35126
- if (!apiKey) {
35127
- throw new Error(
35128
- `createLLM: no API key for provider "${provider}". Pass apiKey directly or set engine.apiKeys["${provider}"] via createEngine.`
35129
- );
35130
- }
35131
- const adapter = opts.adapter ?? defaultAdapterFactory();
35132
- return new LLMClient({
35133
- ...opts,
35134
- provider,
35135
- model: sendModel,
35136
- apiKey,
35137
- adapter,
35138
- fetch: opts.fetch ?? engine.fetch,
35139
- fetchStream: opts.fetchStream ?? engine.fetchStream,
35140
- hooks: opts.hooks ?? engine.hooks,
35141
- sessionId: engine.sessionId,
35142
- catalog: engine.catalog
35143
- });
35144
- }
35145
- function defaultAdapterFactory() {
35146
- return (provider, apiKey, api, baseURL) => {
35147
- const cfg = { apiKey, baseURL };
35148
- switch (provider) {
35149
- case "anthropic":
35150
- return new AnthropicAdapter(cfg);
35151
- case "openai":
35152
- return api === "responses" ? new OpenAIResponsesAdapter(cfg) : new OpenAIAdapter(cfg);
35153
- case "google":
35154
- return api === "interactions" ? new GoogleInteractionsAdapter(cfg) : new GoogleAdapter(cfg);
35155
- case "xai":
35156
- return api === "responses" ? new XAIResponsesAdapter(cfg) : new XAIAdapter(cfg);
35157
- case "openrouter":
35158
- return api === "responses" ? new OpenRouterResponsesAdapter(cfg) : new OpenRouterAdapter(cfg);
35159
- default:
35160
- throw new Error(`createLLM: no default adapter for provider '${provider}'`);
35161
- }
35162
- };
35163
- }
35164
-
35165
35427
  // src/plugins/internal-tools/runner/runner.ts
35166
35428
  var InternalToolRunner = class {
35167
35429
  constructor(config) {
@@ -35289,8 +35551,7 @@ var InternalToolRunner = class {
35289
35551
  const key = requiresDedicated ? `${provider}/${model}` : provider;
35290
35552
  let client = this.clients.get(key);
35291
35553
  if (!client) {
35292
- client = createLLM({
35293
- engine,
35554
+ client = engine.createClient({
35294
35555
  provider,
35295
35556
  model,
35296
35557
  apiKey,
@@ -38132,6 +38393,289 @@ var FACT_CATEGORIES = [
38132
38393
  "other"
38133
38394
  ];
38134
38395
 
38396
+ // src/helpers/client-pool.ts
38397
+ var ClientPool = class {
38398
+ constructor(catalog) {
38399
+ this.catalog = catalog;
38400
+ }
38401
+ catalog;
38402
+ clients = /* @__PURE__ */ new Map();
38403
+ get(provider, model, config) {
38404
+ const key = this.keyFor(provider, model);
38405
+ let client = this.clients.get(key);
38406
+ if (!client) {
38407
+ client = new LLMClient({ ...config, model });
38408
+ this.clients.set(key, client);
38409
+ }
38410
+ return client;
38411
+ }
38412
+ async destroy() {
38413
+ for (const [, client] of this.clients) {
38414
+ client.destroy();
38415
+ }
38416
+ this.clients.clear();
38417
+ }
38418
+ get size() {
38419
+ return this.clients.size;
38420
+ }
38421
+ keyFor(provider, model) {
38422
+ const info = this.catalog?.get(provider, model);
38423
+ if (info?.requiresDedicatedClient) {
38424
+ return `${provider}/${model}`;
38425
+ }
38426
+ return provider;
38427
+ }
38428
+ };
38429
+
38430
+ // src/helpers/client-resolver.ts
38431
+ function directFetch() {
38432
+ return async (req) => {
38433
+ const init = {
38434
+ method: req.method ?? "POST",
38435
+ headers: req.headers,
38436
+ body: typeof req.body === "string" ? req.body : JSON.stringify(req.body)
38437
+ };
38438
+ if (req.signal) init.signal = req.signal;
38439
+ const res = await globalThis.fetch(req.url, init);
38440
+ const headers = {};
38441
+ res.headers.forEach((v, k) => {
38442
+ headers[k] = v;
38443
+ });
38444
+ const body = await res.json().catch(() => null);
38445
+ return { status: res.status, headers, body };
38446
+ };
38447
+ }
38448
+ var ClientResolver = class {
38449
+ constructor(cfg) {
38450
+ this.cfg = cfg;
38451
+ this.pool = new ClientPool(cfg.catalog);
38452
+ }
38453
+ cfg;
38454
+ pool;
38455
+ /** Turn `"anthropic/claude-haiku-4-5"` → resolved client. */
38456
+ resolve(modelId) {
38457
+ const [provider, model] = parseModelId(modelId);
38458
+ const apiKey = this.cfg.apiKeys[provider];
38459
+ if (!apiKey) {
38460
+ const known = Object.keys(this.cfg.apiKeys).filter(
38461
+ (k) => !!this.cfg.apiKeys[k]
38462
+ );
38463
+ throw new Error(
38464
+ `ClientResolver: no API key for provider "${provider}". Configured providers: [${known.join(", ") || "none"}]`
38465
+ );
38466
+ }
38467
+ const fetchFn = this.cfg.fetch ?? directFetch();
38468
+ const client = this.pool.get(provider, model, {
38469
+ provider,
38470
+ apiKey,
38471
+ hooks: this.cfg.hooks,
38472
+ model,
38473
+ fetch: fetchFn,
38474
+ fetchStream: this.cfg.fetchStream,
38475
+ ...this.cfg.clientOptions
38476
+ });
38477
+ return { client, provider, model };
38478
+ }
38479
+ availableProviders() {
38480
+ return Object.keys(this.cfg.apiKeys).filter((p) => !!this.cfg.apiKeys[p]);
38481
+ }
38482
+ async destroy() {
38483
+ await this.pool.destroy();
38484
+ }
38485
+ get size() {
38486
+ return this.pool.size;
38487
+ }
38488
+ };
38489
+ function parseModelId(modelId) {
38490
+ const slash = modelId.indexOf("/");
38491
+ if (slash <= 0 || slash === modelId.length - 1) {
38492
+ throw new Error(`Invalid model id "${modelId}" \u2014 expected format "provider/model"`);
38493
+ }
38494
+ const provider = modelId.slice(0, slash);
38495
+ const model = modelId.slice(slash + 1);
38496
+ return [provider, model];
38497
+ }
38498
+ function isNamespacedModelId(modelId) {
38499
+ const slash = modelId.indexOf("/");
38500
+ return slash > 0 && slash < modelId.length - 1;
38501
+ }
38502
+ function resolveModel(model, provider, label) {
38503
+ if (isNamespacedModelId(model)) {
38504
+ const [p, m] = parseModelId(model);
38505
+ return { provider: p, model: m };
38506
+ }
38507
+ if (!provider) {
38508
+ throw new Error(
38509
+ `${label}: bare model "${model}" requires a provider \u2014 pass it explicitly or use "provider/model".`
38510
+ );
38511
+ }
38512
+ return { provider, model };
38513
+ }
38514
+ var TIER_SUFFIXES = /* @__PURE__ */ new Set(["auto", "standard", "priority", "flex", "scale"]);
38515
+ function parseModelTier(modelId) {
38516
+ const colon = modelId.lastIndexOf(":");
38517
+ if (colon <= 0) return { modelId };
38518
+ const suffix = modelId.slice(colon + 1);
38519
+ if (!TIER_SUFFIXES.has(suffix)) return { modelId };
38520
+ return { modelId: modelId.slice(0, colon), serviceTier: suffix };
38521
+ }
38522
+
38523
+ // src/helpers/engine.ts
38524
+ function createEngine(config = {}) {
38525
+ const sessionId = config.sessionId ?? `sess_${crypto.randomUUID().slice(0, 12)}`;
38526
+ const hooks = config.hooks ?? new HookBus();
38527
+ const bus = config.bus ?? new AgentBus();
38528
+ const persistence = resolvePersistence(config.persistence);
38529
+ const cache2 = resolveCache(config.cache);
38530
+ const catalog = resolveCatalog(config.catalog);
38531
+ const network = new NetworkEngine({ hooks, fetch: config.fetch, retry: config.retry, queues: config.queues });
38532
+ const fetchBound = (req, options) => network.fetch(req, options);
38533
+ const fetchStreamBound = (req, options) => network.fetchStream(req, options);
38534
+ const connectBound = (req) => network.connect(req);
38535
+ const cost = new CostCollector({ hooks, catalog });
38536
+ const telemetry = config.telemetry ? new TelemetryAdapter(hooks, config.telemetry) : null;
38537
+ const handle = {
38538
+ sessionId,
38539
+ hooks,
38540
+ bus,
38541
+ persistence,
38542
+ cache: cache2,
38543
+ network,
38544
+ fetch: fetchBound,
38545
+ fetchStream: fetchStreamBound,
38546
+ connect: connectBound,
38547
+ catalog,
38548
+ cost,
38549
+ telemetry,
38550
+ apiKeys: config.apiKeys ?? {},
38551
+ // Bound inside the literal so the closure captures this handle. The body runs
38552
+ // only when a caller asks for a client, so referencing `handle` here is safe.
38553
+ createClient: (options) => createLLM({ ...options, engine: handle }),
38554
+ destroy() {
38555
+ cost.destroy();
38556
+ telemetry?.destroy();
38557
+ network.destroy();
38558
+ }
38559
+ };
38560
+ if (config.registerAsDefault !== false) {
38561
+ coreRegistry.set(handle);
38562
+ }
38563
+ return handle;
38564
+ }
38565
+ function resolveCatalog(config) {
38566
+ const c = new ModelCatalog();
38567
+ if (!config) return c;
38568
+ if (config instanceof ModelCatalog) return config;
38569
+ if (config === true || config === "defaults") {
38570
+ c.loadProviderDefaults();
38571
+ return c;
38572
+ }
38573
+ if (typeof config === "object" && "entries" in config) {
38574
+ c.load(config.entries);
38575
+ return c;
38576
+ }
38577
+ return c;
38578
+ }
38579
+ function resolvePersistence(config) {
38580
+ if (!config) return new MemoryPersistence();
38581
+ if (typeof config.get === "function") {
38582
+ return config;
38583
+ }
38584
+ const c = config;
38585
+ if (c.type === "memory") return new MemoryPersistence();
38586
+ if (c.type === "file") {
38587
+ if (!c.dir) {
38588
+ throw new Error('createEngine: persistence type "file" requires a `dir` field');
38589
+ }
38590
+ return new FilePersistence(c.dir);
38591
+ }
38592
+ throw new Error(`createEngine: unknown persistence type "${c.type}"`);
38593
+ }
38594
+ function resolveCache(config) {
38595
+ if (!config) return null;
38596
+ if (config instanceof Cache) return config;
38597
+ const c = config;
38598
+ if (c.type === "memory") return new Cache({ store: new MemoryCacheStore() });
38599
+ throw new Error(`createEngine: unknown cache type "${c.type}"`);
38600
+ }
38601
+ var CoreRegistry = class {
38602
+ current = null;
38603
+ /** Get the current default engine, creating a bare one on first read. */
38604
+ get() {
38605
+ if (!this.current) this.current = createEngine();
38606
+ return this.current;
38607
+ }
38608
+ /** Set the default engine. Throws if one is already set unless replace=true.
38609
+ * When replacing, the previous engine is destroyed AFTER the pointer
38610
+ * swap so engine.destroy callbacks can safely query the registry. */
38611
+ set(engine, opts = {}) {
38612
+ if (this.current && !opts.replace) {
38613
+ throw new Error(
38614
+ "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."
38615
+ );
38616
+ }
38617
+ const previous = this.current;
38618
+ this.current = engine;
38619
+ if (previous && opts.replace) {
38620
+ previous.destroy();
38621
+ }
38622
+ }
38623
+ /** Clear the default engine. */
38624
+ clear() {
38625
+ this.current?.destroy();
38626
+ this.current = null;
38627
+ }
38628
+ has() {
38629
+ return this.current !== null;
38630
+ }
38631
+ };
38632
+ var coreRegistry = new CoreRegistry();
38633
+
38634
+ // src/helpers/llm.ts
38635
+ function createLLM(opts) {
38636
+ const engine = opts.engine ?? coreRegistry.get();
38637
+ const { provider, model } = resolveModel(opts.model, opts.provider, "createLLM");
38638
+ const sendModel = engine.catalog.resolveModelId(provider, model);
38639
+ const apiKey = opts.apiKey ?? engine.apiKeys[provider];
38640
+ if (!apiKey) {
38641
+ throw new Error(
38642
+ `createLLM: no API key for provider "${provider}". Pass apiKey directly or set engine.apiKeys["${provider}"] via createEngine.`
38643
+ );
38644
+ }
38645
+ const adapter = opts.adapter ?? defaultAdapterFactory();
38646
+ return new LLMClient({
38647
+ ...opts,
38648
+ provider,
38649
+ model: sendModel,
38650
+ apiKey,
38651
+ adapter,
38652
+ fetch: opts.fetch ?? engine.fetch,
38653
+ fetchStream: opts.fetchStream ?? engine.fetchStream,
38654
+ hooks: opts.hooks ?? engine.hooks,
38655
+ sessionId: engine.sessionId,
38656
+ catalog: engine.catalog
38657
+ });
38658
+ }
38659
+ function defaultAdapterFactory() {
38660
+ return (provider, apiKey, api, baseURL) => {
38661
+ const cfg = { apiKey, baseURL };
38662
+ switch (provider) {
38663
+ case "anthropic":
38664
+ return new AnthropicAdapter(cfg);
38665
+ case "openai":
38666
+ return api === "responses" ? new OpenAIResponsesAdapter(cfg) : new OpenAIAdapter(cfg);
38667
+ case "google":
38668
+ return api === "interactions" ? new GoogleInteractionsAdapter(cfg) : new GoogleAdapter(cfg);
38669
+ case "xai":
38670
+ return api === "responses" ? new XAIResponsesAdapter(cfg) : new XAIAdapter(cfg);
38671
+ case "openrouter":
38672
+ return api === "responses" ? new OpenRouterResponsesAdapter(cfg) : new OpenRouterAdapter(cfg);
38673
+ default:
38674
+ throw new Error(`createLLM: no default adapter for provider '${provider}'`);
38675
+ }
38676
+ };
38677
+ }
38678
+
38135
38679
  // src/helpers/agent.ts
38136
38680
  function createAgent(opts) {
38137
38681
  const engine = opts.engine ?? coreRegistry.get();
@@ -40285,10 +40829,10 @@ function toStopReason(finish) {
40285
40829
  if (finish === "stop") return "endTurn";
40286
40830
  return finish;
40287
40831
  }
40288
- function samplingHandler(config) {
40832
+ function samplingHandlerWith(complete2, config) {
40289
40833
  if (typeof config === "function") return config;
40290
40834
  return async (params) => {
40291
- const result = await complete({
40835
+ const result = await complete2({
40292
40836
  model: config.model,
40293
40837
  provider: config.provider,
40294
40838
  engine: config.engine,
@@ -41073,6 +41617,9 @@ var WsTransport = class extends BaseJsonRpcTransport {
41073
41617
  };
41074
41618
 
41075
41619
  // src/helpers/mcp.ts
41620
+ function samplingHandler(config) {
41621
+ return samplingHandlerWith(complete, config);
41622
+ }
41076
41623
  function defaultNamespace(config) {
41077
41624
  if (isHttpConfig(config)) {
41078
41625
  if (config.name) return config.name;