codex-multi-auth 2.17.3 → 2.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +10 -4
- package/config/README.md +1 -1
- package/config/codex-legacy.json +12 -212
- package/config/codex-modern.json +4 -80
- package/config/minimal-codex.json +1 -1
- package/dist/lib/context-budget/model-context-windows.d.ts +1 -1
- package/dist/lib/context-budget/model-context-windows.js +10 -13
- package/dist/lib/oc-chatgpt-target-detection.d.ts +3 -2
- package/dist/lib/oc-chatgpt-target-detection.js +40 -13
- package/dist/lib/request/error-classification.js +41 -52
- package/dist/lib/request/fetch-helpers.js +1 -1
- package/dist/lib/request/helpers/model-map.d.ts +2 -2
- package/dist/lib/request/helpers/model-map.js +120 -78
- package/dist/lib/request/request-transformer.d.ts +1 -1
- package/dist/lib/request/request-transformer.js +1 -1
- package/dist/lib/runtime/model-discovery-status.d.ts +2 -2
- package/dist/lib/ui/ui-copy.d.ts +1 -1
- package/dist/lib/ui/ui-copy.js +1 -1
- package/dist/lib/usage/pricing.d.ts +1 -1
- package/dist/lib/usage/pricing.js +41 -16
- package/package.json +1 -1
- package/scripts/codex.js +97 -82
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codex-multi-auth",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.18.0",
|
|
4
4
|
"description": "Install and operate codex-multi-auth for the official @openai/codex CLI with multi-account OAuth rotation, switching, health checks, and recovery tools.",
|
|
5
5
|
"interface": {
|
|
6
6
|
"composerIcon": "./assets/codex-multi-auth-icon.svg"
|
package/README.md
CHANGED
|
@@ -5,10 +5,14 @@
|
|
|
5
5
|
[](https://github.com/ndycode/codex-multi-auth/actions/workflows/ci.yml)
|
|
6
6
|
[](LICENSE)
|
|
7
7
|
|
|
8
|
+
<img width="1270" height="729" alt="codex-multi-auth terminal dashboard for Codex CLI multi-account OAuth account status" src="https://github.com/user-attachments/assets/0cecb77e-a6d3-432a-ba48-3577db0c7093" />
|
|
9
|
+
|
|
8
10
|
`codex-multi-auth` is a multi-account OAuth manager for the official `@openai/codex` CLI. It keeps a named pool of ChatGPT sign-ins on your machine, lets you switch the active account, and — when you run Codex through its optional wrapper — rotates accounts across live requests through a loopback-only proxy. It never installs or shadows a `codex` binary; the official OpenAI install keeps owning that command.
|
|
9
11
|
|
|
10
12
|
Use it when one Codex account is not enough: you hit rate limits or quota windows, you split work across organizations and workspaces, you want per-project account pools, or you run unattended agents that need JSON diagnostics and safe repair commands instead of one opaque auth file.
|
|
11
13
|
|
|
14
|
+
Using OpenCode rather than the Codex CLI? The sibling project [`oc-codex-multi-auth`](https://github.com/ndycode/oc-codex-multi-auth) is the plugin that manages the same kind of account pool there.
|
|
15
|
+
|
|
12
16
|
## What it does
|
|
13
17
|
|
|
14
18
|
- **Account pool** — OAuth login for multiple ChatGPT accounts, stored locally under `~/.codex/multi-auth` (files `0600`, directories `0700`), with per-project pools under `projects/<project-key>/`.
|
|
@@ -71,7 +75,7 @@ mcodex # same wrapper, shorter name
|
|
|
71
75
|
| Accounts | `login`, `list`, `status`, `switch <i>`, `unpin`, `workspace` | sign in, inspect the pool, pin or switch the active account, pick workspaces |
|
|
72
76
|
| Selection | `forecast`, `best`, `why-selected`, `check`, `limits`, `models` | preview, explain, and probe which account serves the next request |
|
|
73
77
|
| Runtime | `rotation status` `enable` `disable` `bind-app` `unbind-app` `reset-runtime` `reset-rate-limits` | inspect and control live rotation and the app bind |
|
|
74
|
-
| Repair | `fix`, `doctor`, `verify`, `verify-flagged`, `uninstall` | diagnose and repair storage, flagged accounts, and install residue |
|
|
78
|
+
| Repair | `fix`, `doctor`, `report`, `verify`, `verify-flagged`, `uninstall` | diagnose and repair storage, flagged accounts, and install residue; machine-readable health report |
|
|
75
79
|
| Governance | `usage`, `budget`, `account`, `monitor`, `history`, `resets` | usage ledger, budget limits, tags/weights/pause/drain, snapshots |
|
|
76
80
|
| Local clients | `bridge`, `integrations` | bearer tokens and client snippets for the loopback bridge |
|
|
77
81
|
| Config | `config explain` `template`, `init-config`, `debug bundle`, `features` | effective-config report, config templates, sanitized debug bundle |
|
|
@@ -81,7 +85,7 @@ Everyday examples:
|
|
|
81
85
|
```bash
|
|
82
86
|
codex-multi-auth switch 2 # pin account #2
|
|
83
87
|
codex-multi-auth report --live --json # full machine-readable health report
|
|
84
|
-
codex-multi-auth fix --live --model gpt-
|
|
88
|
+
codex-multi-auth fix --live --model gpt-6.1-sol # live repair probes with a chosen model
|
|
85
89
|
codex-multi-auth doctor --fix # diagnose and apply the safest fixes
|
|
86
90
|
codex-multi-auth usage --since 24h --by model # local usage ledger summary
|
|
87
91
|
codex-multi-auth rotation status # is live rotation enabled?
|
|
@@ -89,7 +93,7 @@ codex-multi-auth rotation status # is live rotation enabled?
|
|
|
89
93
|
|
|
90
94
|
## Runtime rotation, in one paragraph
|
|
91
95
|
|
|
92
|
-
With rotation on (the default), request-bearing wrapper commands — `exec`, `review`, `resume`, `fork`, `app`, and the bare TUI — route through a local proxy that picks the healthiest account per request, refreshes tokens as needed, and fails over across the pool on rate limits within a bounded retry budget. The proxy listens on loopback only, authenticates its own clients with a per-process token, forwards only Responses API
|
|
96
|
+
With rotation on (the default), request-bearing wrapper commands — `exec`, `review`, `resume`, `fork`, `app`, and the bare TUI — route through a local proxy that picks the healthiest account per request, refreshes tokens as needed, and fails over across the pool on rate limits within a bounded retry budget. The proxy listens on loopback only, authenticates its own clients with a per-process token, forwards only Responses API, model-discovery, image, and thread-goal calls, and never writes account emails or tokens to client headers or logs. Plain `codex` is never touched: rotation exists only inside `codex-multi-auth-codex`/`mcodex` sessions, or inside the packaged desktop app after an opt-in, reversible bind. Turn it off with `codex-multi-auth rotation disable` or `CODEX_MULTI_AUTH_RUNTIME_ROTATION_PROXY=0`.
|
|
93
97
|
|
|
94
98
|
## Where state lives
|
|
95
99
|
|
|
@@ -128,10 +132,12 @@ Common symptoms — wrong active account, OAuth callback port `1455` already bou
|
|
|
128
132
|
| [docs/faq.md](docs/faq.md) | Common questions |
|
|
129
133
|
| [docs/upgrade.md](docs/upgrade.md) | Version and legacy-package migration |
|
|
130
134
|
| [docs/privacy.md](docs/privacy.md) | Data handling and local storage behavior |
|
|
135
|
+
| [config/README.md](config/README.md) | Modern vs. legacy catalog templates |
|
|
136
|
+
| [CHANGELOG.md](CHANGELOG.md) | Release history (short version) |
|
|
131
137
|
|
|
132
138
|
## Release notes
|
|
133
139
|
|
|
134
|
-
- Current stable: [v2.
|
|
140
|
+
- Current stable: [v2.18.0](docs/releases/v2.18.0.md) — `npm i -g codex-multi-auth`
|
|
135
141
|
- Earlier stable lines: [v2.6.0](docs/releases/v2.6.0.md), [v2.5.0](docs/releases/v2.5.0.md)
|
|
136
142
|
- Full release archive: [docs/README.md#release-history](docs/README.md#release-history)
|
|
137
143
|
|
package/config/README.md
CHANGED
|
@@ -17,7 +17,7 @@ These files are optional model/provider templates for host/plugin configurations
|
|
|
17
17
|
|
|
18
18
|
## Defaults Included
|
|
19
19
|
|
|
20
|
-
- Current documented OpenAI/Codex model families: GPT-6
|
|
20
|
+
- Current documented OpenAI/Codex model families: GPT-6.1 Sol (`gpt-6.1-sol`, the default), GPT-6 Astra (`gpt-6-astra`), GPT-6 Sol (`gpt-6-sol`) and GPT-6 Luna (`gpt-6-luna`), then `gpt-5.6-sol`/`terra`/`luna`. Retired models (`gpt-5.5`/`gpt-5.5-pro`, `gpt-5.4*`, `gpt-5.3-codex` and older, plus the leaked `gpt-6-astra-aeon` slug) were removed from the picker; their ids still resolve to a replacement, see `docs/configuration.md`
|
|
21
21
|
- The GPT-6 entries carry `limit.context: 272000`, the `context_window` in the upstream Codex catalog. The GPT-5.6 entries still carry the pre-cut `372000` and were left alone here; change them only alongside a deliberate review, since the value feeds a picker rather than the context budget guard (which refuses to estimate either family)
|
|
22
22
|
- The Daybreak cyber models resolve at the code level but are deliberately absent from these templates, matching their hidden visibility in the upstream Codex picker
|
|
23
23
|
- `store: false`
|
package/config/codex-legacy.json
CHANGED
|
@@ -165,8 +165,8 @@
|
|
|
165
165
|
"store": false
|
|
166
166
|
}
|
|
167
167
|
},
|
|
168
|
-
"gpt-6-
|
|
169
|
-
"name": "GPT 6
|
|
168
|
+
"gpt-6.1-sol-low": {
|
|
169
|
+
"name": "GPT 6.1 Sol Low (OAuth)",
|
|
170
170
|
"limit": {
|
|
171
171
|
"context": 272000,
|
|
172
172
|
"output": 128000
|
|
@@ -190,8 +190,8 @@
|
|
|
190
190
|
"store": false
|
|
191
191
|
}
|
|
192
192
|
},
|
|
193
|
-
"gpt-6-
|
|
194
|
-
"name": "GPT 6
|
|
193
|
+
"gpt-6.1-sol-medium": {
|
|
194
|
+
"name": "GPT 6.1 Sol Medium (OAuth)",
|
|
195
195
|
"limit": {
|
|
196
196
|
"context": 272000,
|
|
197
197
|
"output": 128000
|
|
@@ -215,8 +215,8 @@
|
|
|
215
215
|
"store": false
|
|
216
216
|
}
|
|
217
217
|
},
|
|
218
|
-
"gpt-6-
|
|
219
|
-
"name": "GPT 6
|
|
218
|
+
"gpt-6.1-sol-high": {
|
|
219
|
+
"name": "GPT 6.1 Sol High (OAuth)",
|
|
220
220
|
"limit": {
|
|
221
221
|
"context": 272000,
|
|
222
222
|
"output": 128000
|
|
@@ -240,8 +240,8 @@
|
|
|
240
240
|
"store": false
|
|
241
241
|
}
|
|
242
242
|
},
|
|
243
|
-
"gpt-6-
|
|
244
|
-
"name": "GPT 6
|
|
243
|
+
"gpt-6.1-sol-xhigh": {
|
|
244
|
+
"name": "GPT 6.1 Sol Xhigh (OAuth)",
|
|
245
245
|
"limit": {
|
|
246
246
|
"context": 272000,
|
|
247
247
|
"output": 128000
|
|
@@ -265,8 +265,8 @@
|
|
|
265
265
|
"store": false
|
|
266
266
|
}
|
|
267
267
|
},
|
|
268
|
-
"gpt-6-
|
|
269
|
-
"name": "GPT 6
|
|
268
|
+
"gpt-6.1-sol-max": {
|
|
269
|
+
"name": "GPT 6.1 Sol Max (OAuth)",
|
|
270
270
|
"limit": {
|
|
271
271
|
"context": 272000,
|
|
272
272
|
"output": 128000
|
|
@@ -290,8 +290,8 @@
|
|
|
290
290
|
"store": false
|
|
291
291
|
}
|
|
292
292
|
},
|
|
293
|
-
"gpt-6-
|
|
294
|
-
"name": "GPT 6
|
|
293
|
+
"gpt-6.1-sol-ultra": {
|
|
294
|
+
"name": "GPT 6.1 Sol Ultra (OAuth)",
|
|
295
295
|
"limit": {
|
|
296
296
|
"context": 272000,
|
|
297
297
|
"output": 128000
|
|
@@ -1014,206 +1014,6 @@
|
|
|
1014
1014
|
],
|
|
1015
1015
|
"store": false
|
|
1016
1016
|
}
|
|
1017
|
-
},
|
|
1018
|
-
"gpt-5.5-none": {
|
|
1019
|
-
"name": "GPT 5.5 None (OAuth)",
|
|
1020
|
-
"limit": {
|
|
1021
|
-
"context": 272000,
|
|
1022
|
-
"output": 128000
|
|
1023
|
-
},
|
|
1024
|
-
"modalities": {
|
|
1025
|
-
"input": [
|
|
1026
|
-
"text",
|
|
1027
|
-
"image"
|
|
1028
|
-
],
|
|
1029
|
-
"output": [
|
|
1030
|
-
"text"
|
|
1031
|
-
]
|
|
1032
|
-
},
|
|
1033
|
-
"options": {
|
|
1034
|
-
"reasoningEffort": "none",
|
|
1035
|
-
"reasoningSummary": "auto",
|
|
1036
|
-
"textVerbosity": "medium",
|
|
1037
|
-
"include": [
|
|
1038
|
-
"reasoning.encrypted_content"
|
|
1039
|
-
],
|
|
1040
|
-
"store": false
|
|
1041
|
-
}
|
|
1042
|
-
},
|
|
1043
|
-
"gpt-5.5-low": {
|
|
1044
|
-
"name": "GPT 5.5 Low (OAuth)",
|
|
1045
|
-
"limit": {
|
|
1046
|
-
"context": 272000,
|
|
1047
|
-
"output": 128000
|
|
1048
|
-
},
|
|
1049
|
-
"modalities": {
|
|
1050
|
-
"input": [
|
|
1051
|
-
"text",
|
|
1052
|
-
"image"
|
|
1053
|
-
],
|
|
1054
|
-
"output": [
|
|
1055
|
-
"text"
|
|
1056
|
-
]
|
|
1057
|
-
},
|
|
1058
|
-
"options": {
|
|
1059
|
-
"reasoningEffort": "low",
|
|
1060
|
-
"reasoningSummary": "auto",
|
|
1061
|
-
"textVerbosity": "medium",
|
|
1062
|
-
"include": [
|
|
1063
|
-
"reasoning.encrypted_content"
|
|
1064
|
-
],
|
|
1065
|
-
"store": false
|
|
1066
|
-
}
|
|
1067
|
-
},
|
|
1068
|
-
"gpt-5.5-medium": {
|
|
1069
|
-
"name": "GPT 5.5 Medium (OAuth)",
|
|
1070
|
-
"limit": {
|
|
1071
|
-
"context": 272000,
|
|
1072
|
-
"output": 128000
|
|
1073
|
-
},
|
|
1074
|
-
"modalities": {
|
|
1075
|
-
"input": [
|
|
1076
|
-
"text",
|
|
1077
|
-
"image"
|
|
1078
|
-
],
|
|
1079
|
-
"output": [
|
|
1080
|
-
"text"
|
|
1081
|
-
]
|
|
1082
|
-
},
|
|
1083
|
-
"options": {
|
|
1084
|
-
"reasoningEffort": "medium",
|
|
1085
|
-
"reasoningSummary": "auto",
|
|
1086
|
-
"textVerbosity": "medium",
|
|
1087
|
-
"include": [
|
|
1088
|
-
"reasoning.encrypted_content"
|
|
1089
|
-
],
|
|
1090
|
-
"store": false
|
|
1091
|
-
}
|
|
1092
|
-
},
|
|
1093
|
-
"gpt-5.5-high": {
|
|
1094
|
-
"name": "GPT 5.5 High (OAuth)",
|
|
1095
|
-
"limit": {
|
|
1096
|
-
"context": 272000,
|
|
1097
|
-
"output": 128000
|
|
1098
|
-
},
|
|
1099
|
-
"modalities": {
|
|
1100
|
-
"input": [
|
|
1101
|
-
"text",
|
|
1102
|
-
"image"
|
|
1103
|
-
],
|
|
1104
|
-
"output": [
|
|
1105
|
-
"text"
|
|
1106
|
-
]
|
|
1107
|
-
},
|
|
1108
|
-
"options": {
|
|
1109
|
-
"reasoningEffort": "high",
|
|
1110
|
-
"reasoningSummary": "detailed",
|
|
1111
|
-
"textVerbosity": "medium",
|
|
1112
|
-
"include": [
|
|
1113
|
-
"reasoning.encrypted_content"
|
|
1114
|
-
],
|
|
1115
|
-
"store": false
|
|
1116
|
-
}
|
|
1117
|
-
},
|
|
1118
|
-
"gpt-5.5-xhigh": {
|
|
1119
|
-
"name": "GPT 5.5 Extra High (OAuth)",
|
|
1120
|
-
"limit": {
|
|
1121
|
-
"context": 272000,
|
|
1122
|
-
"output": 128000
|
|
1123
|
-
},
|
|
1124
|
-
"modalities": {
|
|
1125
|
-
"input": [
|
|
1126
|
-
"text",
|
|
1127
|
-
"image"
|
|
1128
|
-
],
|
|
1129
|
-
"output": [
|
|
1130
|
-
"text"
|
|
1131
|
-
]
|
|
1132
|
-
},
|
|
1133
|
-
"options": {
|
|
1134
|
-
"reasoningEffort": "xhigh",
|
|
1135
|
-
"reasoningSummary": "detailed",
|
|
1136
|
-
"textVerbosity": "medium",
|
|
1137
|
-
"include": [
|
|
1138
|
-
"reasoning.encrypted_content"
|
|
1139
|
-
],
|
|
1140
|
-
"store": false
|
|
1141
|
-
}
|
|
1142
|
-
},
|
|
1143
|
-
"gpt-5.5-pro-medium": {
|
|
1144
|
-
"name": "GPT 5.5 Pro Medium (OAuth)",
|
|
1145
|
-
"limit": {
|
|
1146
|
-
"context": 272000,
|
|
1147
|
-
"output": 128000
|
|
1148
|
-
},
|
|
1149
|
-
"modalities": {
|
|
1150
|
-
"input": [
|
|
1151
|
-
"text",
|
|
1152
|
-
"image"
|
|
1153
|
-
],
|
|
1154
|
-
"output": [
|
|
1155
|
-
"text"
|
|
1156
|
-
]
|
|
1157
|
-
},
|
|
1158
|
-
"options": {
|
|
1159
|
-
"reasoningEffort": "medium",
|
|
1160
|
-
"reasoningSummary": "detailed",
|
|
1161
|
-
"textVerbosity": "medium",
|
|
1162
|
-
"include": [
|
|
1163
|
-
"reasoning.encrypted_content"
|
|
1164
|
-
],
|
|
1165
|
-
"store": false
|
|
1166
|
-
}
|
|
1167
|
-
},
|
|
1168
|
-
"gpt-5.5-pro-high": {
|
|
1169
|
-
"name": "GPT 5.5 Pro High (OAuth)",
|
|
1170
|
-
"limit": {
|
|
1171
|
-
"context": 272000,
|
|
1172
|
-
"output": 128000
|
|
1173
|
-
},
|
|
1174
|
-
"modalities": {
|
|
1175
|
-
"input": [
|
|
1176
|
-
"text",
|
|
1177
|
-
"image"
|
|
1178
|
-
],
|
|
1179
|
-
"output": [
|
|
1180
|
-
"text"
|
|
1181
|
-
]
|
|
1182
|
-
},
|
|
1183
|
-
"options": {
|
|
1184
|
-
"reasoningEffort": "high",
|
|
1185
|
-
"reasoningSummary": "detailed",
|
|
1186
|
-
"textVerbosity": "medium",
|
|
1187
|
-
"include": [
|
|
1188
|
-
"reasoning.encrypted_content"
|
|
1189
|
-
],
|
|
1190
|
-
"store": false
|
|
1191
|
-
}
|
|
1192
|
-
},
|
|
1193
|
-
"gpt-5.5-pro-xhigh": {
|
|
1194
|
-
"name": "GPT 5.5 Pro Extra High (OAuth)",
|
|
1195
|
-
"limit": {
|
|
1196
|
-
"context": 272000,
|
|
1197
|
-
"output": 128000
|
|
1198
|
-
},
|
|
1199
|
-
"modalities": {
|
|
1200
|
-
"input": [
|
|
1201
|
-
"text",
|
|
1202
|
-
"image"
|
|
1203
|
-
],
|
|
1204
|
-
"output": [
|
|
1205
|
-
"text"
|
|
1206
|
-
]
|
|
1207
|
-
},
|
|
1208
|
-
"options": {
|
|
1209
|
-
"reasoningEffort": "xhigh",
|
|
1210
|
-
"reasoningSummary": "detailed",
|
|
1211
|
-
"textVerbosity": "medium",
|
|
1212
|
-
"include": [
|
|
1213
|
-
"reasoning.encrypted_content"
|
|
1214
|
-
],
|
|
1215
|
-
"store": false
|
|
1216
|
-
}
|
|
1217
1017
|
}
|
|
1218
1018
|
}
|
|
1219
1019
|
}
|
package/config/codex-modern.json
CHANGED
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
"store": false
|
|
16
16
|
},
|
|
17
17
|
"models": {
|
|
18
|
-
"gpt-6-
|
|
19
|
-
"name": "GPT 6
|
|
18
|
+
"gpt-6.1-sol": {
|
|
19
|
+
"name": "GPT 6.1 Sol (OAuth)",
|
|
20
20
|
"limit": {
|
|
21
21
|
"context": 272000,
|
|
22
22
|
"output": 128000
|
|
@@ -63,8 +63,8 @@
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
},
|
|
66
|
-
"gpt-6-astra
|
|
67
|
-
"name": "GPT 6 Astra
|
|
66
|
+
"gpt-6-astra": {
|
|
67
|
+
"name": "GPT 6 Astra (OAuth)",
|
|
68
68
|
"limit": {
|
|
69
69
|
"context": 272000,
|
|
70
70
|
"output": 128000
|
|
@@ -340,82 +340,6 @@
|
|
|
340
340
|
"textVerbosity": "medium"
|
|
341
341
|
}
|
|
342
342
|
}
|
|
343
|
-
},
|
|
344
|
-
"gpt-5.5": {
|
|
345
|
-
"name": "GPT 5.5 (OAuth)",
|
|
346
|
-
"limit": {
|
|
347
|
-
"context": 272000,
|
|
348
|
-
"output": 128000
|
|
349
|
-
},
|
|
350
|
-
"modalities": {
|
|
351
|
-
"input": [
|
|
352
|
-
"text",
|
|
353
|
-
"image"
|
|
354
|
-
],
|
|
355
|
-
"output": [
|
|
356
|
-
"text"
|
|
357
|
-
]
|
|
358
|
-
},
|
|
359
|
-
"variants": {
|
|
360
|
-
"none": {
|
|
361
|
-
"reasoningEffort": "none",
|
|
362
|
-
"reasoningSummary": "auto",
|
|
363
|
-
"textVerbosity": "medium"
|
|
364
|
-
},
|
|
365
|
-
"low": {
|
|
366
|
-
"reasoningEffort": "low",
|
|
367
|
-
"reasoningSummary": "auto",
|
|
368
|
-
"textVerbosity": "medium"
|
|
369
|
-
},
|
|
370
|
-
"medium": {
|
|
371
|
-
"reasoningEffort": "medium",
|
|
372
|
-
"reasoningSummary": "auto",
|
|
373
|
-
"textVerbosity": "medium"
|
|
374
|
-
},
|
|
375
|
-
"high": {
|
|
376
|
-
"reasoningEffort": "high",
|
|
377
|
-
"reasoningSummary": "detailed",
|
|
378
|
-
"textVerbosity": "medium"
|
|
379
|
-
},
|
|
380
|
-
"xhigh": {
|
|
381
|
-
"reasoningEffort": "xhigh",
|
|
382
|
-
"reasoningSummary": "detailed",
|
|
383
|
-
"textVerbosity": "medium"
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
},
|
|
387
|
-
"gpt-5.5-pro": {
|
|
388
|
-
"name": "GPT 5.5 Pro (OAuth)",
|
|
389
|
-
"limit": {
|
|
390
|
-
"context": 272000,
|
|
391
|
-
"output": 128000
|
|
392
|
-
},
|
|
393
|
-
"modalities": {
|
|
394
|
-
"input": [
|
|
395
|
-
"text",
|
|
396
|
-
"image"
|
|
397
|
-
],
|
|
398
|
-
"output": [
|
|
399
|
-
"text"
|
|
400
|
-
]
|
|
401
|
-
},
|
|
402
|
-
"variants": {
|
|
403
|
-
"medium": {
|
|
404
|
-
"reasoningEffort": "medium",
|
|
405
|
-
"reasoningSummary": "detailed",
|
|
406
|
-
"textVerbosity": "medium"
|
|
407
|
-
},
|
|
408
|
-
"high": {
|
|
409
|
-
"reasoningEffort": "high",
|
|
410
|
-
"reasoningSummary": "detailed",
|
|
411
|
-
"textVerbosity": "medium"
|
|
412
|
-
},
|
|
413
|
-
"xhigh": {
|
|
414
|
-
"reasoningEffort": "xhigh",
|
|
415
|
-
"reasoningSummary": "detailed",
|
|
416
|
-
"textVerbosity": "medium"
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
343
|
}
|
|
420
344
|
}
|
|
421
345
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* behavior (see the v2.5.0 release notes) closely enough to launch that no
|
|
7
7
|
* estimate here has been reviewed for it yet.
|
|
8
8
|
*/
|
|
9
|
-
export declare const UNESTIMATED_ROUTABLE_MODELS: readonly ["gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna", "gpt-6-astra", "gpt-6-
|
|
9
|
+
export declare const UNESTIMATED_ROUTABLE_MODELS: readonly ["gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna", "gpt-6-astra", "gpt-6-sol", "gpt-6-luna", "gpt-6.1-sol", "gpt-daybreak-blue-latest", "gpt-daybreak-red-latest"];
|
|
10
10
|
export interface EffectiveContextWindow {
|
|
11
11
|
tokens: number;
|
|
12
12
|
source: "override" | "estimate";
|
|
@@ -23,14 +23,11 @@ import { getNormalizedModel } from "../request/helpers/model-map.js";
|
|
|
23
23
|
* it to UNESTIMATED_ROUTABLE_MODELS instead.
|
|
24
24
|
*/
|
|
25
25
|
//
|
|
26
|
-
// Retired models (`gpt-5.1` through `gpt-5.
|
|
27
|
-
// models) are deliberately absent. Their ids now route to a
|
|
28
|
-
// estimating the window from the retired name would
|
|
29
|
-
// a model it no longer runs on.
|
|
30
|
-
const ESTIMATED_MODEL_CONTEXT_WINDOWS = {
|
|
31
|
-
"gpt-5.5": 260_000,
|
|
32
|
-
"gpt-5.5-pro": 260_000,
|
|
33
|
-
};
|
|
26
|
+
// Retired models (`gpt-5.1` through `gpt-5.5-pro`, `gpt-5-mini`/`nano`, the
|
|
27
|
+
// codex models) are deliberately absent. Their ids now route to a
|
|
28
|
+
// replacement, and estimating the window from the retired name would
|
|
29
|
+
// evaluate a request against a model it no longer runs on.
|
|
30
|
+
const ESTIMATED_MODEL_CONTEXT_WINDOWS = {};
|
|
34
31
|
/**
|
|
35
32
|
* Routable models this guard consciously does not estimate a window for.
|
|
36
33
|
* `getEffectiveContextWindow` returns `null` for these absent an override,
|
|
@@ -52,11 +49,11 @@ export const UNESTIMATED_ROUTABLE_MODELS = [
|
|
|
52
49
|
// measured ceiling for this transport, so it stays unestimated too. Set
|
|
53
50
|
// `contextBudgetGuardModelWindowOverrides` once you know your real ceiling.
|
|
54
51
|
"gpt-6-astra",
|
|
55
|
-
|
|
56
|
-
//
|
|
57
|
-
// catalog as Astra, so the same reasoning keeps them unestimated.
|
|
52
|
+
// Sol, Luna and 6.1 Sol carry the same 272K Codex / 872K max split in the
|
|
53
|
+
// upstream catalog as Astra, so the same reasoning keeps them unestimated.
|
|
58
54
|
"gpt-6-sol",
|
|
59
55
|
"gpt-6-luna",
|
|
56
|
+
"gpt-6.1-sol",
|
|
60
57
|
"gpt-daybreak-blue-latest",
|
|
61
58
|
"gpt-daybreak-red-latest",
|
|
62
59
|
];
|
|
@@ -79,8 +76,8 @@ function normalizeModelName(model) {
|
|
|
79
76
|
* the way they type the model still wins, then the catalog's canonical id for
|
|
80
77
|
* it. `getNormalizedModel` is deliberately the exact/alias-only resolver —
|
|
81
78
|
* `resolveNormalizedModel` falls back to `DEFAULT_MODEL` for anything it does
|
|
82
|
-
* not recognize, which would hand an unknown model
|
|
83
|
-
* evaluate a real session against a fabricated number.
|
|
79
|
+
* not recognize, which would hand an unknown model the default model's
|
|
80
|
+
* window and evaluate a real session against a fabricated number.
|
|
84
81
|
*/
|
|
85
82
|
function windowLookupCandidates(model) {
|
|
86
83
|
const raw = normalizeModelName(model);
|
|
@@ -35,7 +35,8 @@ export type OcChatgptTargetDetectionResult = OcChatgptTargetFound | OcChatgptTar
|
|
|
35
35
|
/**
|
|
36
36
|
* Detects the oc-chatgpt multi-auth storage target by evaluating explicit, canonical, and per-project candidate roots.
|
|
37
37
|
*
|
|
38
|
-
* Examines an explicit override (
|
|
38
|
+
* Examines an explicit override (OC_CODEX_MULTI_AUTH_DIR, the legacy OC_CHATGPT_MULTI_AUTH_DIR alias, or
|
|
39
|
+
* options.explicitRoot), the canonical user store (~/.opencode),
|
|
39
40
|
* and a per-project storage location (derived from options.projectRoot or the current working directory). For each candidate
|
|
40
41
|
* it checks for account artifacts and storage signals and returns a single resolved target, an ambiguity listing multiple
|
|
41
42
|
* matching candidates, or a "none" result with the attempted candidates. This function performs synchronous filesystem checks
|
|
@@ -45,7 +46,7 @@ export type OcChatgptTargetDetectionResult = OcChatgptTargetFound | OcChatgptTar
|
|
|
45
46
|
*
|
|
46
47
|
* @param options - Optional overrides:
|
|
47
48
|
* - explicitRoot: absolute path to force as the candidate root (use `null` to explicitly disable); if omitted the
|
|
48
|
-
*
|
|
49
|
+
* OC_CODEX_MULTI_AUTH_DIR environment variable is considered, then the legacy OC_CHATGPT_MULTI_AUTH_DIR alias.
|
|
49
50
|
* - projectRoot: explicit project root to derive per-project storage; if omitted the current working directory is used to
|
|
50
51
|
* discover the project root.
|
|
51
52
|
* @returns An OcChatgptTargetDetectionResult describing either a resolved `target` (with `descriptor` and a `resolution`
|
|
@@ -2,7 +2,14 @@ import { existsSync, readdirSync } from "node:fs";
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join, normalize, relative, resolve, sep, win32 } from "node:path";
|
|
4
4
|
import { findProjectRoot, getProjectStorageKey, resolveProjectStorageIdentityRoot, } from "./storage/paths.js";
|
|
5
|
-
|
|
5
|
+
// The sibling plugin renamed its account file from `openai-codex-accounts.json`
|
|
6
|
+
// (oc-chatgpt-multi-auth era) to `oc-codex-multi-auth-accounts.json`; both are
|
|
7
|
+
// detected, preferring the current name when a root holds both.
|
|
8
|
+
const ACCOUNT_FILE_NAMES = [
|
|
9
|
+
"oc-codex-multi-auth-accounts.json",
|
|
10
|
+
"openai-codex-accounts.json",
|
|
11
|
+
];
|
|
12
|
+
const ACCOUNT_FILE_NAME = ACCOUNT_FILE_NAMES[0];
|
|
6
13
|
const BACKUPS_DIR_NAME = "backups";
|
|
7
14
|
const PROJECTS_DIR_NAME = "projects";
|
|
8
15
|
const CANONICAL_HOME_BASENAME = ".opencode";
|
|
@@ -107,17 +114,32 @@ function deduplicatePaths(paths) {
|
|
|
107
114
|
}
|
|
108
115
|
return result;
|
|
109
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* Returns the path of the primary account file under `root`, preferring the
|
|
119
|
+
* current `oc-codex-multi-auth-accounts.json` name over the legacy
|
|
120
|
+
* `openai-codex-accounts.json` name when both exist, or `null` when neither
|
|
121
|
+
* file (nor its `.wal` sidecar) is present.
|
|
122
|
+
*/
|
|
123
|
+
function findPrimaryAccountPath(root) {
|
|
124
|
+
for (const name of ACCOUNT_FILE_NAMES) {
|
|
125
|
+
const accountPath = join(root, name);
|
|
126
|
+
if (existsSync(accountPath) || existsSync(`${accountPath}.wal`)) {
|
|
127
|
+
return accountPath;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
110
132
|
/**
|
|
111
133
|
* Detects whether an account file or rotated account artifacts exist under the specified storage root.
|
|
112
134
|
*
|
|
113
|
-
* Scans for
|
|
135
|
+
* Scans for an account file under either known name (`oc-codex-multi-auth-accounts.json` or the legacy `openai-codex-accounts.json`) and its WAL variant, rotated/archived files matching either account filename pattern (excluding `.tmp`, `.wal`, and names containing `.rotate.`), and the backups directory. The probe is tolerant of unreadable directories (errors are ignored) and does not read file contents. Callers should be aware of concurrent filesystem changes — a `false` result does not guarantee no artifact will appear shortly after. On Windows, filesystem matching should be considered case-insensitive by callers. This check does not expose or parse any token contents.
|
|
114
136
|
*
|
|
115
137
|
* @param root - Filesystem path of the storage root to probe
|
|
138
|
+
* @param primaryAccountPath - Result of `findPrimaryAccountPath(root)`, so callers resolve the descriptor path once
|
|
116
139
|
* @returns `true` if any account file or rotated account artifact exists under `root` or its backups directory, `false` otherwise.
|
|
117
140
|
*/
|
|
118
|
-
function hasAccountArtifacts(root) {
|
|
119
|
-
|
|
120
|
-
if (existsSync(accountPath) || existsSync(`${accountPath}.wal`)) {
|
|
141
|
+
function hasAccountArtifacts(root, primaryAccountPath) {
|
|
142
|
+
if (primaryAccountPath !== null) {
|
|
121
143
|
return true;
|
|
122
144
|
}
|
|
123
145
|
const hasRotated = (dir) => {
|
|
@@ -126,7 +148,7 @@ function hasAccountArtifacts(root) {
|
|
|
126
148
|
for (const entry of entries) {
|
|
127
149
|
if (!entry.isFile())
|
|
128
150
|
continue;
|
|
129
|
-
if (!entry.name.startsWith(`${
|
|
151
|
+
if (!ACCOUNT_FILE_NAMES.some((name) => entry.name.startsWith(`${name}.`)))
|
|
130
152
|
continue;
|
|
131
153
|
if (entry.name.endsWith(".tmp"))
|
|
132
154
|
continue;
|
|
@@ -146,7 +168,7 @@ function hasAccountArtifacts(root) {
|
|
|
146
168
|
return true;
|
|
147
169
|
}
|
|
148
170
|
const backupsDir = join(root, BACKUPS_DIR_NAME);
|
|
149
|
-
if (existsSync(join(backupsDir,
|
|
171
|
+
if (ACCOUNT_FILE_NAMES.some((name) => existsSync(join(backupsDir, name)))) {
|
|
150
172
|
return true;
|
|
151
173
|
}
|
|
152
174
|
if (hasRotated(backupsDir)) {
|
|
@@ -191,7 +213,8 @@ function inferScopeFromRoot(root, canonicalRoot) {
|
|
|
191
213
|
/**
|
|
192
214
|
* Detects the oc-chatgpt multi-auth storage target by evaluating explicit, canonical, and per-project candidate roots.
|
|
193
215
|
*
|
|
194
|
-
* Examines an explicit override (
|
|
216
|
+
* Examines an explicit override (OC_CODEX_MULTI_AUTH_DIR, the legacy OC_CHATGPT_MULTI_AUTH_DIR alias, or
|
|
217
|
+
* options.explicitRoot), the canonical user store (~/.opencode),
|
|
195
218
|
* and a per-project storage location (derived from options.projectRoot or the current working directory). For each candidate
|
|
196
219
|
* it checks for account artifacts and storage signals and returns a single resolved target, an ambiguity listing multiple
|
|
197
220
|
* matching candidates, or a "none" result with the attempted candidates. This function performs synchronous filesystem checks
|
|
@@ -201,14 +224,17 @@ function inferScopeFromRoot(root, canonicalRoot) {
|
|
|
201
224
|
*
|
|
202
225
|
* @param options - Optional overrides:
|
|
203
226
|
* - explicitRoot: absolute path to force as the candidate root (use `null` to explicitly disable); if omitted the
|
|
204
|
-
*
|
|
227
|
+
* OC_CODEX_MULTI_AUTH_DIR environment variable is considered, then the legacy OC_CHATGPT_MULTI_AUTH_DIR alias.
|
|
205
228
|
* - projectRoot: explicit project root to derive per-project storage; if omitted the current working directory is used to
|
|
206
229
|
* discover the project root.
|
|
207
230
|
* @returns An OcChatgptTargetDetectionResult describing either a resolved `target` (with `descriptor` and a `resolution`
|
|
208
231
|
* of `"accounts"` or `"signals"`), an `ambiguous` outcome listing conflicting candidates, or `none` with the tried candidates.
|
|
209
232
|
*/
|
|
210
233
|
export function detectOcChatgptMultiAuthTarget(options) {
|
|
211
|
-
const explicitFromEnv = (
|
|
234
|
+
const explicitFromEnv = (firstNonEmpty([
|
|
235
|
+
process.env.OC_CODEX_MULTI_AUTH_DIR,
|
|
236
|
+
process.env.OC_CHATGPT_MULTI_AUTH_DIR,
|
|
237
|
+
]) ?? "").trim();
|
|
212
238
|
const hasExplicitRootOption = options !== undefined && "explicitRoot" in options;
|
|
213
239
|
const explicitRoot = (hasExplicitRootOption ? (options.explicitRoot ?? "") : explicitFromEnv).trim();
|
|
214
240
|
const userHome = getResolvedUserHomeDir();
|
|
@@ -233,9 +259,10 @@ export function detectOcChatgptMultiAuthTarget(options) {
|
|
|
233
259
|
: inferredScope === "project"
|
|
234
260
|
? "project"
|
|
235
261
|
: "default-global";
|
|
236
|
-
const
|
|
262
|
+
const primaryAccountPath = findPrimaryAccountPath(root);
|
|
263
|
+
const accountPath = primaryAccountPath ?? join(root, ACCOUNT_FILE_NAME);
|
|
237
264
|
const backupRoot = join(root, BACKUPS_DIR_NAME);
|
|
238
|
-
const hasAccountArtifactsFlag = hasAccountArtifacts(root);
|
|
265
|
+
const hasAccountArtifactsFlag = hasAccountArtifacts(root, primaryAccountPath);
|
|
239
266
|
return {
|
|
240
267
|
scope: inferredScope,
|
|
241
268
|
source,
|
|
@@ -314,7 +341,7 @@ export function detectOcChatgptMultiAuthTarget(options) {
|
|
|
314
341
|
}
|
|
315
342
|
return {
|
|
316
343
|
kind: "none",
|
|
317
|
-
reason: "No oc-chatgpt-multi-auth target root found; create ~/.opencode or supply OC_CHATGPT_MULTI_AUTH_DIR.",
|
|
344
|
+
reason: "No oc-chatgpt-multi-auth target root found; create ~/.opencode or supply OC_CODEX_MULTI_AUTH_DIR (legacy OC_CHATGPT_MULTI_AUTH_DIR is still accepted).",
|
|
318
345
|
tried: candidates.map(({ scope, source, root, accountPath, backupRoot }) => ({
|
|
319
346
|
scope,
|
|
320
347
|
source,
|