@oh-my-pi/pi-ai 12.11.0 → 12.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oh-my-pi/pi-ai",
3
- "version": "12.11.0",
3
+ "version": "12.11.2",
4
4
  "description": "Unified LLM API with automatic model discovery and provider configuration",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -63,7 +63,7 @@
63
63
  "@connectrpc/connect-node": "^2.1.1",
64
64
  "@google/genai": "^1.41.0",
65
65
  "@mistralai/mistralai": "^1.14.0",
66
- "@oh-my-pi/pi-utils": "12.11.0",
66
+ "@oh-my-pi/pi-utils": "12.11.2",
67
67
  "@sinclair/typebox": "^0.34.48",
68
68
  "@smithy/node-http-handler": "^4.4.10",
69
69
  "ajv": "^8.18.0",
package/src/models.json CHANGED
@@ -8593,8 +8593,8 @@
8593
8593
  "text"
8594
8594
  ],
8595
8595
  "cost": {
8596
- "input": 0.3,
8597
- "output": 1.2,
8596
+ "input": 0.32,
8597
+ "output": 0.8899999999999999,
8598
8598
  "cacheRead": 0.15,
8599
8599
  "cacheWrite": 0
8600
8600
  },
@@ -9834,12 +9834,12 @@
9834
9834
  "text"
9835
9835
  ],
9836
9836
  "cost": {
9837
- "input": 0.39999999999999997,
9838
- "output": 1.75,
9839
- "cacheRead": 0.19999999999999998,
9837
+ "input": 0.47,
9838
+ "output": 2,
9839
+ "cacheRead": 0.14100000000000001,
9840
9840
  "cacheWrite": 0
9841
9841
  },
9842
- "contextWindow": 262144,
9842
+ "contextWindow": 131072,
9843
9843
  "maxTokens": 65535
9844
9844
  },
9845
9845
  "moonshotai/kimi-k2.5": {
@@ -17102,7 +17102,7 @@
17102
17102
  "cursor": {
17103
17103
  "claude-4.5-opus-high": {
17104
17104
  "id": "claude-4.5-opus-high",
17105
- "name": "Claude 4.5 Opus (Cursor)",
17105
+ "name": "Claude 4.5 Opus",
17106
17106
  "api": "cursor-agent",
17107
17107
  "provider": "cursor",
17108
17108
  "baseUrl": "https://api2.cursor.sh",
@@ -17122,7 +17122,7 @@
17122
17122
  },
17123
17123
  "claude-4.5-opus-high-thinking": {
17124
17124
  "id": "claude-4.5-opus-high-thinking",
17125
- "name": "Claude 4.5 Opus Thinking (Cursor)",
17125
+ "name": "Claude 4.5 Opus (Thinking)",
17126
17126
  "api": "cursor-agent",
17127
17127
  "provider": "cursor",
17128
17128
  "baseUrl": "https://api2.cursor.sh",
@@ -17142,7 +17142,7 @@
17142
17142
  },
17143
17143
  "claude-4.5-sonnet": {
17144
17144
  "id": "claude-4.5-sonnet",
17145
- "name": "Claude 4.5 Sonnet (Cursor)",
17145
+ "name": "Claude 4.5 Sonnet",
17146
17146
  "api": "cursor-agent",
17147
17147
  "provider": "cursor",
17148
17148
  "baseUrl": "https://api2.cursor.sh",
@@ -17162,7 +17162,7 @@
17162
17162
  },
17163
17163
  "claude-4.5-sonnet-thinking": {
17164
17164
  "id": "claude-4.5-sonnet-thinking",
17165
- "name": "Claude 4.5 Sonnet Thinking (Cursor)",
17165
+ "name": "Claude 4.5 Sonnet (Thinking)",
17166
17166
  "api": "cursor-agent",
17167
17167
  "provider": "cursor",
17168
17168
  "baseUrl": "https://api2.cursor.sh",
@@ -17180,9 +17180,104 @@
17180
17180
  "contextWindow": 200000,
17181
17181
  "maxTokens": 64000
17182
17182
  },
17183
+ "claude-4.6-opus-high": {
17184
+ "id": "claude-4.6-opus-high",
17185
+ "name": "Claude 4.6 Opus",
17186
+ "api": "cursor-agent",
17187
+ "provider": "cursor",
17188
+ "baseUrl": "https://api2.cursor.sh",
17189
+ "reasoning": false,
17190
+ "input": [
17191
+ "text"
17192
+ ],
17193
+ "cost": {
17194
+ "input": 0,
17195
+ "output": 0,
17196
+ "cacheRead": 0,
17197
+ "cacheWrite": 0
17198
+ },
17199
+ "contextWindow": 200000,
17200
+ "maxTokens": 64000
17201
+ },
17202
+ "claude-4.6-opus-high-thinking": {
17203
+ "id": "claude-4.6-opus-high-thinking",
17204
+ "name": "Claude 4.6 Opus (Thinking)",
17205
+ "api": "cursor-agent",
17206
+ "provider": "cursor",
17207
+ "baseUrl": "https://api2.cursor.sh",
17208
+ "reasoning": false,
17209
+ "input": [
17210
+ "text"
17211
+ ],
17212
+ "cost": {
17213
+ "input": 0,
17214
+ "output": 0,
17215
+ "cacheRead": 0,
17216
+ "cacheWrite": 0
17217
+ },
17218
+ "contextWindow": 200000,
17219
+ "maxTokens": 64000
17220
+ },
17221
+ "claude-4.6-sonnet-medium": {
17222
+ "id": "claude-4.6-sonnet-medium",
17223
+ "name": "Claude 4.6 Sonnet",
17224
+ "api": "cursor-agent",
17225
+ "provider": "cursor",
17226
+ "baseUrl": "https://api2.cursor.sh",
17227
+ "reasoning": false,
17228
+ "input": [
17229
+ "text"
17230
+ ],
17231
+ "cost": {
17232
+ "input": 0,
17233
+ "output": 0,
17234
+ "cacheRead": 0,
17235
+ "cacheWrite": 0
17236
+ },
17237
+ "contextWindow": 200000,
17238
+ "maxTokens": 64000
17239
+ },
17240
+ "claude-4.6-sonnet-medium-thinking": {
17241
+ "id": "claude-4.6-sonnet-medium-thinking",
17242
+ "name": "Claude 4.6 Sonnet (Thinking)",
17243
+ "api": "cursor-agent",
17244
+ "provider": "cursor",
17245
+ "baseUrl": "https://api2.cursor.sh",
17246
+ "reasoning": false,
17247
+ "input": [
17248
+ "text"
17249
+ ],
17250
+ "cost": {
17251
+ "input": 0,
17252
+ "output": 0,
17253
+ "cacheRead": 0,
17254
+ "cacheWrite": 0
17255
+ },
17256
+ "contextWindow": 200000,
17257
+ "maxTokens": 64000
17258
+ },
17183
17259
  "composer-1": {
17184
17260
  "id": "composer-1",
17185
- "name": "Composer 1 (Cursor)",
17261
+ "name": "Composer 1",
17262
+ "api": "cursor-agent",
17263
+ "provider": "cursor",
17264
+ "baseUrl": "https://api2.cursor.sh",
17265
+ "reasoning": false,
17266
+ "input": [
17267
+ "text"
17268
+ ],
17269
+ "cost": {
17270
+ "input": 0,
17271
+ "output": 0,
17272
+ "cacheRead": 0,
17273
+ "cacheWrite": 0
17274
+ },
17275
+ "contextWindow": 200000,
17276
+ "maxTokens": 64000
17277
+ },
17278
+ "composer-1.5": {
17279
+ "id": "composer-1.5",
17280
+ "name": "Composer 1.5",
17186
17281
  "api": "cursor-agent",
17187
17282
  "provider": "cursor",
17188
17283
  "baseUrl": "https://api2.cursor.sh",
@@ -17201,7 +17296,7 @@
17201
17296
  },
17202
17297
  "default": {
17203
17298
  "id": "default",
17204
- "name": "Auto (Cursor)",
17299
+ "name": "Auto",
17205
17300
  "api": "cursor-agent",
17206
17301
  "provider": "cursor",
17207
17302
  "baseUrl": "https://api2.cursor.sh",
@@ -17221,7 +17316,7 @@
17221
17316
  },
17222
17317
  "gemini-3-flash": {
17223
17318
  "id": "gemini-3-flash",
17224
- "name": "Gemini 3 Flash (Cursor)",
17319
+ "name": "Gemini 3 Flash",
17225
17320
  "api": "cursor-agent",
17226
17321
  "provider": "cursor",
17227
17322
  "baseUrl": "https://api2.cursor.sh",
@@ -17241,7 +17336,7 @@
17241
17336
  },
17242
17337
  "gemini-3-pro": {
17243
17338
  "id": "gemini-3-pro",
17244
- "name": "Gemini 3 Pro (Cursor)",
17339
+ "name": "Gemini 3 Pro",
17245
17340
  "api": "cursor-agent",
17246
17341
  "provider": "cursor",
17247
17342
  "baseUrl": "https://api2.cursor.sh",
@@ -17261,7 +17356,7 @@
17261
17356
  },
17262
17357
  "gpt-5.1-codex-max": {
17263
17358
  "id": "gpt-5.1-codex-max",
17264
- "name": "GPT-5.1 Codex Max (Cursor)",
17359
+ "name": "GPT-5.1 Codex Max",
17265
17360
  "api": "cursor-agent",
17266
17361
  "provider": "cursor",
17267
17362
  "baseUrl": "https://api2.cursor.sh",
@@ -17281,7 +17376,7 @@
17281
17376
  },
17282
17377
  "gpt-5.1-codex-max-high": {
17283
17378
  "id": "gpt-5.1-codex-max-high",
17284
- "name": "GPT-5.1 Codex Max High (Cursor)",
17379
+ "name": "GPT-5.1 Codex Max High",
17285
17380
  "api": "cursor-agent",
17286
17381
  "provider": "cursor",
17287
17382
  "baseUrl": "https://api2.cursor.sh",
@@ -17299,9 +17394,47 @@
17299
17394
  "contextWindow": 272000,
17300
17395
  "maxTokens": 128000
17301
17396
  },
17397
+ "gpt-5.1-codex-mini": {
17398
+ "id": "gpt-5.1-codex-mini",
17399
+ "name": "GPT-5.1 Codex Mini",
17400
+ "api": "cursor-agent",
17401
+ "provider": "cursor",
17402
+ "baseUrl": "https://api2.cursor.sh",
17403
+ "reasoning": false,
17404
+ "input": [
17405
+ "text"
17406
+ ],
17407
+ "cost": {
17408
+ "input": 0,
17409
+ "output": 0,
17410
+ "cacheRead": 0,
17411
+ "cacheWrite": 0
17412
+ },
17413
+ "contextWindow": 272000,
17414
+ "maxTokens": 64000
17415
+ },
17416
+ "gpt-5.1-high": {
17417
+ "id": "gpt-5.1-high",
17418
+ "name": "GPT-5.1 High",
17419
+ "api": "cursor-agent",
17420
+ "provider": "cursor",
17421
+ "baseUrl": "https://api2.cursor.sh",
17422
+ "reasoning": false,
17423
+ "input": [
17424
+ "text"
17425
+ ],
17426
+ "cost": {
17427
+ "input": 0,
17428
+ "output": 0,
17429
+ "cacheRead": 0,
17430
+ "cacheWrite": 0
17431
+ },
17432
+ "contextWindow": 200000,
17433
+ "maxTokens": 64000
17434
+ },
17302
17435
  "gpt-5.2": {
17303
17436
  "id": "gpt-5.2",
17304
- "name": "GPT-5.2 (Cursor)",
17437
+ "name": "GPT-5.2",
17305
17438
  "api": "cursor-agent",
17306
17439
  "provider": "cursor",
17307
17440
  "baseUrl": "https://api2.cursor.sh",
@@ -17319,9 +17452,161 @@
17319
17452
  "contextWindow": 400000,
17320
17453
  "maxTokens": 128000
17321
17454
  },
17455
+ "gpt-5.2-codex": {
17456
+ "id": "gpt-5.2-codex",
17457
+ "name": "GPT-5.2 Codex",
17458
+ "api": "cursor-agent",
17459
+ "provider": "cursor",
17460
+ "baseUrl": "https://api2.cursor.sh",
17461
+ "reasoning": false,
17462
+ "input": [
17463
+ "text"
17464
+ ],
17465
+ "cost": {
17466
+ "input": 0,
17467
+ "output": 0,
17468
+ "cacheRead": 0,
17469
+ "cacheWrite": 0
17470
+ },
17471
+ "contextWindow": 272000,
17472
+ "maxTokens": 64000
17473
+ },
17474
+ "gpt-5.2-codex-fast": {
17475
+ "id": "gpt-5.2-codex-fast",
17476
+ "name": "GPT-5.2 Codex Fast",
17477
+ "api": "cursor-agent",
17478
+ "provider": "cursor",
17479
+ "baseUrl": "https://api2.cursor.sh",
17480
+ "reasoning": false,
17481
+ "input": [
17482
+ "text"
17483
+ ],
17484
+ "cost": {
17485
+ "input": 0,
17486
+ "output": 0,
17487
+ "cacheRead": 0,
17488
+ "cacheWrite": 0
17489
+ },
17490
+ "contextWindow": 272000,
17491
+ "maxTokens": 64000
17492
+ },
17493
+ "gpt-5.2-codex-high": {
17494
+ "id": "gpt-5.2-codex-high",
17495
+ "name": "GPT-5.2 Codex High",
17496
+ "api": "cursor-agent",
17497
+ "provider": "cursor",
17498
+ "baseUrl": "https://api2.cursor.sh",
17499
+ "reasoning": false,
17500
+ "input": [
17501
+ "text"
17502
+ ],
17503
+ "cost": {
17504
+ "input": 0,
17505
+ "output": 0,
17506
+ "cacheRead": 0,
17507
+ "cacheWrite": 0
17508
+ },
17509
+ "contextWindow": 272000,
17510
+ "maxTokens": 64000
17511
+ },
17512
+ "gpt-5.2-codex-high-fast": {
17513
+ "id": "gpt-5.2-codex-high-fast",
17514
+ "name": "GPT-5.2 Codex High Fast",
17515
+ "api": "cursor-agent",
17516
+ "provider": "cursor",
17517
+ "baseUrl": "https://api2.cursor.sh",
17518
+ "reasoning": false,
17519
+ "input": [
17520
+ "text"
17521
+ ],
17522
+ "cost": {
17523
+ "input": 0,
17524
+ "output": 0,
17525
+ "cacheRead": 0,
17526
+ "cacheWrite": 0
17527
+ },
17528
+ "contextWindow": 272000,
17529
+ "maxTokens": 64000
17530
+ },
17531
+ "gpt-5.2-codex-low": {
17532
+ "id": "gpt-5.2-codex-low",
17533
+ "name": "GPT-5.2 Codex Low",
17534
+ "api": "cursor-agent",
17535
+ "provider": "cursor",
17536
+ "baseUrl": "https://api2.cursor.sh",
17537
+ "reasoning": false,
17538
+ "input": [
17539
+ "text"
17540
+ ],
17541
+ "cost": {
17542
+ "input": 0,
17543
+ "output": 0,
17544
+ "cacheRead": 0,
17545
+ "cacheWrite": 0
17546
+ },
17547
+ "contextWindow": 272000,
17548
+ "maxTokens": 64000
17549
+ },
17550
+ "gpt-5.2-codex-low-fast": {
17551
+ "id": "gpt-5.2-codex-low-fast",
17552
+ "name": "GPT-5.2 Codex Low Fast",
17553
+ "api": "cursor-agent",
17554
+ "provider": "cursor",
17555
+ "baseUrl": "https://api2.cursor.sh",
17556
+ "reasoning": false,
17557
+ "input": [
17558
+ "text"
17559
+ ],
17560
+ "cost": {
17561
+ "input": 0,
17562
+ "output": 0,
17563
+ "cacheRead": 0,
17564
+ "cacheWrite": 0
17565
+ },
17566
+ "contextWindow": 272000,
17567
+ "maxTokens": 64000
17568
+ },
17569
+ "gpt-5.2-codex-xhigh": {
17570
+ "id": "gpt-5.2-codex-xhigh",
17571
+ "name": "GPT-5.2 Codex Extra High",
17572
+ "api": "cursor-agent",
17573
+ "provider": "cursor",
17574
+ "baseUrl": "https://api2.cursor.sh",
17575
+ "reasoning": false,
17576
+ "input": [
17577
+ "text"
17578
+ ],
17579
+ "cost": {
17580
+ "input": 0,
17581
+ "output": 0,
17582
+ "cacheRead": 0,
17583
+ "cacheWrite": 0
17584
+ },
17585
+ "contextWindow": 272000,
17586
+ "maxTokens": 64000
17587
+ },
17588
+ "gpt-5.2-codex-xhigh-fast": {
17589
+ "id": "gpt-5.2-codex-xhigh-fast",
17590
+ "name": "GPT-5.2 Codex Extra High Fast",
17591
+ "api": "cursor-agent",
17592
+ "provider": "cursor",
17593
+ "baseUrl": "https://api2.cursor.sh",
17594
+ "reasoning": false,
17595
+ "input": [
17596
+ "text"
17597
+ ],
17598
+ "cost": {
17599
+ "input": 0,
17600
+ "output": 0,
17601
+ "cacheRead": 0,
17602
+ "cacheWrite": 0
17603
+ },
17604
+ "contextWindow": 272000,
17605
+ "maxTokens": 64000
17606
+ },
17322
17607
  "gpt-5.2-high": {
17323
17608
  "id": "gpt-5.2-high",
17324
- "name": "GPT-5.2 High (Cursor)",
17609
+ "name": "GPT-5.2 High",
17325
17610
  "api": "cursor-agent",
17326
17611
  "provider": "cursor",
17327
17612
  "baseUrl": "https://api2.cursor.sh",
@@ -17339,9 +17624,161 @@
17339
17624
  "contextWindow": 400000,
17340
17625
  "maxTokens": 128000
17341
17626
  },
17627
+ "gpt-5.3-codex": {
17628
+ "id": "gpt-5.3-codex",
17629
+ "name": "GPT-5.3 Codex",
17630
+ "api": "cursor-agent",
17631
+ "provider": "cursor",
17632
+ "baseUrl": "https://api2.cursor.sh",
17633
+ "reasoning": false,
17634
+ "input": [
17635
+ "text"
17636
+ ],
17637
+ "cost": {
17638
+ "input": 0,
17639
+ "output": 0,
17640
+ "cacheRead": 0,
17641
+ "cacheWrite": 0
17642
+ },
17643
+ "contextWindow": 272000,
17644
+ "maxTokens": 64000
17645
+ },
17646
+ "gpt-5.3-codex-fast": {
17647
+ "id": "gpt-5.3-codex-fast",
17648
+ "name": "GPT-5.3 Codex Fast",
17649
+ "api": "cursor-agent",
17650
+ "provider": "cursor",
17651
+ "baseUrl": "https://api2.cursor.sh",
17652
+ "reasoning": false,
17653
+ "input": [
17654
+ "text"
17655
+ ],
17656
+ "cost": {
17657
+ "input": 0,
17658
+ "output": 0,
17659
+ "cacheRead": 0,
17660
+ "cacheWrite": 0
17661
+ },
17662
+ "contextWindow": 272000,
17663
+ "maxTokens": 64000
17664
+ },
17665
+ "gpt-5.3-codex-high": {
17666
+ "id": "gpt-5.3-codex-high",
17667
+ "name": "GPT-5.3 Codex High",
17668
+ "api": "cursor-agent",
17669
+ "provider": "cursor",
17670
+ "baseUrl": "https://api2.cursor.sh",
17671
+ "reasoning": false,
17672
+ "input": [
17673
+ "text"
17674
+ ],
17675
+ "cost": {
17676
+ "input": 0,
17677
+ "output": 0,
17678
+ "cacheRead": 0,
17679
+ "cacheWrite": 0
17680
+ },
17681
+ "contextWindow": 272000,
17682
+ "maxTokens": 64000
17683
+ },
17684
+ "gpt-5.3-codex-high-fast": {
17685
+ "id": "gpt-5.3-codex-high-fast",
17686
+ "name": "GPT-5.3 Codex High Fast",
17687
+ "api": "cursor-agent",
17688
+ "provider": "cursor",
17689
+ "baseUrl": "https://api2.cursor.sh",
17690
+ "reasoning": false,
17691
+ "input": [
17692
+ "text"
17693
+ ],
17694
+ "cost": {
17695
+ "input": 0,
17696
+ "output": 0,
17697
+ "cacheRead": 0,
17698
+ "cacheWrite": 0
17699
+ },
17700
+ "contextWindow": 272000,
17701
+ "maxTokens": 64000
17702
+ },
17703
+ "gpt-5.3-codex-low": {
17704
+ "id": "gpt-5.3-codex-low",
17705
+ "name": "GPT-5.3 Codex Low",
17706
+ "api": "cursor-agent",
17707
+ "provider": "cursor",
17708
+ "baseUrl": "https://api2.cursor.sh",
17709
+ "reasoning": false,
17710
+ "input": [
17711
+ "text"
17712
+ ],
17713
+ "cost": {
17714
+ "input": 0,
17715
+ "output": 0,
17716
+ "cacheRead": 0,
17717
+ "cacheWrite": 0
17718
+ },
17719
+ "contextWindow": 272000,
17720
+ "maxTokens": 64000
17721
+ },
17722
+ "gpt-5.3-codex-low-fast": {
17723
+ "id": "gpt-5.3-codex-low-fast",
17724
+ "name": "GPT-5.3 Codex Low Fast",
17725
+ "api": "cursor-agent",
17726
+ "provider": "cursor",
17727
+ "baseUrl": "https://api2.cursor.sh",
17728
+ "reasoning": false,
17729
+ "input": [
17730
+ "text"
17731
+ ],
17732
+ "cost": {
17733
+ "input": 0,
17734
+ "output": 0,
17735
+ "cacheRead": 0,
17736
+ "cacheWrite": 0
17737
+ },
17738
+ "contextWindow": 272000,
17739
+ "maxTokens": 64000
17740
+ },
17741
+ "gpt-5.3-codex-xhigh": {
17742
+ "id": "gpt-5.3-codex-xhigh",
17743
+ "name": "GPT-5.3 Codex Extra High",
17744
+ "api": "cursor-agent",
17745
+ "provider": "cursor",
17746
+ "baseUrl": "https://api2.cursor.sh",
17747
+ "reasoning": false,
17748
+ "input": [
17749
+ "text"
17750
+ ],
17751
+ "cost": {
17752
+ "input": 0,
17753
+ "output": 0,
17754
+ "cacheRead": 0,
17755
+ "cacheWrite": 0
17756
+ },
17757
+ "contextWindow": 272000,
17758
+ "maxTokens": 64000
17759
+ },
17760
+ "gpt-5.3-codex-xhigh-fast": {
17761
+ "id": "gpt-5.3-codex-xhigh-fast",
17762
+ "name": "GPT-5.3 Codex Extra High Fast",
17763
+ "api": "cursor-agent",
17764
+ "provider": "cursor",
17765
+ "baseUrl": "https://api2.cursor.sh",
17766
+ "reasoning": false,
17767
+ "input": [
17768
+ "text"
17769
+ ],
17770
+ "cost": {
17771
+ "input": 0,
17772
+ "output": 0,
17773
+ "cacheRead": 0,
17774
+ "cacheWrite": 0
17775
+ },
17776
+ "contextWindow": 272000,
17777
+ "maxTokens": 64000
17778
+ },
17342
17779
  "grok-code-fast-1": {
17343
17780
  "id": "grok-code-fast-1",
17344
- "name": "Grok (Cursor)",
17781
+ "name": "Grok",
17345
17782
  "api": "cursor-agent",
17346
17783
  "provider": "cursor",
17347
17784
  "baseUrl": "https://api2.cursor.sh",
@@ -72,7 +72,7 @@ export interface OpenAIResponsesOptions extends StreamOptions {
72
72
  toolChoice?: ToolChoice;
73
73
  /**
74
74
  * Enforce strict tool call/result pairing when building Responses API inputs.
75
- * Azure OpenAI Responses API requires tool results to have a matching tool call.
75
+ * Azure OpenAI and GitHub Copilot Responses paths require tool results to match prior tool calls.
76
76
  */
77
77
  strictResponsesPairing?: boolean;
78
78
  }
@@ -402,7 +402,9 @@ function createClient(
402
402
  }
403
403
 
404
404
  function buildParams(model: Model<"openai-responses">, context: Context, options?: OpenAIResponsesOptions) {
405
- const strictResponsesPairing = options?.strictResponsesPairing ?? isAzureOpenAIBaseUrl(model.baseUrl ?? "");
405
+ const strictResponsesPairing =
406
+ options?.strictResponsesPairing ??
407
+ (isAzureOpenAIBaseUrl(model.baseUrl ?? "") || model.provider === "github-copilot");
406
408
  const messages = convertMessages(model, context, strictResponsesPairing);
407
409
 
408
410
  const cacheRetention = resolveCacheRetention(options?.cacheRetention);
@@ -1,3 +1,4 @@
1
+ import * as http2 from "node:http2";
1
2
  import { create, fromBinary, toBinary } from "@bufbuild/protobuf";
2
3
  import { z } from "zod";
3
4
  import { getBundledModels } from "../../models";
@@ -5,7 +6,7 @@ import { GetUsableModelsRequestSchema, GetUsableModelsResponseSchema } from "../
5
6
  import type { Model } from "../../types";
6
7
 
7
8
  const CURSOR_DEFAULT_BASE_URL = "https://api2.cursor.sh";
8
- const CURSOR_DEFAULT_CLIENT_VERSION = "cli-2026.01.09-231024f";
9
+ const CURSOR_DEFAULT_CLIENT_VERSION = "cli-2026.02.13-41ac335";
9
10
  const CURSOR_GET_USABLE_MODELS_PATH = "/agent.v1.AgentService/GetUsableModels";
10
11
 
11
12
  const DEFAULT_CONTEXT_WINDOW = 200_000;
@@ -47,8 +48,6 @@ export interface CursorModelDiscoveryOptions {
47
48
  timeoutMs?: number;
48
49
  /** Optional list of custom Cursor model ids to include in request context. */
49
50
  customModelIds?: string[];
50
- /** Optional fetch implementation override for tests. */
51
- fetchImpl?: typeof fetch;
52
51
  }
53
52
 
54
53
  /**
@@ -60,34 +59,19 @@ export interface CursorModelDiscoveryOptions {
60
59
  export async function fetchCursorUsableModels(
61
60
  options: CursorModelDiscoveryOptions,
62
61
  ): Promise<Model<"cursor-agent">[] | null> {
63
- const fetchImpl = options.fetchImpl ?? fetch;
64
- const timeoutMs = options.timeoutMs ?? 15_000;
65
- const signal = AbortSignal.timeout(timeoutMs);
66
-
62
+ const timeoutMs = options.timeoutMs ?? 5_000;
67
63
  try {
68
64
  const requestPayload = create(GetUsableModelsRequestSchema, {
69
65
  customModelIds: normalizeCustomModelIds(options.customModelIds),
70
66
  });
71
- const response = await fetchImpl(buildCursorUrl(options.baseUrl), {
72
- method: "POST",
73
- headers: {
74
- "content-type": "application/connect+proto",
75
- "connect-protocol-version": "1",
76
- te: "trailers",
77
- authorization: `Bearer ${options.apiKey}`,
78
- "x-ghost-mode": "true",
79
- "x-cursor-client-version": options.clientVersion ?? CURSOR_DEFAULT_CLIENT_VERSION,
80
- "x-cursor-client-type": "cli",
81
- },
82
- body: encodeConnectUnaryMessage(toBinary(GetUsableModelsRequestSchema, requestPayload)),
83
- signal,
84
- });
67
+ const body = toBinary(GetUsableModelsRequestSchema, requestPayload);
68
+ const baseUrl = (options.baseUrl ?? CURSOR_DEFAULT_BASE_URL).replace(/\/+$/, "");
85
69
 
86
- if (!response.ok) {
70
+ const responseBuffer = await fetchViaHttp2(baseUrl, body, options, timeoutMs);
71
+
72
+ if (!responseBuffer) {
87
73
  return null;
88
74
  }
89
-
90
- const responseBuffer = new Uint8Array(await response.arrayBuffer());
91
75
  const decoded = decodeGetUsableModelsResponse(responseBuffer);
92
76
  const parsedDecoded = CursorDecodedResponseSchema.safeParse(decoded);
93
77
  if (!parsedDecoded.success) {
@@ -95,15 +79,76 @@ export async function fetchCursorUsableModels(
95
79
  }
96
80
 
97
81
  const references = createCursorReferenceMap();
98
-
99
82
  return normalizeCursorModels(parsedDecoded.data.models, options.baseUrl, references);
100
83
  } catch {
101
84
  return null;
102
85
  }
103
86
  }
104
87
 
105
- function buildCursorUrl(baseUrl?: string): string {
106
- return `${(baseUrl ?? CURSOR_DEFAULT_BASE_URL).replace(/\/+$/, "")}${CURSOR_GET_USABLE_MODELS_PATH}`;
88
+ function buildRequestHeaders(options: CursorModelDiscoveryOptions): Record<string, string> {
89
+ return {
90
+ "content-type": "application/proto",
91
+ te: "trailers",
92
+ authorization: `Bearer ${options.apiKey}`,
93
+ "x-ghost-mode": "true",
94
+ "x-cursor-client-version": options.clientVersion ?? CURSOR_DEFAULT_CLIENT_VERSION,
95
+ "x-cursor-client-type": "cli",
96
+ };
97
+ }
98
+
99
+ /** HTTP/2 transport required by Cursor API (HTTP/1.1 is rejected with 464). */
100
+ async function fetchViaHttp2(
101
+ baseUrl: string,
102
+ body: Uint8Array,
103
+ options: CursorModelDiscoveryOptions,
104
+ timeoutMs: number,
105
+ ): Promise<Uint8Array | null> {
106
+ const { promise, resolve } = Promise.withResolvers<Uint8Array | null>();
107
+ const client = http2.connect(baseUrl);
108
+ const timer = setTimeout(() => {
109
+ client.destroy();
110
+ resolve(null);
111
+ }, timeoutMs);
112
+
113
+ client.on("error", () => {
114
+ clearTimeout(timer);
115
+ resolve(null);
116
+ });
117
+
118
+ const req = client.request({
119
+ ":method": "POST",
120
+ ":path": CURSOR_GET_USABLE_MODELS_PATH,
121
+ ...buildRequestHeaders(options),
122
+ });
123
+
124
+ const chunks: Buffer[] = [];
125
+ req.on("data", (chunk: Buffer) => chunks.push(chunk));
126
+ req.on("end", () => {
127
+ clearTimeout(timer);
128
+ client.close();
129
+ resolve(new Uint8Array(Buffer.concat(chunks)));
130
+ });
131
+ req.on("error", () => {
132
+ clearTimeout(timer);
133
+ client.close();
134
+ resolve(null);
135
+ });
136
+ req.on("response", headers => {
137
+ const status = Number(headers[":status"] ?? 0);
138
+ if (status < 200 || status >= 300) {
139
+ clearTimeout(timer);
140
+ client.close();
141
+ resolve(null);
142
+ }
143
+ });
144
+
145
+ if (body.length > 0) {
146
+ req.end(Buffer.from(body));
147
+ } else {
148
+ req.end();
149
+ }
150
+
151
+ return promise;
107
152
  }
108
153
 
109
154
  function normalizeCustomModelIds(customModelIds: readonly string[] | undefined): string[] {
@@ -132,15 +177,6 @@ function createCursorReferenceMap(): Map<string, Model<"cursor-agent">> {
132
177
  return references;
133
178
  }
134
179
 
135
- function encodeConnectUnaryMessage(payload: Uint8Array): Uint8Array {
136
- const framed = new Uint8Array(5 + payload.length);
137
- framed[0] = 0;
138
- const view = new DataView(framed.buffer, framed.byteOffset, framed.byteLength);
139
- view.setUint32(1, payload.length, false);
140
- framed.set(payload, 5);
141
- return framed;
142
- }
143
-
144
180
  function decodeGetUsableModelsResponse(payload: Uint8Array) {
145
181
  if (payload.length === 0) {
146
182
  return null;