Uh oh!
There was an error while loading. Please reload this page.
feat(voice): add Codex subscription transcription - #5647
Conversation
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Effect service conventions review: 3 findings in apps/server/src/transcription.ts (error modeling and catchTag usage).
Posted via Macroscope — Effect Service Conventions
| export const codexTranscriptionAuthStatus = resolveCodexVoiceCredentials().pipe( | ||
| Effect.as(true), | ||
| Effect.catchTag("TranscriptionCodexAuthError", () => Effect.succeed(false)), |
There was a problem hiding this comment.
Effect.catchTag should be Effect.catchTags({ ... }), even when handling a single known tag.
| exportconstcodexTranscriptionAuthStatus=resolveCodexVoiceCredentials().pipe( | |
| Effect.as(true), | |
| Effect.catchTag("TranscriptionCodexAuthError",()=>Effect.succeed(false)), | |
| exportconstcodexTranscriptionAuthStatus=resolveCodexVoiceCredentials().pipe( | |
| Effect.as(true), | |
| Effect.catchTags({TranscriptionCodexAuthError:()=>Effect.succeed(false)}), |
Posted via Macroscope — Effect Service Conventions
| export class TranscriptionCodexAuthError extends Schema.TaggedErrorClass<TranscriptionCodexAuthError>()( | ||
| "TranscriptionCodexAuthError", | ||
| {}, | ||
| ) { | ||
| override get message(): string { | ||
| return "Voice transcription requires file-based Codex credentials signed in with ChatGPT."; | ||
| } | ||
| } |
There was a problem hiding this comment.
TranscriptionCodexAuthError carries no structural attributes and no cause, yet resolveCodexVoiceCredentials (lines 183-205) collapses five distinct failures into it — settings read failure, no Codex instance configured, CodexSettings decode failure, auth.json read failure, and auth.json JSON/schema decode failure — discarding both the underlying error and the known authPath.
Consider giving the error a multi-value operation/stage field plus the resolved path, and an optional cause: Schema.Defect() (the "no Codex instance" case legitimately has no underlying failure), then mapping each step with the context known at that site. CodexShadowHomeFileSystemError in provider/Drivers/CodexHomeLayout.ts is the existing shape to follow (operation, path, cause). The message getter can stay derived from those attributes so the caller-visible HTTP message remains stable.
Posted via Macroscope — Effect Service Conventions
| if (response.status === 401 || response.status === 403) { | ||
| return yield* new TranscriptionCodexAuthError(); | ||
| } |
There was a problem hiding this comment.
This branch is only reachable for openai/groq (codex returns early on line 236), so a 401/403 from the OpenAI or Groq models endpoint is reported with the Codex-specific message "Voice transcription requires file-based Codex credentials…". The error tag no longer identifies the failure structurally, and the models route in http.ts does not handle TranscriptionCodexAuthError, so the failure escapes its catchTags. Suggest dropping the branch and letting TranscriptionProviderError carry the status.
if (response.status < 200 || response.status >= 300) {
- if (response.status === 401 || response.status === 403) {- return yield* new TranscriptionCodexAuthError();- }Posted via Macroscope — Effect Service Conventions
| @@ -81,6 +86,7 @@ export function BetaSettingsPanel() { | |||
| ); | |||
| const voiceTranscriptionModel = useClientSettings((settings) => settings.voiceTranscriptionModel); | |||
| const [environmentApiKeys, setEnvironmentApiKeys] = useState({ | |||
There was a problem hiding this comment.
🟡 Mediumsettings/BetaSettingsPanel.tsx:88
The Codex authentication row shows Unavailable whenever environmentApiKeys.codex is false, but readVoiceTranscriptionEnvironmentStatus failures are silently swallowed by .catch(() => undefined), leaving all environment keys at their initial false values. So a transient network error or server-side failure on the status request causes the row to incorrectly report that no Codex login was found, even when credentials are configured. Consider tracking a loading/error state for the environment status request so the row can distinguish "not configured" from "unknown."
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/settings/BetaSettingsPanel.tsx around line 88:
The Codex authentication row shows `Unavailable` whenever `environmentApiKeys.codex` is `false`, but `readVoiceTranscriptionEnvironmentStatus` failures are silently swallowed by `.catch(() => undefined)`, leaving all environment keys at their initial `false` values. So a transient network error or server-side failure on the status request causes the row to incorrectly report that no Codex login was found, even when credentials are configured. Consider tracking a loading/error state for the environment status request so the row can distinguish "not configured" from "unknown."
| httpClient.execute, | ||
| Effect.mapError((cause) => new TranscriptionRequestError({ provider: "codex", cause })), | ||
| Effect.flatMap((response) => | ||
| Effect.gen(function* () { |
There was a problem hiding this comment.
🟠 Highsrc/transcription.ts:329
When the Codex transcription endpoint returns HTTP 401 or 403, forwardCodexVoiceTranscription throws TranscriptionProviderError with the message "The transcription provider rejected the request. Check the provider and API key." This is wrong because Codex transcription doesn't use an API key — those statuses mean the Codex credentials are expired or rejected, so the user gets a misleading 502 telling them to check an API key instead of the actionable sign-in prompt. The listVoiceTranscriptionModels function already maps 401/403 to TranscriptionCodexAuthError; forwardCodexVoiceTranscription should do the same instead of falling through to the generic TranscriptionProviderError.
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/transcription.ts around line 329:
When the Codex transcription endpoint returns HTTP 401 or 403, `forwardCodexVoiceTranscription` throws `TranscriptionProviderError` with the message "The transcription provider rejected the request. Check the provider and API key." This is wrong because Codex transcription doesn't use an API key — those statuses mean the Codex credentials are expired or rejected, so the user gets a misleading 502 telling them to check an API key instead of the actionable sign-in prompt. The `listVoiceTranscriptionModels` function already maps 401/403 to `TranscriptionCodexAuthError`; `forwardCodexVoiceTranscription` should do the same instead of falling through to the generic `TranscriptionProviderError`.
Problem
The voice dictation beta in #5213 supports OpenAI and Groq API keys, but users already signed in to Codex with ChatGPT cannot reuse that subscription for transcription.
What changed
Codex subscriptionto the existing transcription provider interfaceThis is intentionally stacked on #5213 so the change stays at its existing transcription seam instead of duplicating the composer, recording, settings, and HTTP work in that PR.
User impact
Users with file-based Codex ChatGPT credentials can select Codex subscription for dictation without configuring a separate speech-to-text API key. A missing or rejected login produces a bounded error and suggests signing in with
codex login.Checks
Focused server, web, and contract tests were added. They were not run on this limited VPS per its workspace instructions; CI should run validation.
UI
Adds a Codex subscription provider option and a host authentication status row in Settings → Beta features → Voice dictation. Screenshots are pending because browser/computer-use validation was not authorized for this run.
Built with GPT-5.6 Sol via Codex in T3 Code.
Note
Add Codex subscription as a voice transcription provider
'codex'as a validVoiceTranscriptionProvider, routed through a newforwardCodexVoiceTranscriptioneffect that posts audio to the Codex Desktop transcription endpoint using file-based ChatGPT OAuth credentials from the server.resolveCodexVoiceCredentialseffect that locates the Codex provider config, readsauth.json, and extractsaccess_tokenandaccount_id.codexTranscriptionAuthStatusboolean onGET /api/transcriptionand surfaces it in the settings UI, which shows a server-side auth status row instead of API key/model inputs when Codex is selected.📊 Macroscope summarized 6ddfeec. 6 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted
🗂️ Filtered Issues
No issues evaluated.