oc-chatgpt-multi-auth 5.4.6 → 5.4.7

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/config/README.md CHANGED
@@ -6,8 +6,8 @@ This directory contains the official OpenCode config templates for the ChatGPT C
6
6
 
7
7
  | File | OpenCode version | Description |
8
8
  |------|------------------|-------------|
9
- | [`opencode-modern.json`](./opencode-modern.json) | **v1.0.210+** | Variant-based config: 7 base models with 26 total presets |
10
- | [`opencode-legacy.json`](./opencode-legacy.json) | **v1.0.209 and below** | Legacy explicit entries: 26 individual model definitions |
9
+ | [`opencode-modern.json`](./opencode-modern.json) | **v1.0.210+** | Variant-based config: 9 base models with 34 total presets |
10
+ | [`opencode-legacy.json`](./opencode-legacy.json) | **v1.0.209 and below** | Legacy explicit entries: 34 individual model definitions |
11
11
 
12
12
  ## Quick pick
13
13
 
@@ -34,16 +34,16 @@ opencode --version
34
34
  OpenCode v1.0.210+ added model `variants`, so one model entry can expose multiple reasoning levels. That keeps modern config much smaller while preserving the same effective presets.
35
35
 
36
36
  Both templates include:
37
- - GPT-5.4, GPT-5.4 Mini, GPT-5 Codex, GPT-5.1, GPT-5.1 Codex, GPT-5.1 Codex Max, GPT-5.1 Codex Mini
37
+ - GPT-5.4, GPT-5.4 Pro, GPT-5.4 Mini, GPT-5.4 Nano, GPT-5 Codex, GPT-5.1, GPT-5.1 Codex, GPT-5.1 Codex Max, GPT-5.1 Codex Mini
38
38
  - Reasoning variants per model family
39
39
  - `store: false` and `include: ["reasoning.encrypted_content"]`
40
- - Context metadata (`gpt-5.4*`: 1,000,000 context / 128,000 output; other shipped models: 272,000 / 128,000)
40
+ - Context metadata (`gpt-5.4`/`gpt-5.4-pro`: 1,050,000; `gpt-5.4-mini`/`gpt-5.4-nano`/Codex models: 400,000; `gpt-5.1`: 272,000; all output: 128,000)
41
41
 
42
42
  Use `opencode debug config` to verify that these template entries were merged into your effective config. `opencode models openai` currently shows OpenCode's built-in provider catalog and can omit config-defined entries such as `gpt-5.4-mini`.
43
43
 
44
44
  If your OpenCode runtime supports global compaction tuning, you can also set:
45
- - `model_context_window = 1000000`
46
- - `model_auto_compact_token_limit = 900000`
45
+ - `model_context_window = 1050000`
46
+ - `model_auto_compact_token_limit = 950000`
47
47
 
48
48
  ## Spark model note
49
49
 
@@ -18,7 +18,7 @@
18
18
  "gpt-5.4-none": {
19
19
  "name": "GPT 5.4 None (OAuth)",
20
20
  "limit": {
21
- "context": 1000000,
21
+ "context": 1050000,
22
22
  "output": 128000
23
23
  },
24
24
  "modalities": {
@@ -43,7 +43,7 @@
43
43
  "gpt-5.4-low": {
44
44
  "name": "GPT 5.4 Low (OAuth)",
45
45
  "limit": {
46
- "context": 1000000,
46
+ "context": 1050000,
47
47
  "output": 128000
48
48
  },
49
49
  "modalities": {
@@ -68,7 +68,7 @@
68
68
  "gpt-5.4-medium": {
69
69
  "name": "GPT 5.4 Medium (OAuth)",
70
70
  "limit": {
71
- "context": 1000000,
71
+ "context": 1050000,
72
72
  "output": 128000
73
73
  },
74
74
  "modalities": {
@@ -93,7 +93,7 @@
93
93
  "gpt-5.4-high": {
94
94
  "name": "GPT 5.4 High (OAuth)",
95
95
  "limit": {
96
- "context": 1000000,
96
+ "context": 1050000,
97
97
  "output": 128000
98
98
  },
99
99
  "modalities": {
@@ -118,7 +118,7 @@
118
118
  "gpt-5.4-xhigh": {
119
119
  "name": "GPT 5.4 Extra High (OAuth)",
120
120
  "limit": {
121
- "context": 1000000,
121
+ "context": 1050000,
122
122
  "output": 128000
123
123
  },
124
124
  "modalities": {
@@ -143,7 +143,7 @@
143
143
  "gpt-5.4-mini-none": {
144
144
  "name": "GPT 5.4 Mini None (OAuth)",
145
145
  "limit": {
146
- "context": 1000000,
146
+ "context": 400000,
147
147
  "output": 128000
148
148
  },
149
149
  "modalities": {
@@ -168,7 +168,7 @@
168
168
  "gpt-5.4-mini-low": {
169
169
  "name": "GPT 5.4 Mini Low (OAuth)",
170
170
  "limit": {
171
- "context": 1000000,
171
+ "context": 400000,
172
172
  "output": 128000
173
173
  },
174
174
  "modalities": {
@@ -193,7 +193,7 @@
193
193
  "gpt-5.4-mini-medium": {
194
194
  "name": "GPT 5.4 Mini Medium (OAuth)",
195
195
  "limit": {
196
- "context": 1000000,
196
+ "context": 400000,
197
197
  "output": 128000
198
198
  },
199
199
  "modalities": {
@@ -218,7 +218,7 @@
218
218
  "gpt-5.4-mini-high": {
219
219
  "name": "GPT 5.4 Mini High (OAuth)",
220
220
  "limit": {
221
- "context": 1000000,
221
+ "context": 400000,
222
222
  "output": 128000
223
223
  },
224
224
  "modalities": {
@@ -243,7 +243,207 @@
243
243
  "gpt-5.4-mini-xhigh": {
244
244
  "name": "GPT 5.4 Mini Extra High (OAuth)",
245
245
  "limit": {
246
- "context": 1000000,
246
+ "context": 400000,
247
+ "output": 128000
248
+ },
249
+ "modalities": {
250
+ "input": [
251
+ "text",
252
+ "image"
253
+ ],
254
+ "output": [
255
+ "text"
256
+ ]
257
+ },
258
+ "options": {
259
+ "reasoningEffort": "xhigh",
260
+ "reasoningSummary": "detailed",
261
+ "textVerbosity": "medium",
262
+ "include": [
263
+ "reasoning.encrypted_content"
264
+ ],
265
+ "store": false
266
+ }
267
+ },
268
+ "gpt-5.4-pro-medium": {
269
+ "name": "GPT 5.4 Pro Medium (OAuth)",
270
+ "limit": {
271
+ "context": 1050000,
272
+ "output": 128000
273
+ },
274
+ "modalities": {
275
+ "input": [
276
+ "text",
277
+ "image"
278
+ ],
279
+ "output": [
280
+ "text"
281
+ ]
282
+ },
283
+ "options": {
284
+ "reasoningEffort": "medium",
285
+ "reasoningSummary": "detailed",
286
+ "textVerbosity": "medium",
287
+ "include": [
288
+ "reasoning.encrypted_content"
289
+ ],
290
+ "store": false
291
+ }
292
+ },
293
+ "gpt-5.4-pro-high": {
294
+ "name": "GPT 5.4 Pro High (OAuth)",
295
+ "limit": {
296
+ "context": 1050000,
297
+ "output": 128000
298
+ },
299
+ "modalities": {
300
+ "input": [
301
+ "text",
302
+ "image"
303
+ ],
304
+ "output": [
305
+ "text"
306
+ ]
307
+ },
308
+ "options": {
309
+ "reasoningEffort": "high",
310
+ "reasoningSummary": "detailed",
311
+ "textVerbosity": "medium",
312
+ "include": [
313
+ "reasoning.encrypted_content"
314
+ ],
315
+ "store": false
316
+ }
317
+ },
318
+ "gpt-5.4-pro-xhigh": {
319
+ "name": "GPT 5.4 Pro Extra High (OAuth)",
320
+ "limit": {
321
+ "context": 1050000,
322
+ "output": 128000
323
+ },
324
+ "modalities": {
325
+ "input": [
326
+ "text",
327
+ "image"
328
+ ],
329
+ "output": [
330
+ "text"
331
+ ]
332
+ },
333
+ "options": {
334
+ "reasoningEffort": "xhigh",
335
+ "reasoningSummary": "detailed",
336
+ "textVerbosity": "medium",
337
+ "include": [
338
+ "reasoning.encrypted_content"
339
+ ],
340
+ "store": false
341
+ }
342
+ },
343
+ "gpt-5.4-nano-none": {
344
+ "name": "GPT 5.4 Nano None (OAuth)",
345
+ "limit": {
346
+ "context": 400000,
347
+ "output": 128000
348
+ },
349
+ "modalities": {
350
+ "input": [
351
+ "text",
352
+ "image"
353
+ ],
354
+ "output": [
355
+ "text"
356
+ ]
357
+ },
358
+ "options": {
359
+ "reasoningEffort": "none",
360
+ "reasoningSummary": "auto",
361
+ "textVerbosity": "medium",
362
+ "include": [
363
+ "reasoning.encrypted_content"
364
+ ],
365
+ "store": false
366
+ }
367
+ },
368
+ "gpt-5.4-nano-low": {
369
+ "name": "GPT 5.4 Nano Low (OAuth)",
370
+ "limit": {
371
+ "context": 400000,
372
+ "output": 128000
373
+ },
374
+ "modalities": {
375
+ "input": [
376
+ "text",
377
+ "image"
378
+ ],
379
+ "output": [
380
+ "text"
381
+ ]
382
+ },
383
+ "options": {
384
+ "reasoningEffort": "low",
385
+ "reasoningSummary": "auto",
386
+ "textVerbosity": "medium",
387
+ "include": [
388
+ "reasoning.encrypted_content"
389
+ ],
390
+ "store": false
391
+ }
392
+ },
393
+ "gpt-5.4-nano-medium": {
394
+ "name": "GPT 5.4 Nano Medium (OAuth)",
395
+ "limit": {
396
+ "context": 400000,
397
+ "output": 128000
398
+ },
399
+ "modalities": {
400
+ "input": [
401
+ "text",
402
+ "image"
403
+ ],
404
+ "output": [
405
+ "text"
406
+ ]
407
+ },
408
+ "options": {
409
+ "reasoningEffort": "medium",
410
+ "reasoningSummary": "auto",
411
+ "textVerbosity": "medium",
412
+ "include": [
413
+ "reasoning.encrypted_content"
414
+ ],
415
+ "store": false
416
+ }
417
+ },
418
+ "gpt-5.4-nano-high": {
419
+ "name": "GPT 5.4 Nano High (OAuth)",
420
+ "limit": {
421
+ "context": 400000,
422
+ "output": 128000
423
+ },
424
+ "modalities": {
425
+ "input": [
426
+ "text",
427
+ "image"
428
+ ],
429
+ "output": [
430
+ "text"
431
+ ]
432
+ },
433
+ "options": {
434
+ "reasoningEffort": "high",
435
+ "reasoningSummary": "detailed",
436
+ "textVerbosity": "medium",
437
+ "include": [
438
+ "reasoning.encrypted_content"
439
+ ],
440
+ "store": false
441
+ }
442
+ },
443
+ "gpt-5.4-nano-xhigh": {
444
+ "name": "GPT 5.4 Nano Extra High (OAuth)",
445
+ "limit": {
446
+ "context": 400000,
247
447
  "output": 128000
248
448
  },
249
449
  "modalities": {
@@ -268,7 +468,7 @@
268
468
  "gpt-5.1-codex-max-low": {
269
469
  "name": "GPT 5.1 Codex Max Low (OAuth)",
270
470
  "limit": {
271
- "context": 272000,
471
+ "context": 400000,
272
472
  "output": 128000
273
473
  },
274
474
  "modalities": {
@@ -293,7 +493,7 @@
293
493
  "gpt-5.1-codex-max-medium": {
294
494
  "name": "GPT 5.1 Codex Max Medium (OAuth)",
295
495
  "limit": {
296
- "context": 272000,
496
+ "context": 400000,
297
497
  "output": 128000
298
498
  },
299
499
  "modalities": {
@@ -318,7 +518,7 @@
318
518
  "gpt-5.1-codex-max-high": {
319
519
  "name": "GPT 5.1 Codex Max High (OAuth)",
320
520
  "limit": {
321
- "context": 272000,
521
+ "context": 400000,
322
522
  "output": 128000
323
523
  },
324
524
  "modalities": {
@@ -343,7 +543,7 @@
343
543
  "gpt-5.1-codex-max-xhigh": {
344
544
  "name": "GPT 5.1 Codex Max Extra High (OAuth)",
345
545
  "limit": {
346
- "context": 272000,
546
+ "context": 400000,
347
547
  "output": 128000
348
548
  },
349
549
  "modalities": {
@@ -368,7 +568,7 @@
368
568
  "gpt-5.1-codex-low": {
369
569
  "name": "GPT 5.1 Codex Low (OAuth)",
370
570
  "limit": {
371
- "context": 272000,
571
+ "context": 400000,
372
572
  "output": 128000
373
573
  },
374
574
  "modalities": {
@@ -393,7 +593,7 @@
393
593
  "gpt-5.1-codex-medium": {
394
594
  "name": "GPT 5.1 Codex Medium (OAuth)",
395
595
  "limit": {
396
- "context": 272000,
596
+ "context": 400000,
397
597
  "output": 128000
398
598
  },
399
599
  "modalities": {
@@ -418,7 +618,7 @@
418
618
  "gpt-5.1-codex-high": {
419
619
  "name": "GPT 5.1 Codex High (OAuth)",
420
620
  "limit": {
421
- "context": 272000,
621
+ "context": 400000,
422
622
  "output": 128000
423
623
  },
424
624
  "modalities": {
@@ -443,7 +643,7 @@
443
643
  "gpt-5.1-codex-mini-medium": {
444
644
  "name": "GPT 5.1 Codex Mini Medium (OAuth)",
445
645
  "limit": {
446
- "context": 272000,
646
+ "context": 400000,
447
647
  "output": 128000
448
648
  },
449
649
  "modalities": {
@@ -468,7 +668,7 @@
468
668
  "gpt-5.1-codex-mini-high": {
469
669
  "name": "GPT 5.1 Codex Mini High (OAuth)",
470
670
  "limit": {
471
- "context": 272000,
671
+ "context": 400000,
472
672
  "output": 128000
473
673
  },
474
674
  "modalities": {
@@ -593,7 +793,7 @@
593
793
  "gpt-5-codex-low": {
594
794
  "name": "GPT 5 Codex Low (OAuth)",
595
795
  "limit": {
596
- "context": 272000,
796
+ "context": 400000,
597
797
  "output": 128000
598
798
  },
599
799
  "modalities": {
@@ -618,7 +818,7 @@
618
818
  "gpt-5-codex-medium": {
619
819
  "name": "GPT 5 Codex Medium (OAuth)",
620
820
  "limit": {
621
- "context": 272000,
821
+ "context": 400000,
622
822
  "output": 128000
623
823
  },
624
824
  "modalities": {
@@ -643,7 +843,7 @@
643
843
  "gpt-5-codex-high": {
644
844
  "name": "GPT 5 Codex High (OAuth)",
645
845
  "limit": {
646
- "context": 272000,
846
+ "context": 400000,
647
847
  "output": 128000
648
848
  },
649
849
  "modalities": {
@@ -18,7 +18,7 @@
18
18
  "gpt-5.4": {
19
19
  "name": "GPT 5.4 (OAuth)",
20
20
  "limit": {
21
- "context": 1000000,
21
+ "context": 1050000,
22
22
  "output": 128000
23
23
  },
24
24
  "modalities": {
@@ -58,10 +58,86 @@
58
58
  }
59
59
  }
60
60
  },
61
+ "gpt-5.4-pro": {
62
+ "name": "GPT 5.4 Pro (OAuth)",
63
+ "limit": {
64
+ "context": 1050000,
65
+ "output": 128000
66
+ },
67
+ "modalities": {
68
+ "input": [
69
+ "text",
70
+ "image"
71
+ ],
72
+ "output": [
73
+ "text"
74
+ ]
75
+ },
76
+ "variants": {
77
+ "medium": {
78
+ "reasoningEffort": "medium",
79
+ "reasoningSummary": "detailed",
80
+ "textVerbosity": "medium"
81
+ },
82
+ "high": {
83
+ "reasoningEffort": "high",
84
+ "reasoningSummary": "detailed",
85
+ "textVerbosity": "medium"
86
+ },
87
+ "xhigh": {
88
+ "reasoningEffort": "xhigh",
89
+ "reasoningSummary": "detailed",
90
+ "textVerbosity": "medium"
91
+ }
92
+ }
93
+ },
61
94
  "gpt-5.4-mini": {
62
95
  "name": "GPT 5.4 Mini (OAuth)",
63
96
  "limit": {
64
- "context": 1000000,
97
+ "context": 400000,
98
+ "output": 128000
99
+ },
100
+ "modalities": {
101
+ "input": [
102
+ "text",
103
+ "image"
104
+ ],
105
+ "output": [
106
+ "text"
107
+ ]
108
+ },
109
+ "variants": {
110
+ "none": {
111
+ "reasoningEffort": "none",
112
+ "reasoningSummary": "auto",
113
+ "textVerbosity": "medium"
114
+ },
115
+ "low": {
116
+ "reasoningEffort": "low",
117
+ "reasoningSummary": "auto",
118
+ "textVerbosity": "medium"
119
+ },
120
+ "medium": {
121
+ "reasoningEffort": "medium",
122
+ "reasoningSummary": "auto",
123
+ "textVerbosity": "medium"
124
+ },
125
+ "high": {
126
+ "reasoningEffort": "high",
127
+ "reasoningSummary": "detailed",
128
+ "textVerbosity": "medium"
129
+ },
130
+ "xhigh": {
131
+ "reasoningEffort": "xhigh",
132
+ "reasoningSummary": "detailed",
133
+ "textVerbosity": "medium"
134
+ }
135
+ }
136
+ },
137
+ "gpt-5.4-nano": {
138
+ "name": "GPT 5.4 Nano (OAuth)",
139
+ "limit": {
140
+ "context": 400000,
65
141
  "output": 128000
66
142
  },
67
143
  "modalities": {
@@ -104,7 +180,7 @@
104
180
  "gpt-5.1-codex-max": {
105
181
  "name": "GPT 5.1 Codex Max (OAuth)",
106
182
  "limit": {
107
- "context": 272000,
183
+ "context": 400000,
108
184
  "output": 128000
109
185
  },
110
186
  "modalities": {
@@ -142,7 +218,7 @@
142
218
  "gpt-5.1-codex": {
143
219
  "name": "GPT 5.1 Codex (OAuth)",
144
220
  "limit": {
145
- "context": 272000,
221
+ "context": 400000,
146
222
  "output": 128000
147
223
  },
148
224
  "modalities": {
@@ -175,7 +251,7 @@
175
251
  "gpt-5.1-codex-mini": {
176
252
  "name": "GPT 5.1 Codex Mini (OAuth)",
177
253
  "limit": {
178
- "context": 272000,
254
+ "context": 400000,
179
255
  "output": 128000
180
256
  },
181
257
  "modalities": {
@@ -241,7 +317,7 @@
241
317
  "gpt-5-codex": {
242
318
  "name": "GPT 5 Codex (OAuth)",
243
319
  "limit": {
244
- "context": 272000,
320
+ "context": 400000,
245
321
  "output": 128000
246
322
  },
247
323
  "modalities": {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AA4M/D;;;;;;;;;;;;;;;GAeG;AAEH,eAAO,MAAM,iBAAiB,EAAE,MAsxL/B,CAAC;AAEF,eAAO,MAAM,gBAAgB,QAAoB,CAAC;AAElD,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AA6L/D;;;;;;;;;;;;;;;GAeG;AAEH,eAAO,MAAM,iBAAiB,EAAE,MA2zL/B,CAAC;AAEF,eAAO,MAAM,gBAAgB,QAAoB,CAAC;AAElD,eAAe,iBAAiB,CAAC"}
package/dist/index.js CHANGED
@@ -34,7 +34,7 @@ import { initLogger, logRequest, logDebug, logInfo, logWarn, logError, setCorrel
34
34
  import { checkAndNotify } from "./lib/auto-update-checker.js";
35
35
  import { handleContextOverflow } from "./lib/context-overflow.js";
36
36
  import { AccountManager, getAccountIdCandidates, extractAccountEmail, extractAccountId, formatAccountLabel, formatCooldown, formatWaitTime, sanitizeEmail, selectBestAccountCandidate, shouldUpdateAccountIdFromToken, resolveRequestAccountId, parseRateLimitReason, lookupCodexCliTokensByEmail, } from "./lib/accounts.js";
37
- import { getStoragePath, loadAccounts, saveAccounts, withAccountStorageTransaction, clearAccounts, setStoragePath, exportAccounts, importAccounts, previewImportAccounts, createTimestampedBackupPath, loadFlaggedAccounts, saveFlaggedAccounts, withFlaggedAccountStorageTransaction, clearFlaggedAccounts, StorageError, formatStorageErrorHint, } from "./lib/storage.js";
37
+ import { getStoragePath, loadAccounts, saveAccounts, withAccountStorageTransaction, clearAccounts, setStoragePath, exportAccounts, importAccounts, previewImportAccounts, createTimestampedBackupPath, loadFlaggedAccounts, saveFlaggedAccounts, withFlaggedAccountStorageTransaction, clearFlaggedAccounts, getWorkspaceIdentityKey, StorageError, formatStorageErrorHint, } from "./lib/storage.js";
38
38
  import { createCodexHeaders, extractRequestUrl, handleErrorResponse, handleSuccessResponse, isDeactivatedWorkspaceError, getUnsupportedCodexModelInfo, resolveUnsupportedCodexFallbackModel, refreshAndUpdateToken, rewriteUrlForCodex, shouldRefreshToken, transformRequestForCodex, } from "./lib/request/fetch-helpers.js";
39
39
  import { applyFastSessionDefaults } from "./lib/request/request-transformer.js";
40
40
  import { getRateLimitBackoff, RATE_LIMIT_SHORT_RETRY_THRESHOLD_MS, resetRateLimitBackoff, } from "./lib/request/rate-limit-backoff.js";
@@ -44,23 +44,10 @@ import { addJitter } from "./lib/rotation.js";
44
44
  import { buildTableHeader, buildTableRow } from "./lib/table-formatter.js";
45
45
  import { setUiRuntimeOptions } from "./lib/ui/runtime.js";
46
46
  import { paintUiText, formatUiBadge, formatUiHeader, formatUiItem, formatUiKeyValue, formatUiSection } from "./lib/ui/format.js";
47
- import { buildBeginnerChecklist, buildBeginnerDoctorFindings, recommendBeginnerNextAction, summarizeBeginnerAccounts, } from "./lib/ui/beginner.js";
47
+ import { buildBeginnerChecklist, buildBeginnerDoctorFindings, formatPromptCacheSnapshot, recommendBeginnerNextAction, summarizeBeginnerAccounts, } from "./lib/ui/beginner.js";
48
48
  import { getModelFamily, getCodexInstructions, MODEL_FAMILIES, prewarmCodexInstructions, } from "./lib/prompts/codex.js";
49
49
  import { prewarmOpenCodeCodexPrompt } from "./lib/prompts/opencode-codex.js";
50
50
  import { createSessionRecoveryHook, isRecoverableError, detectErrorType, getRecoveryToastContent, } from "./lib/recovery.js";
51
- function getWorkspaceIdentityKey(account) {
52
- const organizationId = account.organizationId?.trim();
53
- const accountId = account.accountId?.trim();
54
- const refreshToken = account.refreshToken.trim();
55
- if (organizationId) {
56
- return accountId
57
- ? `organizationId:${organizationId}|accountId:${accountId}`
58
- : `organizationId:${organizationId}`;
59
- }
60
- if (accountId)
61
- return `accountId:${accountId}`;
62
- return `refreshToken:${refreshToken}`;
63
- }
64
51
  function matchesWorkspaceIdentity(account, identityKey) {
65
52
  return getWorkspaceIdentityKey(account) === identityKey;
66
53
  }
@@ -128,6 +115,9 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
128
115
  lastRequestAt: null,
129
116
  lastError: null,
130
117
  lastErrorCategory: null,
118
+ promptCacheEnabledRequests: 0,
119
+ promptCacheMissingRequests: 0,
120
+ lastPromptCacheKey: null,
131
121
  lastSelectedAccountIndex: null,
132
122
  lastQuotaKey: null,
133
123
  lastSelectionSnapshot: null,
@@ -985,6 +975,9 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
985
975
  serverErrors: runtimeMetrics.serverErrors,
986
976
  networkErrors: runtimeMetrics.networkErrors,
987
977
  lastErrorCategory: runtimeMetrics.lastErrorCategory,
978
+ promptCacheEnabledRequests: runtimeMetrics.promptCacheEnabledRequests,
979
+ promptCacheMissingRequests: runtimeMetrics.promptCacheMissingRequests,
980
+ lastPromptCacheKey: runtimeMetrics.lastPromptCacheKey,
988
981
  });
989
982
  const formatDoctorSeverity = (ui, severity) => {
990
983
  if (severity === "ok")
@@ -1505,6 +1498,13 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
1505
1498
  .trim() || undefined;
1506
1499
  const requestCorrelationId = setCorrelationId(threadIdCandidate ? `${threadIdCandidate}:${Date.now()}` : undefined);
1507
1500
  runtimeMetrics.lastRequestAt = Date.now();
1501
+ runtimeMetrics.lastPromptCacheKey = promptCacheKey ?? null;
1502
+ if (promptCacheKey) {
1503
+ runtimeMetrics.promptCacheEnabledRequests++;
1504
+ }
1505
+ else {
1506
+ runtimeMetrics.promptCacheMissingRequests++;
1507
+ }
1508
1508
  const retryBudget = new RetryBudgetTracker(retryBudgetLimits);
1509
1509
  const consumeRetryBudget = (bucket, reason) => {
1510
1510
  if (retryBudget.consume(bucket)) {
@@ -1707,6 +1707,10 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
1707
1707
  abortSignal.addEventListener("abort", onUserAbort, { once: true });
1708
1708
  }
1709
1709
  try {
1710
+ // Request metrics are tracked at the fetch boundary, so retries and
1711
+ // account rotation are counted consistently. These increments are
1712
+ // in-memory only and run on Node's single-threaded event loop, so no
1713
+ // filesystem locking or token-redaction concerns are introduced here.
1710
1714
  runtimeMetrics.totalRequests++;
1711
1715
  response = await fetch(url, {
1712
1716
  ...requestInit,
@@ -1715,6 +1719,13 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
1715
1719
  });
1716
1720
  }
1717
1721
  catch (networkError) {
1722
+ if (abortSignal?.aborted && fetchController.signal.aborted) {
1723
+ accountManager.refundToken(account, modelFamily, model);
1724
+ if (networkError instanceof Error) {
1725
+ throw networkError;
1726
+ }
1727
+ throw new Error(String(networkError));
1728
+ }
1718
1729
  const errorMsg = networkError instanceof Error ? networkError.message : String(networkError);
1719
1730
  logWarn(`Network error for account ${account.index + 1}: ${errorMsg}`);
1720
1731
  if (!consumeRetryBudget("network", `Network error on account ${account.index + 1}: ${errorMsg}`)) {
@@ -4054,6 +4065,7 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
4054
4065
  lines.push(...formatUiSection(ui, "Technical snapshot"));
4055
4066
  lines.push(formatUiKeyValue(ui, "Storage", getStoragePath(), "muted"));
4056
4067
  lines.push(formatUiKeyValue(ui, "Runtime failures", `failed=${runtime.failedRequests}, rateLimited=${runtime.rateLimitedResponses}, authRefreshFailed=${runtime.authRefreshFailures}, server=${runtime.serverErrors}, network=${runtime.networkErrors}`, "muted"));
4068
+ lines.push(formatUiKeyValue(ui, "Prompt cache", formatPromptCacheSnapshot(runtime), "muted"));
4057
4069
  }
4058
4070
  return lines.join("\n");
4059
4071
  }
@@ -4090,6 +4102,7 @@ export const OpenAIOAuthPlugin = async ({ client }) => {
4090
4102
  lines.push("Technical snapshot:");
4091
4103
  lines.push(` Storage: ${getStoragePath()}`);
4092
4104
  lines.push(` Runtime failures: failed=${runtime.failedRequests}, rateLimited=${runtime.rateLimitedResponses}, authRefreshFailed=${runtime.authRefreshFailures}, server=${runtime.serverErrors}, network=${runtime.networkErrors}`);
4105
+ lines.push(` Prompt cache: ${formatPromptCacheSnapshot(runtime)}`);
4093
4106
  }
4094
4107
  return lines.join("\n");
4095
4108
  },