- Home
- Plugins
- Models & Providers
- dsh-oauth-openai
dsh-oauth-openai
ekincn/dsh-oauth-openai
OpenAI Codex OAuth provider and model adapter for dsh-oauth and DeepSeek Harness
Install
dsh plugin --profile web add github:ekincn/dsh-oauth-openaiREADME
dsh-oauth-openai
中文 | English
OpenAI Codex OAuth provider for DeepSeek Harness: sign in to ChatGPT through dsh-oauth, register the openai-codex model route, expose an editable model catalog, and correct the one request field the ChatGPT Codex backend refuses. The whole integration installs as external third-party bundles — no app rebuild or replacement.
Responsibility boundary
dsh-oauth: account page, login sessions, secret storage, refresh locking, and logout.dsh-oauth-openai: the OpenAI Codex OAuth protocol, account parsing, refresh, the model adapter, and the model-catalog settings page.- It never copies Codex CLI's
auth.json, and it never treats a ChatGPT subscription token as an OpenAI Platform API key.
Features
- ChatGPT sign-in: browser PKCE callback when the local
1455port is reachable, otherwise device code; credentials live in the Harness credential store and refresh automatically. openai-codexmodel route: pi-ai'sopenai-codex-responsesprotocol, over the installed catalog or custom model rows (id, display name, context window, output cap, input modalities).- Editable model catalog: in the plugin's settings page. With no saved override the route inherits pi-ai's installed Codex catalog; a saved list replaces it wholesale and can be reset.
- Codex parameter compatibility fix (see below).
Install (third-party, external)
Requires DeepSeek Harness 0.2.x (verified on the official desktop 0.2.0-rc.2).
Two tarballs ship in dist/, installed in order:
| Package | Contents |
|---|---|
dist/ekin_chen-dsh-oauth-0.1.2.tgz | @ekin_chen/dsh-oauth — the account foundation (code identical to upstream dsh-oauth@0.1.1; manifest adapted for 0.2.x and republished under our own scope, see VENDORED.md) |
dist/ekin_chen-dsh-oauth-openai-0.2.3.tgz | This plugin (@ekin_chen/dsh-oauth-openai) |
dsh plugin --profile desktop add /abs/path/dist/ekin_chen-dsh-oauth-0.1.2.tgz
dsh plugin --profile desktop add /abs/path/dist/ekin_chen-dsh-oauth-openai-0.2.3.tgz
Naming: the npm names
dsh-oauth/dsh-oauth-openaibelong to a third party (ruihuahe, MIT). This stack is republished under our own scope@ekin_chen/*with attribution (THIRD_PARTY_NOTICES). Registry install:dsh plugin --profile desktop add @ekin_chen/dsh-oauth-openai(@ekin_chen/dsh-oauthcomes along as its dependency).
add selects each bundle automatically; restart the app when the profile has no HMR.
Publishing (maintainers): npm publish dist/ekin_chen-dsh-oauth-0.1.2.tgz --access public, then npm publish dist/ekin_chen-dsh-oauth-openai-0.2.3.tgz --access public (scoped packages default to private). Never touch the third-party dsh-oauth/dsh-oauth-openai names.
Rebuild from source:
pnpm install
pnpm test
pnpm run build
pnpm run pack:check
node scripts/vendor-dsh-oauth.mjs dist # regenerate the dsh-oauth external package
pnpm run buildclearsdist/; runpack:checkfirst, thenvendor-dsh-oauth.
Usage
- Settings → OpenAI Codex: sign in (browser / device code), account status and sign-out, and the model-catalog editor (add/remove rows, adopt rows from the installed catalog, save, reset).
- Pick
openai-codex/<model id>in the model selector; custom models appear there too.
The temperature problem (Unsupported parameter: temperature)
Symptom. On the openai-codex route the experimental Auto review classifies every pending tool call with temperature: 0 (upstream packages/experimental/auto-review, classifyRisk). The ChatGPT Codex backend rejects the temperature field, so the request fails with PI_AI_ERROR: Codex error: Unsupported parameter: temperature and the tool call is blocked.
Fix. Two stripping layers, both confined to Codex-bound traffic and neither changing the call config recorded in session logs:
- Adapter layer —
OpenAICodexAdapter.stream()dropstemperaturebefore pi-ai sees the request (a loop-assembled request keeps its loop identity on the copy). llm/streamwaterfall layer —codexTemperatureListenerre-dispatches atemperature-free copy through the same waterfall. This layer keeps working even whilellm-pi-ai's configured profile still owns the route (see below), so Auto review and any othertemperature-carrying call succeed.
Toggle: stripRequestTemperature (default true).
Evidence (scripts/smoke-request.mjs, real stack against the real backend, A/B):
strip=true finish=stop text="pong" # fix on: succeeds
strip=false finish=error "Codex error: Unsupported parameter: temperature" # fix off: reproduces the bug
Host constraint (0.2.x)
On 0.2.x runtimes connection.rpc.handle cannot register custom channels: its registration path reads owner.webServer, which the Cordis inject rules reject (cannot get property "webServer" without inject), so requests fall through to the SPA static layer and get HTTP 405. Every third-party plugin using that API hits this (for example the tailscale-serve settings toggle). This plugin therefore serves its control channel as exact Fetch routes on the shared /api channel (connection.fetch.register), verified over real HTTP: 401 unauthenticated, standard server-response envelopes once admitted.
Relationship with the built-in llm-pi-ai route
The route and the Models-page directory entry are first-come registrations:
- If the profile's
cordis.patch.ymlconfiguresllm-pi-ai.providers.openai-codex, the built-in adapter keeps serving the route. This plugin backs off (logging a migration hint) while thellm/streamlayer still fixestemperature. - To let this plugin serve the route (its accounts and catalog), delete the
llm-pi-aiproviders.openai-codexsection and keep the model rows in Settings → OpenAI Codex, then sign in once on that page. - The native Models-page card for
openai-codexeditsllm-pi-ai's section; this plugin's catalog lives in its own settings page. Do not mix the two.
Configuration reference
- id: llm-openai-codex
config:
loginMethod: auto # auto | browser | device-code
authorizationTimeoutMs: 900000
streamIdleTimeoutMs: 300000
stripRequestTemperature: true
maxRequestImageBytes: 20971520
models: # omitted = inherit installed catalog; list = full replacement
- id: gpt-5.6-luna
name: GPT-5.6 Luna
contextWindow: 272000
maxTokens: 128000 # an explicit value also becomes the request default cap
input: [text, image] # unknown ids inherit the first image-capable installed model
Compatibility and dependency policy
@deepseek-ai/dsh-*peer ranges are>=0.1.0-rc.6 <0.3.0, which the plugin compatibility gate (semver.satisfies(runtime, range, { includePrerelease: true })) accepts on 0.2.x.- Every peer is
optional: the host runtime supplies same-generation copies through the Loader's interception, so pnpm never vendors duplicate@deepseek-ai/*,pi-ai, ordsh-oauthcopies into the profile. - The
@earendil-works/pi-aicoupling is^0.87.1(the version the 0.2.0-rc.2 desktop ships).
Development and verification
pnpm test # temperature fix (both layers), catalog resolution, composition, RPC contract, config validation
pnpm run typecheck
node scripts/smoke-request.mjs # real request (needs a Codex login on this machine)
node scripts/smoke-request.mjs --no-strip # control run: should reproduce the original error
License
MIT. Third-party components are listed in THIRD_PARTY_NOTICES.md.
Related plugins
dsh-routing-suite
yjh051108/dsh-routing-suite
dsh-our-free-model
ebony-vinyl/dsh-our-free-model
dsh-workbuddy-connect
corrinehu/dsh-workbuddy-connect
dsh-plugin-subscriptions
v1ki/dsh-plugin-subscriptions