Skip to content

Commit 0c5e603

Browse files
committed
fix(openai): clarify auth routes in picker and docs
1 parent 2b6e08b commit 0c5e603

4 files changed

Lines changed: 96 additions & 0 deletions

File tree

docs/help/faq.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,31 @@ for usage/billing and raise limits as needed.
657657
OpenClaw supports **OpenAI Code (Codex)** via OAuth (ChatGPT sign-in). Onboarding can run the OAuth flow and will set the default model to `openai-codex/gpt-5.4` when appropriate. See [Model providers](/concepts/model-providers) and [Onboarding (CLI)](/start/wizard).
658658
</Accordion>
659659

660+
<Accordion title="Why does ChatGPT GPT-5.4 not unlock openai/gpt-5.4 in OpenClaw?">
661+
OpenClaw treats the two routes separately:
662+
663+
- `openai-codex/gpt-5.4` = ChatGPT/Codex OAuth
664+
- `openai/gpt-5.4` = direct OpenAI Platform API
665+
666+
In OpenClaw, ChatGPT/Codex sign-in is wired to the `openai-codex/*` route,
667+
not the direct `openai/*` route. If you want the direct API path in
668+
OpenClaw, set `OPENAI_API_KEY` (or the equivalent OpenAI provider config).
669+
If you want ChatGPT/Codex sign-in in OpenClaw, use `openai-codex/*`.
670+
671+
</Accordion>
672+
673+
<Accordion title="Why can Codex OAuth limits differ from ChatGPT web?">
674+
`openai-codex/*` uses the Codex OAuth route, and its usable quota windows are
675+
OpenAI-managed and plan-dependent. In practice, those limits can differ from
676+
the ChatGPT website/app experience, even when both are tied to the same account.
677+
678+
OpenClaw can show the currently visible provider usage/quota windows in
679+
`openclaw models status`, but it does not invent or normalize ChatGPT-web
680+
entitlements into direct API access. If you want the direct OpenAI Platform
681+
billing/limit path, use `openai/*` with an API key.
682+
683+
</Accordion>
684+
660685
<Accordion title="Do you support OpenAI subscription auth (Codex OAuth)?">
661686
Yes. OpenClaw fully supports **OpenAI Code (Codex) subscription OAuth**.
662687
OpenAI explicitly allows subscription OAuth usage in external tools/workflows

docs/providers/openai.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,12 @@ openclaw config set plugins.entries.openai.config.personality off
8282
**Best for:** direct API access and usage-based billing.
8383
Get your API key from the OpenAI dashboard.
8484

85+
Route summary:
86+
87+
- `openai/gpt-5.4` = direct OpenAI Platform API route
88+
- Requires `OPENAI_API_KEY` (or equivalent OpenAI provider config)
89+
- In OpenClaw, ChatGPT/Codex sign-in is routed through `openai-codex/*`, not `openai/*`
90+
8591
### CLI setup
8692

8793
```bash
@@ -172,6 +178,12 @@ parameters, provider selection, and failover behavior.
172178
**Best for:** using ChatGPT/Codex subscription access instead of an API key.
173179
Codex cloud requires ChatGPT sign-in, while the Codex CLI supports ChatGPT or API key sign-in.
174180

181+
Route summary:
182+
183+
- `openai-codex/gpt-5.4` = ChatGPT/Codex OAuth route
184+
- Uses ChatGPT/Codex sign-in, not a direct OpenAI Platform API key
185+
- Provider-side limits for `openai-codex/*` can differ from the ChatGPT web/app experience
186+
175187
### CLI setup (Codex OAuth)
176188

177189
```bash
@@ -193,6 +205,10 @@ openclaw models auth login --provider openai-codex
193205
OpenAI's current Codex docs list `gpt-5.4` as the current Codex model. OpenClaw
194206
maps that to `openai-codex/gpt-5.4` for ChatGPT/Codex OAuth usage.
195207

208+
This route is intentionally separate from `openai/gpt-5.4`. If you want the
209+
direct OpenAI Platform API path, use `openai/*` with an API key. If you want
210+
ChatGPT/Codex sign-in, use `openai-codex/*`.
211+
196212
If onboarding reuses an existing Codex CLI login, those credentials stay
197213
managed by Codex CLI. On expiry, OpenClaw re-reads the external Codex source
198214
first and, when the provider can refresh it, writes the refreshed credential

src/commands/model-picker.test.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,46 @@ beforeEach(() => {
8888
});
8989

9090
describe("promptDefaultModel", () => {
91+
it("adds auth-route hints for OpenAI API and Codex OAuth models", async () => {
92+
loadModelCatalog.mockResolvedValue([
93+
{
94+
provider: "openai",
95+
id: "gpt-5.4",
96+
name: "GPT-5.4",
97+
},
98+
{
99+
provider: "openai-codex",
100+
id: "gpt-5.4",
101+
name: "GPT-5.4",
102+
},
103+
]);
104+
105+
const select = vi.fn(async (params) => params.initialValue as never);
106+
const prompter = makePrompter({ select });
107+
108+
await promptDefaultModel({
109+
config: { agents: { defaults: {} } } as OpenClawConfig,
110+
prompter,
111+
allowKeep: false,
112+
includeManual: false,
113+
ignoreAllowlist: true,
114+
});
115+
116+
const options = select.mock.calls[0]?.[0]?.options ?? [];
117+
expect(options).toEqual(
118+
expect.arrayContaining([
119+
expect.objectContaining({
120+
value: "openai/gpt-5.4",
121+
hint: expect.stringContaining("API key route"),
122+
}),
123+
expect.objectContaining({
124+
value: "openai-codex/gpt-5.4",
125+
hint: expect.stringContaining("ChatGPT OAuth route"),
126+
}),
127+
]),
128+
);
129+
});
130+
91131
it("treats byteplus plan models as preferred-provider matches", async () => {
92132
loadModelCatalog.mockResolvedValue([
93133
{

src/flows/model-picker.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,17 @@ function normalizeModelKeys(values: string[]): string[] {
115115
return next;
116116
}
117117

118+
function resolveModelRouteHint(provider: string): string | undefined {
119+
const normalized = normalizeProviderId(provider);
120+
if (normalized === "openai") {
121+
return "API key route";
122+
}
123+
if (normalized === "openai-codex") {
124+
return "ChatGPT OAuth route";
125+
}
126+
return undefined;
127+
}
128+
118129
function addModelSelectOption(params: {
119130
entry: {
120131
provider: string;
@@ -146,6 +157,10 @@ function addModelSelectOption(params: {
146157
if (aliases?.length) {
147158
hints.push(`alias: ${aliases.join(", ")}`);
148159
}
160+
const routeHint = resolveModelRouteHint(params.entry.provider);
161+
if (routeHint) {
162+
hints.push(routeHint);
163+
}
149164
if (!params.hasAuth(params.entry.provider)) {
150165
hints.push("auth missing");
151166
}

0 commit comments

Comments
 (0)