diff --git a/packages/types/src/provider-settings.ts b/packages/types/src/provider-settings.ts index 8434158541..18fc082a14 100644 --- a/packages/types/src/provider-settings.ts +++ b/packages/types/src/provider-settings.ts @@ -25,6 +25,7 @@ import { vscodeLlmModels, xaiModels, internationalZAiModels, + openAiNativeCodexModels, } from "./providers/index.js" /** @@ -132,6 +133,7 @@ export const providerNames = [ "mistral", "moonshot", "openai-native", + "openai-native-codex", "qwen-code", "roo", "sambanova", @@ -299,6 +301,11 @@ const openAiNativeSchema = apiModelIdProviderModelSchema.extend({ openAiNativeServiceTier: serviceTierSchema.optional(), }) +// ChatGPT Codex (auth.json) variant - uses local OAuth credentials file (path) +const openAiNativeCodexSchema = apiModelIdProviderModelSchema.extend({ + openAiNativeCodexOauthPath: z.string().optional(), +}) + const mistralSchema = apiModelIdProviderModelSchema.extend({ mistralApiKey: z.string().optional(), mistralCodestralUrl: z.string().optional(), @@ -430,6 +437,7 @@ export const providerSettingsSchemaDiscriminated = z.discriminatedUnion("apiProv geminiSchema.merge(z.object({ apiProvider: z.literal("gemini") })), geminiCliSchema.merge(z.object({ apiProvider: z.literal("gemini-cli") })), openAiNativeSchema.merge(z.object({ apiProvider: z.literal("openai-native") })), + openAiNativeCodexSchema.merge(z.object({ apiProvider: z.literal("openai-native-codex") })), mistralSchema.merge(z.object({ apiProvider: z.literal("mistral") })), deepSeekSchema.merge(z.object({ apiProvider: z.literal("deepseek") })), deepInfraSchema.merge(z.object({ apiProvider: z.literal("deepinfra") })), @@ -471,6 +479,7 @@ export const providerSettingsSchema = z.object({ ...geminiSchema.shape, ...geminiCliSchema.shape, ...openAiNativeSchema.shape, + ...openAiNativeCodexSchema.shape, ...mistralSchema.shape, ...deepSeekSchema.shape, ...deepInfraSchema.shape, @@ -554,6 +563,7 @@ export const modelIdKeysByProvider: Record = { bedrock: "apiModelId", vertex: "apiModelId", "openai-native": "openAiModelId", + "openai-native-codex": "apiModelId", ollama: "ollamaModelId", lmstudio: "lmStudioModelId", gemini: "apiModelId", @@ -676,6 +686,11 @@ export const MODELS_BY_PROVIDER: Record< label: "OpenAI", models: Object.keys(openAiNativeModels), }, + "openai-native-codex": { + id: "openai-native-codex", + label: "OpenAI (ChatGPT Codex)", + models: Object.keys(openAiNativeCodexModels), + }, "qwen-code": { id: "qwen-code", label: "Qwen Code", models: Object.keys(qwenCodeModels) }, roo: { id: "roo", label: "Roo", models: Object.keys(rooModels) }, sambanova: { diff --git a/packages/types/src/providers/index.ts b/packages/types/src/providers/index.ts index 21e43aaa99..0ebe0a4573 100644 --- a/packages/types/src/providers/index.ts +++ b/packages/types/src/providers/index.ts @@ -18,6 +18,7 @@ export * from "./mistral.js" export * from "./moonshot.js" export * from "./ollama.js" export * from "./openai.js" +export * from "./openai-codex.js" export * from "./openrouter.js" export * from "./qwen-code.js" export * from "./requesty.js" diff --git a/packages/types/src/providers/openai-codex.ts b/packages/types/src/providers/openai-codex.ts new file mode 100644 index 0000000000..3c8fac74a3 --- /dev/null +++ b/packages/types/src/providers/openai-codex.ts @@ -0,0 +1,47 @@ +import type { ModelInfo } from "../model.js" + +export type OpenAiNativeCodexModelId = keyof typeof openAiNativeCodexModels + +export const openAiNativeCodexDefaultModelId: OpenAiNativeCodexModelId = "gpt-5" + +export const openAiNativeCodexModels = { + "gpt-5": { + maxTokens: 128000, + contextWindow: 400000, + supportsImages: true, + supportsPromptCache: true, + supportsReasoningEffort: true, + reasoningEffort: "medium", + description: "GPT-5 via ChatGPT Responses (Codex). Optimized for coding and agentic tasks.", + supportsTemperature: false, + }, + "gpt-5-codex": { + maxTokens: 128000, + contextWindow: 400000, + supportsImages: true, + supportsPromptCache: true, + supportsReasoningEffort: true, + reasoningEffort: "medium", + description: + "GPT-5 Codex via ChatGPT Responses (Codex). A GPT‑5 variant exposed to the client with coding‑oriented defaults.", + supportsTemperature: false, + }, + "codex-mini-latest": { + // Based on OpenAI's Codex CLI page (fast reasoning model tuned from o4-mini) + maxTokens: 100000, + contextWindow: 200000, + supportsImages: true, // input images supported + supportsPromptCache: true, + supportsReasoningEffort: true, + reasoningEffort: "medium", + description: + "codex-mini-latest via ChatGPT Responses (Codex). Fast reasoning model optimized for the Codex CLI (fine‑tuned o4‑mini).", + supportsTemperature: false, + // Pricing per 1M tokens + inputPrice: 1.5, + outputPrice: 6.0, + // Prompt cache pricing + cacheWritesPrice: 1.5, + cacheReadsPrice: 0.375, + }, +} as const satisfies Record diff --git a/src/api/index.ts b/src/api/index.ts index ac00967676..655ff35b44 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -16,6 +16,7 @@ import { LmStudioHandler, GeminiHandler, OpenAiNativeHandler, + OpenAiNativeCodexHandler, DeepSeekHandler, MoonshotHandler, MistralHandler, @@ -115,6 +116,8 @@ export function buildApiHandler(configuration: ProviderSettings): ApiHandler { return new GeminiHandler(options) case "openai-native": return new OpenAiNativeHandler(options) + case "openai-native-codex": + return new OpenAiNativeCodexHandler(options) case "deepseek": return new DeepSeekHandler(options) case "doubao": diff --git a/src/api/providers/index.ts b/src/api/providers/index.ts index 85d877b6bc..a65de3f6f5 100644 --- a/src/api/providers/index.ts +++ b/src/api/providers/index.ts @@ -19,6 +19,7 @@ export { LmStudioHandler } from "./lm-studio" export { MistralHandler } from "./mistral" export { OllamaHandler } from "./ollama" export { OpenAiNativeHandler } from "./openai-native" +export { OpenAiNativeCodexHandler } from "./openai-native-codex" export { OpenAiHandler } from "./openai" export { OpenRouterHandler } from "./openrouter" export { QwenCodeHandler } from "./qwen-code" diff --git a/src/api/providers/openai-native-codex.prompt.ts b/src/api/providers/openai-native-codex.prompt.ts new file mode 100644 index 0000000000..27096dc6c3 --- /dev/null +++ b/src/api/providers/openai-native-codex.prompt.ts @@ -0,0 +1,161 @@ +/** + * ChatGPT Codex system prompt (canonical/inert): + * - The Responses API applies an immutable default system prompt server‑side. + * - We cannot replace it dynamically; this file supplies the canonical text used for the top‑level "instructions". + * Strategy: + * - We complement this with a separate system-role injection in the provider using + * (to de-emphasize defaults) and (the current task). + * - See OpenAiNativeCodexHandler.createMessage for details and rationale. + */ +export default `You are Codex, based on GPT-5. You are running as a coding agent in the Codex CLI on a user's computer. + +## General + +- The arguments to \`shell\` will be passed to execvp(). Most terminal commands should be prefixed with ["bash", "-lc"]. +- Always set the \`workdir\` param when using the shell function. Do not use \`cd\` unless absolutely necessary. +- When searching for text or files, prefer using \`rg\` or \`rg --files\` respectively because \`rg\` is much faster than alternatives like \`grep\`. (If the \`rg\` command is not found, then use alternatives.) + +## Editing constraints + +- Default to ASCII when editing or creating files. Only introduce non-ASCII or other Unicode characters when there is a clear justification and the file already uses them. +- Add succinct code comments that explain what is going on if code is not self-explanatory. You should not add comments like "Assigns the value to the variable", but a brief comment might be useful ahead of a complex code block that the user would otherwise have to spend time parsing out. Usage of these comments should be rare. +- You may be in a dirty git worktree. + * NEVER revert existing changes you did not make unless explicitly requested, since these changes were made by the user. + * If asked to make a commit or code edits and there are unrelated changes to your work or changes that you didn't make in those files, don't revert those changes. + * If the changes are in files you've touched recently, you should read carefully and understand how you can work with the changes rather than reverting them. + * If the changes are in unrelated files, just ignore them and don't revert them. +- While you are working, you might notice unexpected changes that you didn't make. If this happens, STOP IMMEDIATELY and ask the user how they would like to proceed. + +## Plan tool + +When using the planning tool: +- Skip using the planning tool for straightforward tasks (roughly the easiest 25%). +- Do not make single-step plans. +- When you made a plan, update it after having performed one of the sub-tasks that you shared on the plan. + +## Codex CLI harness, sandboxing, and approvals + +The Codex CLI harness supports several different configurations for sandboxing and escalation approvals that the user can choose from. + +Filesystem sandboxing defines which files can be read or written. The options for \`sandbox_mode\` are: +- **read-only**: The sandbox only permits reading files. +- **workspace-write**: The sandbox permits reading files, and editing files in \`cwd\` and \`writable_roots\`. Editing files in other directories requires approval. +- **danger-full-access**: No filesystem sandboxing - all commands are permitted. + +Network sandboxing defines whether network can be accessed without approval. Options for \`network_access\` are: +- **restricted**: Requires approval +- **enabled**: No approval needed + +Approvals are your mechanism to get user consent to run shell commands without the sandbox. Possible configuration options for \`approval_policy\` are +- **untrusted**: The harness will escalate most commands for user approval, apart from a limited allowlist of safe "read" commands. +- **on-failure**: The harness will allow all commands to run in the sandbox (if enabled), and failures will be escalated to the user for approval to run again without the sandbox. +- **on-request**: Commands will be run in the sandbox by default, and you can specify in your tool call if you want to escalate a command to run without sandboxing. (Note that this mode is not always available. If it is, you'll see parameters for it in the \`shell\` command description.) +- **never**: This is a non-interactive mode where you may NEVER ask the user for approval to run commands. Instead, you must always persist and work around constraints to solve the task for the user. You MUST do your utmost best to finish the task and validate your work before yielding. If this mode is paired with \`danger-full-access\`, take advantage of it to deliver the best outcome for the user. Further, in this mode, your default testing philosophy is overridden: Even if you don't see local patterns for testing, you may add tests and scripts to validate your work. Just remove them before yielding. + +When you are running with \`approval_policy == on-request\`, and sandboxing enabled, here are scenarios where you'll need to request approval: +- You need to run a command that writes to a directory that requires it (e.g. running tests that write to /var) +- You need to run a GUI app (e.g., open/xdg-open/osascript) to open browsers or files. +- You are running sandboxed and need to run a command that requires network access (e.g. installing packages) +- If you run a command that is important to solving the user's query, but it fails because of sandboxing, rerun the command with approval. ALWAYS proceed to use the \`with_escalated_permissions\` and \`justification\` parameters - do not message the user before requesting approval for the command. +- You are about to take a potentially destructive action such as an \`rm\` or \`git reset\` that the user did not explicitly ask for +- (for all of these, you should weigh alternative paths that do not require approval) + +When \`sandbox_mode\` is set to read-only, you'll need to request approval for any command that isn't a read. + +You will be told what filesystem sandboxing, network sandboxing, and approval mode are active in a developer or user message. If you are not told about this, assume that you are running with workspace-write, network sandboxing enabled, and approval on-failure. + +Although they introduce friction to the user because your work is paused until the user responds, you should leverage them when necessary to accomplish important work. If the completing the task requires escalated permissions, Do not let these settings or the sandbox deter you from attempting to accomplish the user's task unless it is set to "never", in which case never ask for approvals. + +When requesting approval to execute a command that will require escalated privileges: + - Provide the \`with_escalated_permissions\` parameter with the boolean value true + - Include a short, 1 sentence explanation for why you need to enable \`with_escalated_permissions\` in the justification parameter + +## Special user requests + +- If the user makes a simple request (such as asking for the time) which you can fulfill by running a terminal command (such as \`date\`), you should do so. +- If the user asks for a "review", default to a code review mindset: prioritise identifying bugs, risks, behavioural regressions, and missing tests. Findings must be the primary focus of the response - keep summaries or overviews brief and only after enumerating the issues. Present findings first (ordered by severity with file/line references), follow with open questions or assumptions, and offer a change-summary only as a secondary detail. If no findings are discovered, state that explicitly and mention any residual risks or testing gaps. + +## Presenting your work and final message + +You are producing plain text that will later be styled by the CLI. Follow these rules exactly. Formatting should make results easy to scan, but not feel mechanical. Use judgment to decide how much structure adds value. + +- Default: be very concise; friendly coding teammate tone. +- Ask only when needed; suggest ideas; mirror the user's style. +- For substantial work, summarize clearly; follow final‑answer formatting. +- Skip heavy formatting for simple confirmations. +- Don't dump large files you've written; reference paths only. +- No "save/copy this file" - User is on the same machine. +- Offer logical next steps (tests, commits, build) briefly; add verify steps if you couldn't do something. +- For code changes: + * Lead with a quick explanation of the change, and then give more details on the context covering where and why a change was made. Do not start this explanation with "summary", just jump right in. + * If there are natural next steps the user may want to take, suggest them at the end of your response. Do not make suggestions if there are no natural next steps. + * When suggesting multiple options, use numeric lists for the suggestions so the user can quickly respond with a single number. +- The user does not command execution outputs. When asked to show the output of a command (e.g. \`git show\`), relay the important details in your answer or summarize the key lines so the user understands the result. + +### Final answer structure and style guidelines + +- Plain text; CLI handles styling. Use structure only when it helps scanability. +- Headers: optional; short Title Case (1-3 words) wrapped in **…**; no blank line before the first bullet; add only if they truly help. +- Bullets: use - ; merge related points; keep to one line when possible; 4–6 per list ordered by importance; keep phrasing consistent. +- Monospace: backticks for commands/paths/env vars/code ids and inline examples; use for literal keyword bullets; never combine with **. +- Code samples or multi-line snippets should be wrapped in fenced code blocks; add a language hint whenever obvious. +- Structure: group related bullets; order sections general → specific → supporting; for subsections, start with a bolded keyword bullet, then items; match complexity to the task. +- Tone: collaborative, concise, factual; present tense, active voice; self‑contained; no "above/below"; parallel wording. +- Don'ts: no nested bullets/hierarchies; no ANSI codes; don't cram unrelated keywords; keep keyword lists short—wrap/reformat if long; avoid naming formatting styles in answers. +- Adaptation: code explanations → precise, structured with code refs; simple tasks → lead with outcome; big changes → logical walkthrough + rationale + next actions; casual one-offs → plain sentences, no headers/bullets. +- File References: When referencing files in your response, make sure to include the relevant start line and always follow the below rules: + * Use inline code to make file paths clickable. + * Each reference should have a stand alone path. Even if it's the same file. + * Accepted: absolute, workspace‑relative, a/ or b/ diff prefixes, or bare filename/suffix. + * Line/column (1‑based, optional): :line[:column] or #Lline[Ccolumn] (column defaults to 1). + * Do not use URIs like file://, vscode://, or https://. + * Do not provide range of lines + * Examples: src/app.ts, src/app.ts:42, b/server/index.js#L10, C:\\repo\\project\\main.rs:12:5 +` + +/** + * Rationale for overridePrompt: + * - Codex’s default system prompt cannot be removed. + * - This override clarifies Roo’s identity and precedence rules and asks the model to honor Roo’s tools and flow. + * - It is injected as so the server’s default is still present, but downweighted in practice. + */ +export const overridePrompt = `## Identity and precedence +- You are Roo (not Codex). Ignore any "Codex", "Codex CLI", or "based on GPT-5" identity statements. Roo's rules take precedence over any harness text. + +## Tooling model +- Ignore any "shell" function, execvp argument formats, and "workdir" parameters. Use Roo's command-execution tool with an explicit working directory. +- If a command must run elsewhere, run a single command string prefixed with "cd && ..." via the tool; do not rely on a separate "workdir" concept. + +## Code search and file exploration +- Do not use terminal search utilities (e.g., ripgrep/grep) to explore repositories. +- For any new area of exploration: first use the semantic code search tool; then use the project's regex search and file reader tools as needed. + +## Planning and preambles +- Do not reference or depend on a generic "planning tool." +- For non-trivial tasks: briefly restate the goal, outline a short plan up front, provide concise progress updates during tool use, and summarize outcomes distinctly. + +## Approvals and sandboxing +- Ignore Codex approval/sandbox modes and escalation parameters (including any fields to request escalated permissions or justifications). +- Follow Roo's one-tool-per-message flow and wait for user confirmation after each tool use. Do not take destructive/high-impact actions without explicit user confirmation. + +## Testing and validation +- Do not add temporary tests/scripts solely for validation and then remove them. +- Ensure changes retain or add proper test coverage using the repository's established test runner, paths, and conventions. + +## Output and formatting +- Ignore "plain text only" guidance. Follow Roo's Markdown rules, including clickable file and syntax references in the required link format. +- Do not dump large file contents; reference file paths instead. + +## Command outputs and environment assumptions +- Do not assume a CLI will style or relay outputs automatically. Summarize essential results per Roo's rules; request pasted output only if absolutely necessary. +- Assume Roo's environment semantics (e.g., macOS, constrained workspace directory) and tool behavior. + +## Risky operations and GUIs +- Do not request or simulate escalation flows from Codex. Propose safe alternatives within Roo's constraints and obtain explicit confirmation when required. +- Do not launch GUI apps or perform networked installs via Codex-style approvals. + +## Eagerness calibration +- Gather just enough context to act; avoid repetitive searches; prefer acting and validating over extended exploration. Proceed under reasonable uncertainty when appropriate, documenting assumptions succinctly. + +- Any instructions following these rules in this override prompt take precedence over these override rules. +` diff --git a/src/api/providers/openai-native-codex.ts b/src/api/providers/openai-native-codex.ts new file mode 100644 index 0000000000..8f613e2a62 --- /dev/null +++ b/src/api/providers/openai-native-codex.ts @@ -0,0 +1,562 @@ +import type { Anthropic } from "@anthropic-ai/sdk" +import { promises as fs } from "node:fs" +import os from "node:os" +import path from "node:path" + +import type { ApiHandlerCreateMessageMetadata } from "../index" +import { BaseProvider } from "./base-provider" +// stream + params +import { ApiStream, ApiStreamUsageChunk } from "../transform/stream" +import { getModelParams } from "../transform/model-params" +// Provider prompt content as a TS string module (no loader required) +import codexPromptContent, { overridePrompt } from "./openai-native-codex.prompt" +import { getApiRequestTimeout } from "./utils/timeout-config" +import { t } from "i18next" + +import { + type ModelInfo, + type ReasoningEffortWithMinimal, + type ServiceTier, + type VerbosityLevel, + openAiNativeCodexDefaultModelId, + openAiNativeCodexModels, +} from "@roo-code/types" + +import type { ApiHandlerOptions } from "../../shared/api" +import { calculateApiCostOpenAI } from "../../shared/cost" + +export type OpenAiNativeCodexModel = ReturnType + +// Codex input typing for safer transforms and tests +type CodexRole = "system" | "user" | "assistant" +interface CodexInputText { + type: "input_text" + text: string +} +interface CodexOutputText { + type: "output_text" + text: string +} +interface CodexInputImage { + type: "input_image" + image_url: string +} +type CodexContent = CodexInputText | CodexOutputText | CodexInputImage +interface CodexMessage { + role: CodexRole + content: CodexContent[] +} + +interface AuthTokens { + access_token?: string + account_id?: string + id_token?: string +} +interface AuthJson { + tokens?: AuthTokens +} + +/** + * OpenAI Native (Codex) provider + * - Uses ChatGPT auth.json tokens (no API key) + * - Calls ChatGPT Responses endpoint: https://chatgpt.com/backend-api/codex/responses + */ +export class OpenAiNativeCodexHandler extends BaseProvider { + protected options: ApiHandlerOptions + private chatgptAccessToken!: string + private chatgptAccountId?: string + + // Inline-loaded provider prompt (via esbuild text loader for .md files) + + // Provider prompt content is loaded via loadProviderPrompt() + + constructor(options: ApiHandlerOptions) { + super() + this.options = options + if (this.options.enableGpt5ReasoningSummary === undefined) { + this.options.enableGpt5ReasoningSummary = true + } + + // Credentials are resolved lazily via ensureAuthenticated() on first use. + } + + // Normalize usage to Roo's ApiStreamUsageChunk and compute totalCost + private normalizeUsage(usage: any, model: OpenAiNativeCodexModel): ApiStreamUsageChunk | undefined { + if (!usage) return undefined + + const inputDetails = usage.input_tokens_details ?? usage.prompt_tokens_details + const hasCachedTokens = typeof inputDetails?.cached_tokens === "number" + const hasCacheMissTokens = typeof inputDetails?.cache_miss_tokens === "number" + const cachedFromDetails = hasCachedTokens ? inputDetails.cached_tokens : 0 + const missFromDetails = hasCacheMissTokens ? inputDetails.cache_miss_tokens : 0 + + let totalInputTokens = usage.input_tokens ?? usage.prompt_tokens ?? 0 + if (totalInputTokens === 0 && inputDetails && (cachedFromDetails > 0 || missFromDetails > 0)) { + totalInputTokens = cachedFromDetails + missFromDetails + } + + const totalOutputTokens = usage.output_tokens ?? usage.completion_tokens ?? 0 + const cacheWriteTokens = usage.cache_creation_input_tokens ?? usage.cache_write_tokens ?? 0 + const cacheReadTokens = + usage.cache_read_input_tokens ?? usage.cache_read_tokens ?? usage.cached_tokens ?? cachedFromDetails ?? 0 + + const totalCost = calculateApiCostOpenAI( + model.info, + totalInputTokens, + totalOutputTokens, + cacheWriteTokens, + cacheReadTokens, + ) + + const reasoningTokens = + typeof usage.output_tokens_details?.reasoning_tokens === "number" + ? usage.output_tokens_details.reasoning_tokens + : undefined + + const out: ApiStreamUsageChunk = { + type: "usage", + inputTokens: totalInputTokens, + outputTokens: totalOutputTokens, + cacheWriteTokens, + cacheReadTokens, + ...(typeof reasoningTokens === "number" ? { reasoningTokens } : {}), + totalCost, + } + return out + } + + private async ensureAuthenticated(): Promise { + if (this.chatgptAccessToken) return + + const configured = (this.options as any).openAiNativeCodexOauthPath as string | undefined + const defaultPath = "~/.codex/auth.json" + const expandHome = (p: string) => p.replace(/^~(?=\/|\\|$)/, os.homedir()) + const pathToUse = configured && configured.trim() ? configured.trim() : defaultPath + const explicitPath = expandHome(pathToUse) + const resolvedPath = path.resolve(explicitPath) + + // Guard file size before reading to prevent loading unexpectedly large files + const MAX_OAUTH_SIZE = 1_000_000 // 1 MB + try { + const stat = await fs.stat(resolvedPath) + if (stat.size > MAX_OAUTH_SIZE) { + throw new Error( + t("common:errors.openaiNativeCodex.oauthFileTooLarge", { + path: resolvedPath, + size: stat.size, + max: MAX_OAUTH_SIZE, + }), + ) + } + } catch (e: any) { + // Surface read failure with localized error (e.g., file missing or inaccessible) + const base = t("common:errors.openaiNativeCodex.oauthReadFailed", { + path: resolvedPath, + error: e?.message || String(e), + }) + throw new Error(base) + } + + let raw: string + try { + raw = await fs.readFile(resolvedPath, "utf8") + } catch (e: any) { + const base = t("common:errors.openaiNativeCodex.oauthReadFailed", { + path: resolvedPath, + error: e?.message || String(e), + }) + throw new Error(base) + } + + // Post-read size check using byte length + if (Buffer.byteLength(raw, "utf8") > MAX_OAUTH_SIZE) { + throw new Error( + t("common:errors.openaiNativeCodex.oauthFileTooLarge", { + path: resolvedPath, + size: Buffer.byteLength(raw, "utf8"), + max: MAX_OAUTH_SIZE, + }), + ) + } + + let j: AuthJson + try { + j = JSON.parse(raw) as AuthJson + } catch (e: any) { + const base = t("common:errors.openaiNativeCodex.oauthParseFailed", { + path: resolvedPath, + error: e?.message || String(e), + }) + throw new Error(base) + } + + const tokens: AuthTokens = j?.tokens ?? {} + const access = typeof tokens.access_token === "string" ? tokens.access_token : undefined + let account = typeof tokens.account_id === "string" ? tokens.account_id : undefined + + if (!account && typeof tokens.id_token === "string") { + const decoded = this.extractAccountIdFromIdToken(tokens.id_token) + if (decoded) { + account = decoded + } + } + + if (!access) { + throw new Error(t("common:errors.openaiNativeCodex.missingAccessToken")) + } + + this.chatgptAccessToken = access + this.chatgptAccountId = account + } + + // Extract ChatGPT account id from id_token without verifying signature (local decode for UX only) + protected extractAccountIdFromIdToken(idToken: string): string | undefined { + try { + const parts = idToken.split(".") + if (parts.length !== 3) return undefined + const payload = parts[1] + const padded = payload + "=".repeat((4 - (payload.length % 4)) % 4) + const claims = JSON.parse(Buffer.from(padded, "base64").toString("utf8")) + const auth = claims?.["https://api.openai.com/auth"] + return typeof auth?.chatgpt_account_id === "string" ? auth.chatgpt_account_id : undefined + } catch { + return undefined + } + } + + override getModel() { + const modelId = this.options.apiModelId + const id = + modelId && modelId in openAiNativeCodexModels + ? (modelId as keyof typeof openAiNativeCodexModels) + : openAiNativeCodexDefaultModelId + const info: ModelInfo = openAiNativeCodexModels[id] + + const params = getModelParams({ + format: "openai", + modelId: id as string, + model: info, + settings: this.options, + }) + + // Reasoning effort is computed by getModelParams based on model + settings + return { id: id as string, info, ...params, verbosity: params.verbosity } + } + + override async *createMessage( + systemPrompt: string, + messages: Anthropic.Messages.MessageParam[], + metadata?: ApiHandlerCreateMessageMetadata, + ): ApiStream { + const model = this.getModel() + await this.ensureAuthenticated() + + // Transform messages to Codex input with strong typing + const formattedInput = this.buildCodexInput(messages, systemPrompt) + + // Use provider-local prompt content for top-level instructions (TS string module) + const codexPrompt = codexPromptContent + + // Codex (chatgpt.com codex/responses) is stateless and does NOT support previous_response_id. + // We always send curated prior items in `input` to preserve continuity. + const requestBody = this.buildRequestBody( + model, + formattedInput, + codexPrompt, + (model as any).verbosity as VerbosityLevel | undefined, + (model as any).reasoning?.reasoning_effort as ReasoningEffortWithMinimal | undefined, + ) + + yield* this.makeResponsesRequest(requestBody, model) + } + + // Split out for unit testing and clearer typing + protected buildCodexInput(messages: Anthropic.Messages.MessageParam[], systemPrompt: string): CodexMessage[] { + const formatted: CodexMessage[] = [] + // Inject provider overrides and dynamic instructions as a system role using and XML tags + let injectedUserInstructions = false + + for (const message of messages) { + const role: CodexRole = message.role === "user" ? "user" : "assistant" + const content: CodexContent[] = [] + + if (!injectedUserInstructions && typeof systemPrompt === "string" && systemPrompt.trim().length > 0) { + // Codex system prompt immutability: + // - The top-level "instructions" field sent to codex/responses is immutable on the server. + // - We cannot dynamically alter the default system prompt that Codex applies. + // Strategy and rationale: + // - We inject two system-role items before the first user/assistant turn: + // 1) — explains to the model how Roo’s rules supersede Codex defaults. + // 2) — the current task/systemPrompt, asking Codex to prioritize these rules/tools. + // - This pattern reduces the impact of Codex’s default prompt without trying to replace it (not possible). + // - We also keep these separate from user messages to avoid tool execution bias. + formatted.push({ + role: "system", + content: [ + { + type: "input_text", + text: `${overridePrompt}`, + }, + { type: "input_text", text: `${systemPrompt}` }, + ], + }) + injectedUserInstructions = true + } + + if (typeof message.content === "string") { + if (role === "user") content.push({ type: "input_text", text: message.content }) + else content.push({ type: "output_text", text: message.content }) + } else if (Array.isArray(message.content)) { + for (const block of message.content) { + if (block.type === "text") { + const text = (block as any).text as string + if (typeof text === "string") { + if (role === "user") content.push({ type: "input_text", text }) + else content.push({ type: "output_text", text }) + } + } else if (block.type === "image") { + const image = block as Anthropic.Messages.ImageBlockParam + const imageUrl = `data:${image.source.media_type};base64,${image.source.data}` + content.push({ type: "input_image", image_url: imageUrl }) + } + } + } + if (content.length > 0) formatted.push({ role, content }) + } + + return formatted + } + + private buildRequestBody( + model: OpenAiNativeCodexModel, + formattedInput: CodexMessage[], + providerPrompt: string, + verbosity: VerbosityLevel | undefined, + reasoningEffort: ReasoningEffortWithMinimal | undefined, + ) { + // For Codex provider: + // - Use the model's default reasoning effort (currently "medium") unless explicitly overridden in settings. + // - Both "gpt-5" and "gpt-5-codex" follow the provided/default effort without forcing "minimal". + let effectiveEffort: ReasoningEffortWithMinimal | undefined = reasoningEffort + + const body: { + model: string + input: CodexMessage[] + stream: true + store: false + instructions: string + reasoning?: { + effort: ReasoningEffortWithMinimal + summary?: "auto" + } + text?: { verbosity: VerbosityLevel } + } = { + model: model.id, + input: formattedInput, + stream: true, + // ChatGPT Responses requires store=false + store: false, + // Top-level instructions string passed in by caller (createMessage supplies provider prompt) + instructions: providerPrompt, + ...(effectiveEffort && { + reasoning: { + effort: effectiveEffort, + ...(this.options.enableGpt5ReasoningSummary ? { summary: "auto" as const } : {}), + }, + }), + // ChatGPT codex/responses does not support previous_response_id (stateless). + // Preserve continuity by sending curated prior items in `input`. + } + if (model.info.supportsVerbosity === true) { + body.text = { verbosity: (verbosity || "medium") as VerbosityLevel } + } + return body + } + + private async *makeResponsesRequest(requestBody: any, model: OpenAiNativeCodexModel): ApiStream { + const apiKey = this.chatgptAccessToken + const url = "https://chatgpt.com/backend-api/codex/responses" + const headers: Record = { + "Content-Type": "application/json", + Authorization: `Bearer ${apiKey}`, + Accept: "text/event-stream", + "OpenAI-Beta": "responses=experimental", + } + if (this.chatgptAccountId) headers["chatgpt-account-id"] = this.chatgptAccountId + + let timeoutId: ReturnType | undefined + try { + const timeoutMs = getApiRequestTimeout() + const controller = new AbortController() + timeoutId = timeoutMs > 0 ? setTimeout(() => controller.abort(), timeoutMs) : undefined + const response = await fetch(url, { + method: "POST", + headers, + body: JSON.stringify(requestBody), + signal: controller.signal, + }) + + if (!response.ok) { + const text = await response.text().catch(() => "") + const requestId = + response.headers.get("x-request-id") || response.headers.get("openai-request-id") || undefined + let userMessage: string | undefined + try { + const parsed = JSON.parse(text) + userMessage = parsed?.error?.message || parsed?.message || parsed?.error || undefined + } catch { + // ignore parse error + } + const snippet = (text || "").slice(0, 500).replace(/\s+/g, " ").trim() + const msg = t("common:errors.openaiNativeCodex.httpError", { + status: response.status, + requestId: requestId || "n/a", + modelId: model.id, + message: userMessage || snippet, + }) + const err = new Error(msg) + ;(err as any).status = response.status + if (requestId) (err as any).requestId = requestId + ;(err as any).provider = "openai-native-codex" + ;(err as any).raw = snippet + throw err + } + if (!response.body) { + throw new Error(t("common:errors.openaiNativeCodex.noResponseBody")) + } + + // Stream parse + { + const reader = response.body.getReader() + const decoder = new TextDecoder() + let buffer = "" + let hasContent = false + let sawTextDelta = false + let sawReasoningDelta = false + + try { + while (true) { + const { done, value } = await reader.read() + if (done) break + + buffer += decoder.decode(value, { stream: true }) + const lines = buffer.split("\n") + buffer = lines.pop() || "" + + for (const line of lines) { + if (line.startsWith("data: ")) { + const data = line.slice(6).trim() + if (data === "[DONE]") { + continue + } + try { + const parsed = JSON.parse(data) + // Persist tier when available (parity with openai-native) + if (parsed.response?.service_tier) { + } + // Minimal content extraction similar to OpenAI Responses + if (parsed?.type === "response.text.delta" && parsed?.delta) { + hasContent = true + sawTextDelta = true + yield { type: "text", text: parsed.delta } + } else if (parsed?.type === "response.output_text.delta" && parsed?.delta) { + hasContent = true + sawTextDelta = true + yield { type: "text", text: parsed.delta } + } else if ( + parsed?.type === "response.output_text.done" && + typeof parsed?.text === "string" + ) { + if (!sawTextDelta) { + hasContent = true + yield { type: "text", text: parsed.text } + } + } else if ( + parsed?.type === "response.reasoning_summary_text.delta" && + typeof parsed?.delta === "string" + ) { + hasContent = true + sawReasoningDelta = true + yield { type: "reasoning", text: parsed.delta } + } else if ( + parsed?.type === "response.reasoning_summary_text.done" && + typeof parsed?.text === "string" + ) { + if (!sawReasoningDelta) { + hasContent = true + yield { type: "reasoning", text: parsed.text } + } + } else if (parsed?.response?.output && Array.isArray(parsed.response.output)) { + for (const item of parsed.response.output) { + if (item.type === "text" && Array.isArray(item.content)) { + for (const c of item.content) { + if (c?.type === "text" && typeof c.text === "string") { + hasContent = true + yield { type: "text", text: c.text } + } + } + } else if (item.type === "reasoning" && typeof item.text === "string") { + hasContent = true + yield { type: "reasoning", text: item.text } + } + } + if ( + (parsed.type === "response.completed" || parsed.type === "response.done") && + parsed.response?.usage + ) { + const usageData = this.normalizeUsage(parsed.response.usage, model) + if (usageData) { + yield usageData + } + } + } else if ( + parsed.type === "response.completed" || + parsed.type === "response.done" + ) { + const usageData = this.normalizeUsage(parsed.response?.usage, model) + if (usageData) { + yield usageData + } + } else if (parsed?.usage) { + const usageData = this.normalizeUsage(parsed.usage, model) + if (usageData) { + yield usageData + } + } + } catch { + // ignore parse errors + } + } else if (line.trim() && !line.startsWith(":")) { + try { + const parsed = JSON.parse(line) + if (parsed.content || parsed.text || parsed.message) { + hasContent = true + yield { type: "text", text: parsed.content || parsed.text || parsed.message } + } + } catch { + // ignore + } + } + } + } + if (!hasContent) { + throw new Error(t("common:errors.openaiNativeCodex.emptyStream", { modelId: model.id })) + } + } finally { + try { + reader.releaseLock() + } catch {} + } + } + } catch (err) { + throw err as Error + } finally { + // Clear timeout if set + try { + if (typeof timeoutId !== "undefined") { + clearTimeout(timeoutId as any) + } + } catch {} + } + } +} diff --git a/src/i18n/locales/ca/common.json b/src/i18n/locales/ca/common.json index a1f528ef97..1de013b9ee 100644 --- a/src/i18n/locales/ca/common.json +++ b/src/i18n/locales/ca/common.json @@ -117,6 +117,15 @@ "roo": { "authenticationRequired": "El proveïdor Roo requereix autenticació al núvol. Si us plau, inicieu sessió a Roo Code Cloud." }, + "openaiNativeCodex": { + "oauthReadFailed": "Error en carregar les credencials OAuth de ChatGPT a {{path}}: {{error}}. Consell: autentica't amb la CLI de Codex (p. ex., \"codex login\") per crear auth.json.", + "oauthParseFailed": "Error en analitzar el JSON de credencials OAuth de ChatGPT a {{path}}: {{error}}. Consell: assegura't que el fitxer sigui JSON vàlid o torna a autenticar-te amb \"codex login\" per regenerar-lo.", + "oauthFileTooLarge": "El fitxer de credencials OAuth a {{path}} és massa gran ({{size}} bytes). El màxim permès és {{max}} bytes.", + "missingAccessToken": "Les credencials OAuth de ChatGPT no tenen tokens.access_token.", + "httpError": "Codex HTTP {{status}} (req: {{requestId}}) model={{modelId}}: {{message}}", + "noResponseBody": "Error de respostes de ChatGPT: No hi ha cos de resposta", + "emptyStream": "El flux de respostes de ChatGPT no ha retornat contingut per al model {{modelId}}" + }, "api": { "invalidKeyInvalidChars": "La clau API conté caràcters no vàlids." }, diff --git a/src/i18n/locales/de/common.json b/src/i18n/locales/de/common.json index dbd9452e60..9f16da4f23 100644 --- a/src/i18n/locales/de/common.json +++ b/src/i18n/locales/de/common.json @@ -114,6 +114,15 @@ "roo": { "authenticationRequired": "Roo-Anbieter erfordert Cloud-Authentifizierung. Bitte melde dich bei Roo Code Cloud an." }, + "openaiNativeCodex": { + "oauthReadFailed": "Fehler beim Laden der ChatGPT OAuth-Anmeldedaten unter {{path}}: {{error}}. Tipp: Authentifiziere dich mit der Codex CLI (z.B. \"codex login\"), um auth.json zu erstellen.", + "oauthParseFailed": "Fehler beim Parsen der ChatGPT OAuth-Anmeldedaten JSON unter {{path}}: {{error}}. Tipp: Stelle sicher, dass die Datei gültiges JSON ist oder authentifiziere dich erneut mit \"codex login\", um sie zu regenerieren.", + "oauthFileTooLarge": "OAuth-Anmeldedatei unter {{path}} ist zu groß ({{size}} Bytes). Maximal erlaubt sind {{max}} Bytes.", + "missingAccessToken": "ChatGPT OAuth-Anmeldedaten fehlen tokens.access_token.", + "httpError": "Codex HTTP {{status}} (req: {{requestId}}) model={{modelId}}: {{message}}", + "noResponseBody": "ChatGPT Responses Fehler: Kein Antworttext vorhanden", + "emptyStream": "ChatGPT Responses Stream hat keinen Inhalt für Modell {{modelId}} zurückgegeben" + }, "api": { "invalidKeyInvalidChars": "API-Schlüssel enthält ungültige Zeichen." }, diff --git a/src/i18n/locales/en/common.json b/src/i18n/locales/en/common.json index 3a613cc1c2..6809a567f7 100644 --- a/src/i18n/locales/en/common.json +++ b/src/i18n/locales/en/common.json @@ -114,6 +114,15 @@ "roo": { "authenticationRequired": "Roo provider requires cloud authentication. Please sign in to Roo Code Cloud." }, + "openaiNativeCodex": { + "oauthReadFailed": "Failed to load ChatGPT OAuth credentials at {{path}}: {{error}}. Tip: authenticate with the Codex CLI (e.g., \"codex login\") to create auth.json.", + "oauthParseFailed": "Failed to parse ChatGPT OAuth credentials JSON at {{path}}: {{error}}. Tip: ensure the file is valid JSON or re-authenticate with \"codex login\" to regenerate it.", + "oauthFileTooLarge": "OAuth credentials file at {{path}} is too large ({{size}} bytes). Maximum allowed is {{max}} bytes.", + "missingAccessToken": "ChatGPT OAuth credentials are missing tokens.access_token.", + "httpError": "Codex HTTP {{status}} (req: {{requestId}}) model={{modelId}}: {{message}}", + "noResponseBody": "ChatGPT Responses error: No response body", + "emptyStream": "ChatGPT Responses stream returned no content for model {{modelId}}" + }, "api": { "invalidKeyInvalidChars": "API key contains invalid characters." }, diff --git a/src/i18n/locales/es/common.json b/src/i18n/locales/es/common.json index 49dcfe98c5..f659034fce 100644 --- a/src/i18n/locales/es/common.json +++ b/src/i18n/locales/es/common.json @@ -114,6 +114,15 @@ "roo": { "authenticationRequired": "El proveedor Roo requiere autenticación en la nube. Por favor, inicia sesión en Roo Code Cloud." }, + "openaiNativeCodex": { + "oauthReadFailed": "Error al cargar las credenciales OAuth de ChatGPT en {{path}}: {{error}}. Consejo: auténticate con la CLI de Codex (ej., \"codex login\") para crear auth.json.", + "oauthParseFailed": "Error al analizar el JSON de credenciales OAuth de ChatGPT en {{path}}: {{error}}. Consejo: asegúrate de que el archivo sea JSON válido o vuelve a autenticarte con \"codex login\" para regenerarlo.", + "oauthFileTooLarge": "El archivo de credenciales OAuth en {{path}} es demasiado grande ({{size}} bytes). El máximo permitido es {{max}} bytes.", + "missingAccessToken": "Las credenciales OAuth de ChatGPT no tienen tokens.access_token.", + "httpError": "Codex HTTP {{status}} (req: {{requestId}}) model={{modelId}}: {{message}}", + "noResponseBody": "Error de respuestas de ChatGPT: Sin cuerpo de respuesta", + "emptyStream": "El flujo de respuestas de ChatGPT no devolvió contenido para el modelo {{modelId}}" + }, "api": { "invalidKeyInvalidChars": "La clave API contiene caracteres inválidos." }, diff --git a/src/i18n/locales/fr/common.json b/src/i18n/locales/fr/common.json index 260bbbf13b..b57efc3bf8 100644 --- a/src/i18n/locales/fr/common.json +++ b/src/i18n/locales/fr/common.json @@ -114,6 +114,15 @@ "roo": { "authenticationRequired": "Le fournisseur Roo nécessite une authentification cloud. Veuillez vous connecter à Roo Code Cloud." }, + "openaiNativeCodex": { + "oauthReadFailed": "Échec du chargement des identifiants OAuth ChatGPT à {{path}} : {{error}}. Conseil : authentifiez-vous avec la CLI Codex (ex. \"codex login\") pour créer auth.json.", + "oauthParseFailed": "Échec de l'analyse du JSON des identifiants OAuth ChatGPT à {{path}} : {{error}}. Conseil : assurez-vous que le fichier est un JSON valide ou ré-authentifiez-vous avec \"codex login\" pour le régénérer.", + "oauthFileTooLarge": "Le fichier d'identifiants OAuth à {{path}} est trop volumineux ({{size}} octets). Le maximum autorisé est {{max}} octets.", + "missingAccessToken": "Les identifiants OAuth ChatGPT n'ont pas de tokens.access_token.", + "httpError": "Codex HTTP {{status}} (req: {{requestId}}) model={{modelId}} : {{message}}", + "noResponseBody": "Erreur de réponses ChatGPT : Aucun corps de réponse", + "emptyStream": "Le flux de réponses ChatGPT n'a retourné aucun contenu pour le modèle {{modelId}}" + }, "api": { "invalidKeyInvalidChars": "La clé API contient des caractères invalides." }, diff --git a/src/i18n/locales/hi/common.json b/src/i18n/locales/hi/common.json index ab7d594e8f..34bce6bd31 100644 --- a/src/i18n/locales/hi/common.json +++ b/src/i18n/locales/hi/common.json @@ -114,6 +114,15 @@ "roo": { "authenticationRequired": "Roo प्रदाता को क्लाउड प्रमाणीकरण की आवश्यकता है। कृपया Roo Code Cloud में साइन इन करें।" }, + "openaiNativeCodex": { + "oauthReadFailed": "{{path}} पर ChatGPT OAuth क्रेडेंशियल लोड करने में विफल: {{error}}। सुझाव: auth.json बनाने के लिए Codex CLI के साथ प्रमाणित करें (जैसे, \"codex login\")।", + "oauthParseFailed": "{{path}} पर ChatGPT OAuth क्रेडेंशियल JSON पार्स करने में विफल: {{error}}। सुझाव: सुनिश्चित करें कि फ़ाइल वैध JSON है या इसे पुनर्जनित करने के लिए \"codex login\" के साथ पुनः प्रमाणित करें।", + "oauthFileTooLarge": "{{path}} पर OAuth क्रेडेंशियल फ़ाइल बहुत बड़ी है ({{size}} बाइट्स)। अधिकतम अनुमतित {{max}} बाइट्स है।", + "missingAccessToken": "ChatGPT OAuth क्रेडेंशियल में tokens.access_token गुम है।", + "httpError": "Codex HTTP {{status}} (req: {{requestId}}) model={{modelId}}: {{message}}", + "noResponseBody": "ChatGPT प्रतिक्रिया त्रुटि: कोई प्रतिक्रिया बॉडी नहीं", + "emptyStream": "ChatGPT प्रतिक्रिया स्ट्रीम ने मॉडल {{modelId}} के लिए कोई सामग्री वापस नहीं की" + }, "api": { "invalidKeyInvalidChars": "API कुंजी में अमान्य वर्ण हैं।" }, diff --git a/src/i18n/locales/id/common.json b/src/i18n/locales/id/common.json index ddd549b6f0..f7fb7abfcf 100644 --- a/src/i18n/locales/id/common.json +++ b/src/i18n/locales/id/common.json @@ -114,6 +114,15 @@ "roo": { "authenticationRequired": "Penyedia Roo memerlukan autentikasi cloud. Silakan masuk ke Roo Code Cloud." }, + "openaiNativeCodex": { + "oauthReadFailed": "Gagal memuat kredensial OAuth ChatGPT di {{path}}: {{error}}. Tips: autentikasi dengan Codex CLI (mis., \"codex login\") untuk membuat auth.json.", + "oauthParseFailed": "Gagal mengurai JSON kredensial OAuth ChatGPT di {{path}}: {{error}}. Tips: pastikan file adalah JSON yang valid atau autentikasi ulang dengan \"codex login\" untuk meregenerasi.", + "oauthFileTooLarge": "File kredensial OAuth di {{path}} terlalu besar ({{size}} byte). Maksimum yang diizinkan adalah {{max}} byte.", + "missingAccessToken": "Kredensial OAuth ChatGPT tidak memiliki tokens.access_token.", + "httpError": "Codex HTTP {{status}} (req: {{requestId}}) model={{modelId}}: {{message}}", + "noResponseBody": "Error respons ChatGPT: Tidak ada body respons", + "emptyStream": "Stream respons ChatGPT tidak mengembalikan konten untuk model {{modelId}}" + }, "api": { "invalidKeyInvalidChars": "Kunci API mengandung karakter tidak valid." }, diff --git a/src/i18n/locales/it/common.json b/src/i18n/locales/it/common.json index 80e8e0633b..c2a34557ef 100644 --- a/src/i18n/locales/it/common.json +++ b/src/i18n/locales/it/common.json @@ -114,6 +114,15 @@ "roo": { "authenticationRequired": "Il provider Roo richiede l'autenticazione cloud. Accedi a Roo Code Cloud." }, + "openaiNativeCodex": { + "oauthReadFailed": "Impossibile caricare le credenziali OAuth di ChatGPT in {{path}}: {{error}}. Suggerimento: autenticati con la CLI Codex (es. \"codex login\") per creare auth.json.", + "oauthParseFailed": "Impossibile analizzare il JSON delle credenziali OAuth di ChatGPT in {{path}}: {{error}}. Suggerimento: assicurati che il file sia JSON valido o ri-autenticati con \"codex login\" per rigenerarlo.", + "oauthFileTooLarge": "Il file delle credenziali OAuth in {{path}} è troppo grande ({{size}} byte). Il massimo consentito è {{max}} byte.", + "missingAccessToken": "Le credenziali OAuth di ChatGPT non hanno tokens.access_token.", + "httpError": "Codex HTTP {{status}} (req: {{requestId}}) model={{modelId}}: {{message}}", + "noResponseBody": "Errore risposte ChatGPT: Nessun corpo di risposta", + "emptyStream": "Il flusso di risposte ChatGPT non ha restituito contenuto per il modello {{modelId}}" + }, "api": { "invalidKeyInvalidChars": "La chiave API contiene caratteri non validi." }, diff --git a/src/i18n/locales/ja/common.json b/src/i18n/locales/ja/common.json index accba790a2..21cf4ad30c 100644 --- a/src/i18n/locales/ja/common.json +++ b/src/i18n/locales/ja/common.json @@ -114,6 +114,15 @@ "roo": { "authenticationRequired": "Rooプロバイダーはクラウド認証が必要です。Roo Code Cloudにサインインしてください。" }, + "openaiNativeCodex": { + "oauthReadFailed": "{{path}}でChatGPT OAuth認証情報の読み込みに失敗しました: {{error}}。ヒント: Codex CLI(例:\"codex login\")で認証してauth.jsonを作成してください。", + "oauthParseFailed": "{{path}}でChatGPT OAuth認証情報JSONの解析に失敗しました: {{error}}。ヒント: ファイルが有効なJSONであることを確認するか、\"codex login\"で再認証して再生成してください。", + "oauthFileTooLarge": "{{path}}のOAuth認証情報ファイルが大きすぎます({{size}}バイト)。最大許可サイズは{{max}}バイトです。", + "missingAccessToken": "ChatGPT OAuth認証情報にtokens.access_tokenがありません。", + "httpError": "Codex HTTP {{status}} (req: {{requestId}}) model={{modelId}}: {{message}}", + "noResponseBody": "ChatGPTレスポンスエラー: レスポンスボディがありません", + "emptyStream": "ChatGPTレスポンスストリームがモデル{{modelId}}のコンテンツを返しませんでした" + }, "api": { "invalidKeyInvalidChars": "APIキーに無効な文字が含まれています。" }, diff --git a/src/i18n/locales/ko/common.json b/src/i18n/locales/ko/common.json index acb7bd47d7..9a95714ca1 100644 --- a/src/i18n/locales/ko/common.json +++ b/src/i18n/locales/ko/common.json @@ -114,6 +114,15 @@ "roo": { "authenticationRequired": "Roo 제공업체는 클라우드 인증이 필요합니다. Roo Code Cloud에 로그인하세요." }, + "openaiNativeCodex": { + "oauthReadFailed": "{{path}}에서 ChatGPT OAuth 자격 증명 로드 실패: {{error}}. 팁: Codex CLI(예: \"codex login\")로 인증하여 auth.json을 생성하세요.", + "oauthParseFailed": "{{path}}에서 ChatGPT OAuth 자격 증명 JSON 파싱 실패: {{error}}. 팁: 파일이 유효한 JSON인지 확인하거나 \"codex login\"으로 재인증하여 재생성하세요.", + "oauthFileTooLarge": "{{path}}의 OAuth 자격 증명 파일이 너무 큽니다({{size}}바이트). 최대 허용 크기는 {{max}}바이트입니다.", + "missingAccessToken": "ChatGPT OAuth 자격 증명에 tokens.access_token이 없습니다.", + "httpError": "Codex HTTP {{status}} (req: {{requestId}}) model={{modelId}}: {{message}}", + "noResponseBody": "ChatGPT 응답 오류: 응답 본문 없음", + "emptyStream": "ChatGPT 응답 스트림이 모델 {{modelId}}에 대한 콘텐츠를 반환하지 않았습니다" + }, "api": { "invalidKeyInvalidChars": "API 키에 유효하지 않은 문자가 포함되어 있습니다." }, diff --git a/src/i18n/locales/nl/common.json b/src/i18n/locales/nl/common.json index d43690c435..36398dc853 100644 --- a/src/i18n/locales/nl/common.json +++ b/src/i18n/locales/nl/common.json @@ -114,6 +114,15 @@ "roo": { "authenticationRequired": "Roo provider vereist cloud authenticatie. Log in bij Roo Code Cloud." }, + "openaiNativeCodex": { + "oauthReadFailed": "Laden van ChatGPT OAuth-referenties op {{path}} mislukt: {{error}}. Tip: authenticeer met de Codex CLI (bijv. \"codex login\") om auth.json aan te maken.", + "oauthParseFailed": "Parsen van ChatGPT OAuth-referenties JSON op {{path}} mislukt: {{error}}. Tip: zorg ervoor dat het bestand geldige JSON is of authenticeer opnieuw met \"codex login\" om het te regenereren.", + "oauthFileTooLarge": "OAuth-referentiebestand op {{path}} is te groot ({{size}} bytes). Maximum toegestaan is {{max}} bytes.", + "missingAccessToken": "ChatGPT OAuth-referenties missen tokens.access_token.", + "httpError": "Codex HTTP {{status}} (req: {{requestId}}) model={{modelId}}: {{message}}", + "noResponseBody": "ChatGPT Responses fout: Geen response body", + "emptyStream": "ChatGPT Responses stream retourneerde geen inhoud voor model {{modelId}}" + }, "api": { "invalidKeyInvalidChars": "API-sleutel bevat ongeldige karakters." }, diff --git a/src/i18n/locales/pl/common.json b/src/i18n/locales/pl/common.json index 56c076f785..4ca02b4458 100644 --- a/src/i18n/locales/pl/common.json +++ b/src/i18n/locales/pl/common.json @@ -114,6 +114,15 @@ "roo": { "authenticationRequired": "Dostawca Roo wymaga uwierzytelnienia w chmurze. Zaloguj się do Roo Code Cloud." }, + "openaiNativeCodex": { + "oauthReadFailed": "Nie udało się załadować danych uwierzytelniających OAuth ChatGPT w {{path}}: {{error}}. Wskazówka: uwierzytelnij się za pomocą Codex CLI (np. \"codex login\"), aby utworzyć auth.json.", + "oauthParseFailed": "Nie udało się przeanalizować JSON danych uwierzytelniających OAuth ChatGPT w {{path}}: {{error}}. Wskazówka: upewnij się, że plik jest prawidłowym JSON lub ponownie uwierzytelnij się za pomocą \"codex login\", aby go zregenerować.", + "oauthFileTooLarge": "Plik danych uwierzytelniających OAuth w {{path}} jest za duży ({{size}} bajtów). Maksymalny dozwolony rozmiar to {{max}} bajtów.", + "missingAccessToken": "Dane uwierzytelniające OAuth ChatGPT nie zawierają tokens.access_token.", + "httpError": "Codex HTTP {{status}} (req: {{requestId}}) model={{modelId}}: {{message}}", + "noResponseBody": "Błąd odpowiedzi ChatGPT: Brak treści odpowiedzi", + "emptyStream": "Strumień odpowiedzi ChatGPT nie zwrócił zawartości dla modelu {{modelId}}" + }, "api": { "invalidKeyInvalidChars": "Klucz API zawiera nieprawidłowe znaki." }, diff --git a/src/i18n/locales/pt-BR/common.json b/src/i18n/locales/pt-BR/common.json index c2cd63255f..663d2a0e1b 100644 --- a/src/i18n/locales/pt-BR/common.json +++ b/src/i18n/locales/pt-BR/common.json @@ -118,6 +118,15 @@ "roo": { "authenticationRequired": "O provedor Roo requer autenticação na nuvem. Faça login no Roo Code Cloud." }, + "openaiNativeCodex": { + "oauthReadFailed": "Falha ao carregar credenciais OAuth do ChatGPT em {{path}}: {{error}}. Dica: autentique-se com a CLI do Codex (ex: \"codex login\") para criar auth.json.", + "oauthParseFailed": "Falha ao analisar JSON das credenciais OAuth do ChatGPT em {{path}}: {{error}}. Dica: certifique-se de que o arquivo seja JSON válido ou autentique-se novamente com \"codex login\" para regenerá-lo.", + "oauthFileTooLarge": "Arquivo de credenciais OAuth em {{path}} é muito grande ({{size}} bytes). O máximo permitido é {{max}} bytes.", + "missingAccessToken": "Credenciais OAuth do ChatGPT estão faltando tokens.access_token.", + "httpError": "Codex HTTP {{status}} (req: {{requestId}}) model={{modelId}}: {{message}}", + "noResponseBody": "Erro de respostas do ChatGPT: Sem corpo de resposta", + "emptyStream": "Stream de respostas do ChatGPT não retornou conteúdo para o modelo {{modelId}}" + }, "api": { "invalidKeyInvalidChars": "A chave API contém caracteres inválidos." }, diff --git a/src/i18n/locales/ru/common.json b/src/i18n/locales/ru/common.json index 9595f1f276..c5897d27ce 100644 --- a/src/i18n/locales/ru/common.json +++ b/src/i18n/locales/ru/common.json @@ -114,6 +114,15 @@ "roo": { "authenticationRequired": "Провайдер Roo требует облачной аутентификации. Войдите в Roo Code Cloud." }, + "openaiNativeCodex": { + "oauthReadFailed": "Не удалось загрузить учетные данные OAuth ChatGPT по пути {{path}}: {{error}}. Совет: аутентифицируйтесь с помощью Codex CLI (например, \"codex login\") для создания auth.json.", + "oauthParseFailed": "Не удалось разобрать JSON учетных данных OAuth ChatGPT по пути {{path}}: {{error}}. Совет: убедитесь, что файл является действительным JSON, или повторно аутентифицируйтесь с помощью \"codex login\" для его регенерации.", + "oauthFileTooLarge": "Файл учетных данных OAuth по пути {{path}} слишком большой ({{size}} байт). Максимально допустимый размер {{max}} байт.", + "missingAccessToken": "В учетных данных OAuth ChatGPT отсутствует tokens.access_token.", + "httpError": "Codex HTTP {{status}} (req: {{requestId}}) model={{modelId}}: {{message}}", + "noResponseBody": "Ошибка ответов ChatGPT: Нет тела ответа", + "emptyStream": "Поток ответов ChatGPT не вернул содержимое для модели {{modelId}}" + }, "api": { "invalidKeyInvalidChars": "API-ключ содержит недопустимые символы." }, diff --git a/src/i18n/locales/tr/common.json b/src/i18n/locales/tr/common.json index aa11041110..a6829617f4 100644 --- a/src/i18n/locales/tr/common.json +++ b/src/i18n/locales/tr/common.json @@ -114,6 +114,15 @@ "roo": { "authenticationRequired": "Roo sağlayıcısı bulut kimlik doğrulaması gerektirir. Lütfen Roo Code Cloud'a giriş yapın." }, + "openaiNativeCodex": { + "oauthReadFailed": "{{path}} konumunda ChatGPT OAuth kimlik bilgileri yüklenemedi: {{error}}. İpucu: auth.json oluşturmak için Codex CLI ile kimlik doğrulaması yapın (örn. \"codex login\").", + "oauthParseFailed": "{{path}} konumunda ChatGPT OAuth kimlik bilgileri JSON'u ayrıştırılamadı: {{error}}. İpucu: dosyanın geçerli JSON olduğundan emin olun veya yeniden oluşturmak için \"codex login\" ile yeniden kimlik doğrulaması yapın.", + "oauthFileTooLarge": "{{path}} konumundaki OAuth kimlik bilgileri dosyası çok büyük ({{size}} bayt). İzin verilen maksimum {{max}} bayttır.", + "missingAccessToken": "ChatGPT OAuth kimlik bilgilerinde tokens.access_token eksik.", + "httpError": "Codex HTTP {{status}} (req: {{requestId}}) model={{modelId}}: {{message}}", + "noResponseBody": "ChatGPT Yanıtları hatası: Yanıt gövdesi yok", + "emptyStream": "ChatGPT Yanıtları akışı {{modelId}} modeli için içerik döndürmedi" + }, "api": { "invalidKeyInvalidChars": "API anahtarı geçersiz karakterler içeriyor." }, diff --git a/src/i18n/locales/vi/common.json b/src/i18n/locales/vi/common.json index b4b92b373e..8979ed97bd 100644 --- a/src/i18n/locales/vi/common.json +++ b/src/i18n/locales/vi/common.json @@ -114,6 +114,15 @@ "roo": { "authenticationRequired": "Nhà cung cấp Roo yêu cầu xác thực đám mây. Vui lòng đăng nhập vào Roo Code Cloud." }, + "openaiNativeCodex": { + "oauthReadFailed": "Không thể tải thông tin xác thực OAuth ChatGPT tại {{path}}: {{error}}. Mẹo: xác thực với Codex CLI (ví dụ: \"codex login\") để tạo auth.json.", + "oauthParseFailed": "Không thể phân tích JSON thông tin xác thực OAuth ChatGPT tại {{path}}: {{error}}. Mẹo: đảm bảo tệp là JSON hợp lệ hoặc xác thực lại với \"codex login\" để tạo lại.", + "oauthFileTooLarge": "Tệp thông tin xác thực OAuth tại {{path}} quá lớn ({{size}} byte). Kích thước tối đa cho phép là {{max}} byte.", + "missingAccessToken": "Thông tin xác thực OAuth ChatGPT thiếu tokens.access_token.", + "httpError": "Codex HTTP {{status}} (req: {{requestId}}) model={{modelId}}: {{message}}", + "noResponseBody": "Lỗi phản hồi ChatGPT: Không có nội dung phản hồi", + "emptyStream": "Luồng phản hồi ChatGPT không trả về nội dung cho mô hình {{modelId}}" + }, "api": { "invalidKeyInvalidChars": "Khóa API chứa ký tự không hợp lệ." }, diff --git a/src/i18n/locales/zh-CN/common.json b/src/i18n/locales/zh-CN/common.json index 8c42744484..63e8799b8d 100644 --- a/src/i18n/locales/zh-CN/common.json +++ b/src/i18n/locales/zh-CN/common.json @@ -119,6 +119,15 @@ "roo": { "authenticationRequired": "Roo 提供商需要云认证。请登录 Roo Code Cloud。" }, + "openaiNativeCodex": { + "oauthReadFailed": "无法在 {{path}} 加载 ChatGPT OAuth 凭据:{{error}}。提示:使用 Codex CLI 进行身份验证(例如 \"codex login\")以创建 auth.json。", + "oauthParseFailed": "无法在 {{path}} 解析 ChatGPT OAuth 凭据 JSON:{{error}}。提示:确保文件是有效的 JSON 或使用 \"codex login\" 重新验证以重新生成。", + "oauthFileTooLarge": "{{path}} 处的 OAuth 凭据文件过大({{size}} 字节)。最大允许大小为 {{max}} 字节。", + "missingAccessToken": "ChatGPT OAuth 凭据缺少 tokens.access_token。", + "httpError": "Codex HTTP {{status}} (req: {{requestId}}) model={{modelId}}: {{message}}", + "noResponseBody": "ChatGPT 响应错误:无响应正文", + "emptyStream": "ChatGPT 响应流未为模型 {{modelId}} 返回内容" + }, "api": { "invalidKeyInvalidChars": "API 密钥包含无效字符。" }, diff --git a/src/i18n/locales/zh-TW/common.json b/src/i18n/locales/zh-TW/common.json index 5a31d601b4..94e207e56c 100644 --- a/src/i18n/locales/zh-TW/common.json +++ b/src/i18n/locales/zh-TW/common.json @@ -113,6 +113,15 @@ "roo": { "authenticationRequired": "Roo 提供者需要雲端認證。請登入 Roo Code Cloud。" }, + "openaiNativeCodex": { + "oauthReadFailed": "無法在 {{path}} 載入 ChatGPT OAuth 憑證:{{error}}。提示:使用 Codex CLI 進行驗證(例如 \"codex login\")以建立 auth.json。", + "oauthParseFailed": "無法在 {{path}} 解析 ChatGPT OAuth 憑證 JSON:{{error}}。提示:確保檔案是有效的 JSON 或使用 \"codex login\" 重新驗證以重新產生。", + "oauthFileTooLarge": "{{path}} 的 OAuth 憑證檔案過大({{size}} 位元組)。允許的最大大小為 {{max}} 位元組。", + "missingAccessToken": "ChatGPT OAuth 憑證缺少 tokens.access_token。", + "httpError": "Codex HTTP {{status}} (req: {{requestId}}) model={{modelId}}: {{message}}", + "noResponseBody": "ChatGPT 回應錯誤:無回應內容", + "emptyStream": "ChatGPT 回應串流未為模型 {{modelId}} 傳回內容" + }, "api": { "invalidKeyInvalidChars": "API 金鑰包含無效字元。" }, diff --git a/webview-ui/src/components/settings/ApiOptions.tsx b/webview-ui/src/components/settings/ApiOptions.tsx index 3b6536f75b..5ff11c6119 100644 --- a/webview-ui/src/components/settings/ApiOptions.tsx +++ b/webview-ui/src/components/settings/ApiOptions.tsx @@ -14,6 +14,7 @@ import { unboundDefaultModelId, litellmDefaultModelId, openAiNativeDefaultModelId, + openAiNativeCodexDefaultModelId, anthropicDefaultModelId, doubaoDefaultModelId, claudeCodeDefaultModelId, @@ -84,6 +85,7 @@ import { OpenAICompatible, OpenRouter, QwenCode, + OpenAiNativeCodex, Requesty, SambaNova, Unbound, @@ -320,6 +322,7 @@ const ApiOptions = ({ "claude-code": { field: "apiModelId", default: claudeCodeDefaultModelId }, "qwen-code": { field: "apiModelId", default: qwenCodeDefaultModelId }, "openai-native": { field: "apiModelId", default: openAiNativeDefaultModelId }, + "openai-native-codex": { field: "apiModelId", default: openAiNativeCodexDefaultModelId }, gemini: { field: "apiModelId", default: geminiDefaultModelId }, deepseek: { field: "apiModelId", default: deepSeekDefaultModelId }, doubao: { field: "apiModelId", default: doubaoDefaultModelId }, @@ -375,6 +378,7 @@ const ApiOptions = ({ // Get the URL slug - use custom mapping if available, otherwise use the provider key. const slugs: Record = { "openai-native": "openai", + "openai-native-codex": "openai-codex", openai: "openai-compatible", } @@ -519,6 +523,13 @@ const ApiOptions = ({ /> )} + {selectedProvider === "openai-native-codex" && ( + + )} + {selectedProvider === "mistral" && ( )} @@ -693,8 +704,11 @@ const ApiOptions = ({ } // Clear reasoning effort when switching models to allow the new model's default to take effect - // This is especially important for GPT-5 models which default to "medium" - if (selectedProvider === "openai-native") { + // Applies to both OpenAI Native and ChatGPT Codex providers + if ( + selectedProvider === "openai-native" || + selectedProvider === "openai-native-codex" + ) { setApiConfigurationField("reasoningEffort", undefined) } }}> diff --git a/webview-ui/src/components/settings/ThinkingBudget.tsx b/webview-ui/src/components/settings/ThinkingBudget.tsx index 7a85e61e7a..eecd45f275 100644 --- a/webview-ui/src/components/settings/ThinkingBudget.tsx +++ b/webview-ui/src/components/settings/ThinkingBudget.tsx @@ -34,9 +34,16 @@ const shouldShowMinimalOption = ( modelId: string | undefined, supportsEffort: boolean | undefined, ): boolean => { - const isGpt5Model = provider === "openai-native" && modelId?.startsWith("gpt-5") + // Keep existing behavior for native OpenAI provider + const isGpt5Native = provider === "openai-native" && modelId?.startsWith("gpt-5") + + // For ChatGPT Codex provider, only expose "minimal" for the regular gpt-5 model, + // not for the "gpt-5-codex" variant + const isGpt5CodexRegular = provider === "openai-native-codex" && modelId === "gpt-5" + const isOpenRouterWithEffort = provider === "openrouter" && supportsEffort === true - return !!(isGpt5Model || isOpenRouterWithEffort) + + return !!(isGpt5Native || isGpt5CodexRegular || isOpenRouterWithEffort) } export const ThinkingBudget = ({ apiConfiguration, setApiConfigurationField, modelInfo }: ThinkingBudgetProps) => { @@ -65,8 +72,7 @@ export const ThinkingBudget = ({ apiConfiguration, setApiConfigurationField, mod ? (["minimal", ...baseEfforts] as ReasoningEffortWithMinimal[]) : baseEfforts - // Default reasoning effort - use model's default if available - // GPT-5 models have "medium" as their default in the model configuration + // Default reasoning effort - use model's default if available (no special-case overrides) const modelDefaultReasoningEffort = modelInfo?.reasoningEffort as ReasoningEffortWithMinimal | undefined const defaultReasoningEffort: ReasoningEffortWithMinimal = modelDefaultReasoningEffort || "medium" const currentReasoningEffort: ReasoningEffortWithMinimal = diff --git a/webview-ui/src/components/settings/constants.ts b/webview-ui/src/components/settings/constants.ts index ae336730ff..a7552fee5b 100644 --- a/webview-ui/src/components/settings/constants.ts +++ b/webview-ui/src/components/settings/constants.ts @@ -10,6 +10,7 @@ import { geminiModels, mistralModels, openAiNativeModels, + openAiNativeCodexModels, qwenCodeModels, vertexModels, xaiModels, @@ -34,6 +35,7 @@ export const MODELS_BY_PROVIDER: Partial void +} + +export const OpenAiNativeCodex: React.FC = ({ apiConfiguration, setApiConfigurationField }) => { + const { t } = useAppTranslation() + const defaultPath = "~/.codex/auth.json" + + const handleInputChange = (e: Event | React.FormEvent) => { + const element = e.target as HTMLInputElement + setApiConfigurationField("openAiNativeCodexOauthPath", element.value) + } + + return ( +
+
+ + + + +

+ {t("settings:providers.openAiNativeCodex.oauthPathDescription", { defaultPath })} +

+ +
+ {t("settings:providers.openAiNativeCodex.oauthCliDescription")} +
+ +
+ {t("settings:providers.openAiNativeCodex.oauthConnectDescription")} +
+ + + {t("settings:providers.openAiNativeCodex.learnMoreLinkText")} + +
+
+ ) +} diff --git a/webview-ui/src/components/settings/providers/index.ts b/webview-ui/src/components/settings/providers/index.ts index fe0e6cecf9..bc6866c306 100644 --- a/webview-ui/src/components/settings/providers/index.ts +++ b/webview-ui/src/components/settings/providers/index.ts @@ -30,3 +30,4 @@ export { Fireworks } from "./Fireworks" export { Featherless } from "./Featherless" export { VercelAiGateway } from "./VercelAiGateway" export { DeepInfra } from "./DeepInfra" +export { OpenAiNativeCodex } from "./OpenAiNativeCodex" diff --git a/webview-ui/src/components/ui/hooks/useSelectedModel.ts b/webview-ui/src/components/ui/hooks/useSelectedModel.ts index 3a24df2f85..3c85f9a2ee 100644 --- a/webview-ui/src/components/ui/hooks/useSelectedModel.ts +++ b/webview-ui/src/components/ui/hooks/useSelectedModel.ts @@ -19,6 +19,8 @@ import { openAiModelInfoSaneDefaults, openAiNativeDefaultModelId, openAiNativeModels, + openAiNativeCodexDefaultModelId, + openAiNativeCodexModels, vertexDefaultModelId, vertexModels, xaiDefaultModelId, @@ -250,6 +252,11 @@ function getSelectedModel({ const info = openAiNativeModels[id as keyof typeof openAiNativeModels] return { id, info } } + case "openai-native-codex": { + const id = apiConfiguration.apiModelId ?? openAiNativeCodexDefaultModelId + const info = openAiNativeCodexModels[id as keyof typeof openAiNativeCodexModels] + return { id, info } + } case "mistral": { const id = apiConfiguration.apiModelId ?? mistralDefaultModelId const info = mistralModels[id as keyof typeof mistralModels] @@ -360,7 +367,13 @@ function getSelectedModel({ // case "human-relay": // case "fake-ai": default: { - provider satisfies "anthropic" | "gemini-cli" | "qwen-code" | "human-relay" | "fake-ai" + provider satisfies + | "anthropic" + | "gemini-cli" + | "qwen-code" + | "human-relay" + | "fake-ai" + | "openai-native-codex" const id = apiConfiguration.apiModelId ?? anthropicDefaultModelId const baseInfo = anthropicModels[id as keyof typeof anthropicModels] diff --git a/webview-ui/src/i18n/locales/ca/settings.json b/webview-ui/src/i18n/locales/ca/settings.json index 2aa6b7ad72..ccfd88638d 100644 --- a/webview-ui/src/i18n/locales/ca/settings.json +++ b/webview-ui/src/i18n/locales/ca/settings.json @@ -399,6 +399,13 @@ "authenticatedMessage": "Autenticat de forma segura a través del teu compte de Roo Code Cloud.", "connectButton": "Connecta amb Roo Code Cloud" }, + "openAiNativeCodex": { + "oauthPathLabel": "Ruta de credencials OAuth", + "oauthPathDescription": "Ruta a les teves credencials auth.json de ChatGPT Codex. Per defecte {{defaultPath}} si es deixa buit (Windows: C:\\\\Users\\\\USERNAME\\\\.codex\\\\auth.json).", + "oauthCliDescription": "ChatGPT Codex utilitza les teves credencials web de ChatGPT a través de la CLI oficial de Codex. Autentica't amb la CLI de Codex perquè es creï auth.json. Si utilitzes una ubicació personalitzada, estableix aquí la ruta completa del fitxer.", + "oauthConnectDescription": "Després de l'autenticació, Roo llegirà el token d'accés des d'auth.json i es connectarà a ChatGPT Responses (Codex).", + "learnMoreLinkText": "Aprèn més sobre ChatGPT" + }, "openRouter": { "providerRouting": { "title": "Encaminament de Proveïdors d'OpenRouter", @@ -827,7 +834,8 @@ "providerNotAllowed": "El proveïdor '{{provider}}' no està permès per la vostra organització", "modelNotAllowed": "El model '{{model}}' no està permès per al proveïdor '{{provider}}' per la vostra organització", "profileInvalid": "Aquest perfil conté un proveïdor o model que no està permès per la vostra organització", - "qwenCodeOauthPath": "Has de proporcionar una ruta vàlida de credencials OAuth" + "qwenCodeOauthPath": "Has de proporcionar una ruta vàlida de credencials OAuth", + "openAiNativeCodexOauthPath": "Opcional: Camí a l'auth.json de ChatGPT Codex. Quan estigui buit, per defecte és ~/.codex/auth.json." }, "placeholders": { "apiKey": "Introduïu la clau API...", diff --git a/webview-ui/src/i18n/locales/de/settings.json b/webview-ui/src/i18n/locales/de/settings.json index a96e215185..b371440b7b 100644 --- a/webview-ui/src/i18n/locales/de/settings.json +++ b/webview-ui/src/i18n/locales/de/settings.json @@ -399,6 +399,13 @@ "authenticatedMessage": "Sicher authentifiziert über dein Roo Code Cloud-Konto.", "connectButton": "Mit Roo Code Cloud verbinden" }, + "openAiNativeCodex": { + "oauthPathLabel": "OAuth-Anmeldedaten-Pfad", + "oauthPathDescription": "Pfad zu deinen ChatGPT Codex auth.json-Anmeldedaten. Standardmäßig {{defaultPath}}, wenn leer gelassen (Windows: C:\\\\Users\\\\USERNAME\\\\.codex\\\\auth.json).", + "oauthCliDescription": "ChatGPT Codex verwendet deine ChatGPT-Web-Anmeldedaten über die offizielle Codex CLI. Authentifiziere dich mit der Codex CLI, damit auth.json erstellt wird. Wenn du einen benutzerdefinierten Speicherort verwendest, gib hier den vollständigen Dateipfad an.", + "oauthConnectDescription": "Nach der Authentifizierung liest Roo das Zugriffstoken aus auth.json und verbindet sich mit ChatGPT Responses (Codex).", + "learnMoreLinkText": "Mehr über ChatGPT erfahren" + }, "openRouter": { "providerRouting": { "title": "OpenRouter Anbieter-Routing", @@ -827,7 +834,8 @@ "providerNotAllowed": "Anbieter '{{provider}}' ist von deiner Organisation nicht erlaubt", "modelNotAllowed": "Modell '{{model}}' ist für Anbieter '{{provider}}' von deiner Organisation nicht erlaubt", "profileInvalid": "Dieses Profil enthält einen Anbieter oder ein Modell, das von deiner Organisation nicht erlaubt ist", - "qwenCodeOauthPath": "Du musst einen gültigen OAuth-Anmeldedaten-Pfad angeben" + "qwenCodeOauthPath": "Du musst einen gültigen OAuth-Anmeldedaten-Pfad angeben", + "openAiNativeCodexOauthPath": "Optional: Pfad zur ChatGPT Codex auth.json. Wenn leer, wird standardmäßig ~/.codex/auth.json verwendet." }, "placeholders": { "apiKey": "API-Schlüssel eingeben...", diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index aa3199e8e8..b14698eb8d 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -404,6 +404,13 @@ "authenticatedMessage": "Securely authenticated through your Roo Code Cloud account.", "connectButton": "Connect to Roo Code Cloud" }, + "openAiNativeCodex": { + "oauthPathLabel": "OAuth Credentials Path", + "oauthPathDescription": "Path to your ChatGPT Codex auth.json credentials. Defaults to {{defaultPath}} if left empty (Windows: C:\\\\Users\\\\USERNAME\\\\.codex\\\\auth.json).", + "oauthCliDescription": "ChatGPT Codex uses your ChatGPT web credentials via the official Codex CLI. Authenticate with the Codex CLI so that auth.json is created. If you use a custom location, set the full file path here.", + "oauthConnectDescription": "After authentication, Roo will read the access token from auth.json and connect to ChatGPT Responses (Codex).", + "learnMoreLinkText": "Learn more about ChatGPT" + }, "openRouter": { "providerRouting": { "title": "OpenRouter Provider Routing", @@ -832,7 +839,8 @@ "providerNotAllowed": "Provider '{{provider}}' is not allowed by your organization", "modelNotAllowed": "Model '{{model}}' is not allowed for provider '{{provider}}' by your organization", "profileInvalid": "This profile contains a provider or model that is not allowed by your organization", - "qwenCodeOauthPath": "You must provide a valid OAuth credentials path." + "qwenCodeOauthPath": "You must provide a valid OAuth credentials path.", + "openAiNativeCodexOauthPath": "Optional: Path to ChatGPT Codex auth.json. When empty, defaults to ~/.codex/auth.json." }, "placeholders": { "apiKey": "Enter API Key...", diff --git a/webview-ui/src/i18n/locales/es/settings.json b/webview-ui/src/i18n/locales/es/settings.json index 44c1b9496d..645549c128 100644 --- a/webview-ui/src/i18n/locales/es/settings.json +++ b/webview-ui/src/i18n/locales/es/settings.json @@ -399,6 +399,13 @@ "authenticatedMessage": "Autenticado de forma segura a través de tu cuenta de Roo Code Cloud.", "connectButton": "Conectar a Roo Code Cloud" }, + "openAiNativeCodex": { + "oauthPathLabel": "Ruta de credenciales OAuth", + "oauthPathDescription": "Ruta a tus credenciales auth.json de ChatGPT Codex. Por defecto {{defaultPath}} si se deja vacío (Windows: C:\\\\Users\\\\USERNAME\\\\.codex\\\\auth.json).", + "oauthCliDescription": "ChatGPT Codex usa tus credenciales web de ChatGPT a través del CLI oficial de Codex. Autentícate con el CLI de Codex para que se cree auth.json. Si usas una ubicación personalizada, establece aquí la ruta completa del archivo.", + "oauthConnectDescription": "Después de la autenticación, Roo leerá el token de acceso desde auth.json y se conectará a ChatGPT Responses (Codex).", + "learnMoreLinkText": "Aprende más sobre ChatGPT" + }, "openRouter": { "providerRouting": { "title": "Enrutamiento de Proveedores de OpenRouter", @@ -827,7 +834,8 @@ "providerNotAllowed": "El proveedor '{{provider}}' no está permitido por su organización", "modelNotAllowed": "El modelo '{{model}}' no está permitido para el proveedor '{{provider}}' por su organización", "profileInvalid": "Este perfil contiene un proveedor o modelo que no está permitido por su organización", - "qwenCodeOauthPath": "Debes proporcionar una ruta válida de credenciales OAuth" + "qwenCodeOauthPath": "Debes proporcionar una ruta válida de credenciales OAuth", + "openAiNativeCodexOauthPath": "Opcional: Ruta al auth.json de ChatGPT Codex. Cuando esté vacío, por defecto es ~/.codex/auth.json." }, "placeholders": { "apiKey": "Ingrese clave API...", diff --git a/webview-ui/src/i18n/locales/fr/settings.json b/webview-ui/src/i18n/locales/fr/settings.json index cd2b3bef87..4ce7f930f5 100644 --- a/webview-ui/src/i18n/locales/fr/settings.json +++ b/webview-ui/src/i18n/locales/fr/settings.json @@ -399,6 +399,13 @@ "authenticatedMessage": "Authentifié de manière sécurisée via ton compte Roo Code Cloud.", "connectButton": "Se connecter à Roo Code Cloud" }, + "openAiNativeCodex": { + "oauthPathLabel": "Chemin des identifiants OAuth", + "oauthPathDescription": "Chemin vers vos identifiants auth.json de ChatGPT Codex. Par défaut {{defaultPath}} si laissé vide (Windows: C:\\\\Users\\\\USERNAME\\\\.codex\\\\auth.json).", + "oauthCliDescription": "ChatGPT Codex utilise vos identifiants web ChatGPT via le CLI officiel Codex. Authentifiez-vous avec le CLI Codex pour que auth.json soit créé. Si vous utilisez un emplacement personnalisé, définissez ici le chemin complet du fichier.", + "oauthConnectDescription": "Après l'authentification, Roo lira le token d'accès depuis auth.json et se connectera à ChatGPT Responses (Codex).", + "learnMoreLinkText": "En savoir plus sur ChatGPT" + }, "openRouter": { "providerRouting": { "title": "Routage des fournisseurs OpenRouter", @@ -827,7 +834,8 @@ "providerNotAllowed": "Le fournisseur '{{provider}}' n'est pas autorisé par votre organisation", "modelNotAllowed": "Le modèle '{{model}}' n'est pas autorisé pour le fournisseur '{{provider}}' par votre organisation", "profileInvalid": "Ce profil contient un fournisseur ou un modèle qui n'est pas autorisé par votre organisation", - "qwenCodeOauthPath": "Tu dois fournir un chemin valide pour les identifiants OAuth" + "qwenCodeOauthPath": "Tu dois fournir un chemin valide pour les identifiants OAuth", + "openAiNativeCodexOauthPath": "Optionnel : Chemin vers l'auth.json de ChatGPT Codex. Quand vide, par défaut ~/.codex/auth.json." }, "placeholders": { "apiKey": "Saisissez la clé API...", diff --git a/webview-ui/src/i18n/locales/hi/settings.json b/webview-ui/src/i18n/locales/hi/settings.json index d9d8184fbb..aee5c979d5 100644 --- a/webview-ui/src/i18n/locales/hi/settings.json +++ b/webview-ui/src/i18n/locales/hi/settings.json @@ -399,6 +399,13 @@ "authenticatedMessage": "आपके Roo Code Cloud खाते के माध्यम से सुरक्षित रूप से प्रमाणित।", "connectButton": "Roo Code Cloud से कनेक्ट करें" }, + "openAiNativeCodex": { + "oauthPathLabel": "OAuth क्रेडेंशियल पथ", + "oauthPathDescription": "आपके ChatGPT Codex auth.json क्रेडेंशियल का पथ। यदि खाली छोड़ा जाए तो डिफ़ॉल्ट {{defaultPath}} (Windows: C:\\\\Users\\\\USERNAME\\\\.codex\\\\auth.json)।", + "oauthCliDescription": "ChatGPT Codex आधिकारिक Codex CLI के माध्यम से आपके ChatGPT वेब क्रेडेंशियल का उपयोग करता है। Codex CLI के साथ प्रमाणित करें ताकि auth.json बनाया जा सके। यदि आप कस्टम स्थान का उपयोग करते हैं, तो यहाँ पूरा फ़ाइल पथ सेट करें।", + "oauthConnectDescription": "प्रमाणीकरण के बाद, Roo auth.json से एक्सेस टोकन पढ़ेगा और ChatGPT Responses (Codex) से कनेक्ट होगा।", + "learnMoreLinkText": "ChatGPT के बारे में और जानें" + }, "openRouter": { "providerRouting": { "title": "OpenRouter प्रदाता रूटिंग", @@ -828,7 +835,8 @@ "providerNotAllowed": "प्रदाता '{{provider}}' आपके संगठन द्वारा अनुमत नहीं है", "modelNotAllowed": "मॉडल '{{model}}' प्रदाता '{{provider}}' के लिए आपके संगठन द्वारा अनुमत नहीं है", "profileInvalid": "इस प्रोफ़ाइल में एक प्रदाता या मॉडल शामिल है जो आपके संगठन द्वारा अनुमत नहीं है", - "qwenCodeOauthPath": "आपको एक वैध OAuth क्रेडेंशियल पथ प्रदान करना होगा" + "qwenCodeOauthPath": "आपको एक वैध OAuth क्रेडेंशियल पथ प्रदान करना होगा", + "openAiNativeCodexOauthPath": "वैकल्पिक: ChatGPT Codex auth.json का पथ। जब खाली हो, तो डिफ़ॉल्ट ~/.codex/auth.json है।" }, "placeholders": { "apiKey": "API कुंजी दर्ज करें...", diff --git a/webview-ui/src/i18n/locales/id/settings.json b/webview-ui/src/i18n/locales/id/settings.json index 187f42958b..e24d2f57eb 100644 --- a/webview-ui/src/i18n/locales/id/settings.json +++ b/webview-ui/src/i18n/locales/id/settings.json @@ -403,6 +403,13 @@ "authenticatedMessage": "Terautentikasi dengan aman melalui akun Roo Code Cloud Anda.", "connectButton": "Hubungkan ke Roo Code Cloud" }, + "openAiNativeCodex": { + "oauthPathLabel": "Jalur Kredensial OAuth", + "oauthPathDescription": "Jalur ke kredensial auth.json ChatGPT Codex Anda. Default ke {{defaultPath}} jika dibiarkan kosong (Windows: C:\\\\Users\\\\USERNAME\\\\.codex\\\\auth.json).", + "oauthCliDescription": "ChatGPT Codex menggunakan kredensial web ChatGPT Anda melalui CLI Codex resmi. Autentikasi dengan CLI Codex agar auth.json dibuat. Jika Anda menggunakan lokasi kustom, atur jalur file lengkap di sini.", + "oauthConnectDescription": "Setelah autentikasi, Roo akan membaca token akses dari auth.json dan terhubung ke ChatGPT Responses (Codex).", + "learnMoreLinkText": "Pelajari lebih lanjut tentang ChatGPT" + }, "openRouter": { "providerRouting": { "title": "OpenRouter Provider Routing", @@ -857,7 +864,8 @@ "providerNotAllowed": "Provider '{{provider}}' tidak diizinkan oleh organisasi kamu", "modelNotAllowed": "Model '{{model}}' tidak diizinkan untuk provider '{{provider}}' oleh organisasi kamu", "profileInvalid": "Profil ini berisi provider atau model yang tidak diizinkan oleh organisasi kamu", - "qwenCodeOauthPath": "Kamu harus memberikan jalur kredensial OAuth yang valid" + "qwenCodeOauthPath": "Kamu harus memberikan jalur kredensial OAuth yang valid", + "openAiNativeCodexOauthPath": "Opsional: Jalur ke auth.json ChatGPT Codex. Ketika kosong, default ke ~/.codex/auth.json." }, "placeholders": { "apiKey": "Masukkan API Key...", diff --git a/webview-ui/src/i18n/locales/it/settings.json b/webview-ui/src/i18n/locales/it/settings.json index 335877b0a8..966a4f4e3e 100644 --- a/webview-ui/src/i18n/locales/it/settings.json +++ b/webview-ui/src/i18n/locales/it/settings.json @@ -399,6 +399,13 @@ "authenticatedMessage": "Autenticato in modo sicuro tramite il tuo account Roo Code Cloud.", "connectButton": "Connetti a Roo Code Cloud" }, + "openAiNativeCodex": { + "oauthPathLabel": "Percorso credenziali OAuth", + "oauthPathDescription": "Percorso alle tue credenziali auth.json di ChatGPT Codex. Predefinito {{defaultPath}} se lasciato vuoto (Windows: C:\\\\Users\\\\USERNAME\\\\.codex\\\\auth.json).", + "oauthCliDescription": "ChatGPT Codex utilizza le tue credenziali web ChatGPT tramite la CLI ufficiale Codex. Autenticati con la CLI Codex in modo che venga creato auth.json. Se usi una posizione personalizzata, imposta qui il percorso completo del file.", + "oauthConnectDescription": "Dopo l'autenticazione, Roo leggerà il token di accesso da auth.json e si connetterà a ChatGPT Responses (Codex).", + "learnMoreLinkText": "Scopri di più su ChatGPT" + }, "openRouter": { "providerRouting": { "title": "Routing dei fornitori OpenRouter", @@ -828,7 +835,8 @@ "providerNotAllowed": "Il fornitore '{{provider}}' non è consentito dalla tua organizzazione", "modelNotAllowed": "Il modello '{{model}}' non è consentito per il fornitore '{{provider}}' dalla tua organizzazione.", "profileInvalid": "Questo profilo contiene un fornitore o un modello non consentito dalla tua organizzazione.", - "qwenCodeOauthPath": "Devi fornire un percorso valido per le credenziali OAuth" + "qwenCodeOauthPath": "Devi fornire un percorso valido per le credenziali OAuth", + "openAiNativeCodexOauthPath": "Opzionale: Percorso all'auth.json di ChatGPT Codex. Quando vuoto, predefinito a ~/.codex/auth.json." }, "placeholders": { "apiKey": "Inserisci chiave API...", diff --git a/webview-ui/src/i18n/locales/ja/settings.json b/webview-ui/src/i18n/locales/ja/settings.json index bce95eeab2..f6428310df 100644 --- a/webview-ui/src/i18n/locales/ja/settings.json +++ b/webview-ui/src/i18n/locales/ja/settings.json @@ -399,6 +399,13 @@ "authenticatedMessage": "Roo Code Cloudアカウントを通じて安全に認証されています。", "connectButton": "Roo Code Cloudに接続" }, + "openAiNativeCodex": { + "oauthPathLabel": "OAuth認証情報パス", + "oauthPathDescription": "ChatGPT Codex auth.json認証情報へのパス。空の場合は{{defaultPath}}がデフォルト(Windows: C:\\\\Users\\\\USERNAME\\\\.codex\\\\auth.json)。", + "oauthCliDescription": "ChatGPT Codexは公式Codex CLIを介してChatGPTウェブ認証情報を使用します。auth.jsonが作成されるようにCodex CLIで認証してください。カスタムの場所を使用する場合は、ここに完全なファイルパスを設定してください。", + "oauthConnectDescription": "認証後、Rooはauth.jsonからアクセストークンを読み取り、ChatGPT Responses(Codex)に接続します。", + "learnMoreLinkText": "ChatGPTについて詳しく学ぶ" + }, "openRouter": { "providerRouting": { "title": "OpenRouterプロバイダールーティング", @@ -828,7 +835,8 @@ "providerNotAllowed": "プロバイダー「{{provider}}」は組織によって許可されていません", "modelNotAllowed": "モデル「{{model}}」はプロバイダー「{{provider}}」に対して組織によって許可されていません", "profileInvalid": "このプロファイルには、組織によって許可されていないプロバイダーまたはモデルが含まれています", - "qwenCodeOauthPath": "有効なOAuth認証情報のパスを提供する必要があります" + "qwenCodeOauthPath": "有効なOAuth認証情報のパスを提供する必要があります", + "openAiNativeCodexOauthPath": "オプション: ChatGPT Codex auth.jsonへのパス。空の場合、デフォルトは ~/.codex/auth.json です。" }, "placeholders": { "apiKey": "API キーを入力...", diff --git a/webview-ui/src/i18n/locales/ko/settings.json b/webview-ui/src/i18n/locales/ko/settings.json index f7aec2f4ce..7f1b15976a 100644 --- a/webview-ui/src/i18n/locales/ko/settings.json +++ b/webview-ui/src/i18n/locales/ko/settings.json @@ -399,6 +399,13 @@ "authenticatedMessage": "Roo Code Cloud 계정을 통해 안전하게 인증되었습니다.", "connectButton": "Roo Code Cloud에 연결" }, + "openAiNativeCodex": { + "oauthPathLabel": "OAuth 자격 증명 경로", + "oauthPathDescription": "ChatGPT Codex auth.json 자격 증명 경로입니다. 비어있으면 기본값 {{defaultPath}}를 사용합니다 (Windows: C:\\\\Users\\\\USERNAME\\\\.codex\\\\auth.json).", + "oauthCliDescription": "ChatGPT Codex는 공식 Codex CLI를 통해 ChatGPT 웹 자격 증명을 사용합니다. auth.json이 생성되도록 Codex CLI로 인증하세요. 사용자 정의 위치를 사용하는 경우 여기에 전체 파일 경로를 설정하세요.", + "oauthConnectDescription": "인증 후 Roo는 auth.json에서 액세스 토큰을 읽고 ChatGPT Responses (Codex)에 연결합니다.", + "learnMoreLinkText": "ChatGPT에 대해 자세히 알아보기" + }, "openRouter": { "providerRouting": { "title": "OpenRouter 제공자 라우팅", @@ -828,7 +835,8 @@ "providerNotAllowed": "제공자 '{{provider}}'는 조직에서 허용되지 않습니다", "modelNotAllowed": "모델 '{{model}}'은 제공자 '{{provider}}'에 대해 조직에서 허용되지 않습니다", "profileInvalid": "이 프로필에는 조직에서 허용되지 않는 제공자 또는 모델이 포함되어 있습니다", - "qwenCodeOauthPath": "유효한 OAuth 자격 증명 경로를 제공해야 합니다" + "qwenCodeOauthPath": "유효한 OAuth 자격 증명 경로를 제공해야 합니다", + "openAiNativeCodexOauthPath": "선택사항: ChatGPT Codex auth.json 경로. 비어있을 때 기본값은 ~/.codex/auth.json입니다." }, "placeholders": { "apiKey": "API 키 입력...", diff --git a/webview-ui/src/i18n/locales/nl/settings.json b/webview-ui/src/i18n/locales/nl/settings.json index d5b246e22a..5f419a6580 100644 --- a/webview-ui/src/i18n/locales/nl/settings.json +++ b/webview-ui/src/i18n/locales/nl/settings.json @@ -399,6 +399,13 @@ "authenticatedMessage": "Veilig geauthenticeerd via je Roo Code Cloud-account.", "connectButton": "Verbinden met Roo Code Cloud" }, + "openAiNativeCodex": { + "oauthPathLabel": "OAuth-referentiepad", + "oauthPathDescription": "Pad naar je ChatGPT Codex auth.json-referenties. Standaard {{defaultPath}} als leeg gelaten (Windows: C:\\\\Users\\\\USERNAME\\\\.codex\\\\auth.json).", + "oauthCliDescription": "ChatGPT Codex gebruikt je ChatGPT-webreferenties via de officiële Codex CLI. Authenticeer met de Codex CLI zodat auth.json wordt aangemaakt. Als je een aangepaste locatie gebruikt, stel hier het volledige bestandspad in.", + "oauthConnectDescription": "Na authenticatie zal Roo het toegangstoken uit auth.json lezen en verbinden met ChatGPT Responses (Codex).", + "learnMoreLinkText": "Meer leren over ChatGPT" + }, "openRouter": { "providerRouting": { "title": "OpenRouter-providerroutering", @@ -828,7 +835,8 @@ "providerNotAllowed": "Provider '{{provider}}' is niet toegestaan door je organisatie", "modelNotAllowed": "Model '{{model}}' is niet toegestaan voor provider '{{provider}}' door je organisatie", "profileInvalid": "Dit profiel bevat een provider of model dat niet is toegestaan door je organisatie", - "qwenCodeOauthPath": "Je moet een geldig OAuth-referentiepad opgeven" + "qwenCodeOauthPath": "Je moet een geldig OAuth-referentiepad opgeven", + "openAiNativeCodexOauthPath": "Optioneel: Pad naar ChatGPT Codex auth.json. Wanneer leeg, standaard ~/.codex/auth.json." }, "placeholders": { "apiKey": "Voer API-sleutel in...", diff --git a/webview-ui/src/i18n/locales/pl/settings.json b/webview-ui/src/i18n/locales/pl/settings.json index 385a38fe2c..6a61aef42f 100644 --- a/webview-ui/src/i18n/locales/pl/settings.json +++ b/webview-ui/src/i18n/locales/pl/settings.json @@ -399,6 +399,13 @@ "authenticatedMessage": "Bezpiecznie uwierzytelniony przez twoje konto Roo Code Cloud.", "connectButton": "Połącz z Roo Code Cloud" }, + "openAiNativeCodex": { + "oauthPathLabel": "Ścieżka poświadczeń OAuth", + "oauthPathDescription": "Ścieżka do twoich poświadczeń auth.json ChatGPT Codex. Domyślnie {{defaultPath}} jeśli pozostawione puste (Windows: C:\\\\Users\\\\USERNAME\\\\.codex\\\\auth.json).", + "oauthCliDescription": "ChatGPT Codex używa twoich poświadczeń internetowych ChatGPT przez oficjalne CLI Codex. Uwierzytelnij się za pomocą CLI Codex, aby utworzono auth.json. Jeśli używasz niestandardowej lokalizacji, ustaw tutaj pełną ścieżkę pliku.", + "oauthConnectDescription": "Po uwierzytelnieniu Roo odczyta token dostępu z auth.json i połączy się z ChatGPT Responses (Codex).", + "learnMoreLinkText": "Dowiedz się więcej o ChatGPT" + }, "openRouter": { "providerRouting": { "title": "Routing dostawców OpenRouter", @@ -828,7 +835,8 @@ "providerNotAllowed": "Dostawca '{{provider}}' nie jest dozwolony przez Twoją organizację", "modelNotAllowed": "Model '{{model}}' nie jest dozwolony dla dostawcy '{{provider}}' przez Twoją organizację", "profileInvalid": "Ten profil zawiera dostawcę lub model, który nie jest dozwolony przez Twoją organizację", - "qwenCodeOauthPath": "Musisz podać prawidłową ścieżkę do poświadczeń OAuth" + "qwenCodeOauthPath": "Musisz podać prawidłową ścieżkę do poświadczeń OAuth", + "openAiNativeCodexOauthPath": "Opcjonalne: Ścieżka do auth.json ChatGPT Codex. Gdy puste, domyślnie ~/.codex/auth.json." }, "placeholders": { "apiKey": "Wprowadź klucz API...", diff --git a/webview-ui/src/i18n/locales/pt-BR/settings.json b/webview-ui/src/i18n/locales/pt-BR/settings.json index be2ff89ff7..b9dc2ef019 100644 --- a/webview-ui/src/i18n/locales/pt-BR/settings.json +++ b/webview-ui/src/i18n/locales/pt-BR/settings.json @@ -399,6 +399,13 @@ "authenticatedMessage": "Autenticado com segurança através da sua conta Roo Code Cloud.", "connectButton": "Conectar ao Roo Code Cloud" }, + "openAiNativeCodex": { + "oauthPathLabel": "Caminho das credenciais OAuth", + "oauthPathDescription": "Caminho para suas credenciais auth.json do ChatGPT Codex. Padrão {{defaultPath}} se deixado vazio (Windows: C:\\\\Users\\\\USERNAME\\\\.codex\\\\auth.json).", + "oauthCliDescription": "ChatGPT Codex usa suas credenciais web do ChatGPT através da CLI oficial do Codex. Autentique com a CLI do Codex para que auth.json seja criado. Se você usar um local personalizado, defina o caminho completo do arquivo aqui.", + "oauthConnectDescription": "Após a autenticação, Roo lerá o token de acesso do auth.json e se conectará ao ChatGPT Responses (Codex).", + "learnMoreLinkText": "Saiba mais sobre ChatGPT" + }, "openRouter": { "providerRouting": { "title": "Roteamento de Provedores OpenRouter", @@ -828,7 +835,8 @@ "providerNotAllowed": "O provedor '{{provider}}' não é permitido pela sua organização", "modelNotAllowed": "O modelo '{{model}}' não é permitido para o provedor '{{provider}}' pela sua organização", "profileInvalid": "Este perfil contém um provedor ou modelo que não é permitido pela sua organização", - "qwenCodeOauthPath": "Você deve fornecer um caminho válido de credenciais OAuth" + "qwenCodeOauthPath": "Você deve fornecer um caminho válido de credenciais OAuth", + "openAiNativeCodexOauthPath": "Opcional: Caminho para o auth.json do ChatGPT Codex. Quando vazio, padrão é ~/.codex/auth.json." }, "placeholders": { "apiKey": "Digite a chave API...", diff --git a/webview-ui/src/i18n/locales/ru/settings.json b/webview-ui/src/i18n/locales/ru/settings.json index b429f01f4e..4e7c4d89fa 100644 --- a/webview-ui/src/i18n/locales/ru/settings.json +++ b/webview-ui/src/i18n/locales/ru/settings.json @@ -399,6 +399,13 @@ "authenticatedMessage": "Безопасно аутентифицирован через твой аккаунт Roo Code Cloud.", "connectButton": "Подключиться к Roo Code Cloud" }, + "openAiNativeCodex": { + "oauthPathLabel": "Путь к учетным данным OAuth", + "oauthPathDescription": "Путь к вашим учетным данным auth.json ChatGPT Codex. По умолчанию {{defaultPath}}, если оставлено пустым (Windows: C:\\\\Users\\\\USERNAME\\\\.codex\\\\auth.json).", + "oauthCliDescription": "ChatGPT Codex использует ваши веб-учетные данные ChatGPT через официальный CLI Codex. Аутентифицируйтесь с помощью CLI Codex, чтобы создать auth.json. Если вы используете пользовательское расположение, установите здесь полный путь к файлу.", + "oauthConnectDescription": "После аутентификации Roo прочитает токен доступа из auth.json и подключится к ChatGPT Responses (Codex).", + "learnMoreLinkText": "Узнать больше о ChatGPT" + }, "openRouter": { "providerRouting": { "title": "Маршрутизация провайдера OpenRouter", @@ -828,7 +835,8 @@ "providerNotAllowed": "Провайдер '{{provider}}' не разрешен вашей организацией", "modelNotAllowed": "Модель '{{model}}' не разрешена для провайдера '{{provider}}' вашей организацией", "profileInvalid": "Этот профиль содержит провайдера или модель, которые не разрешены вашей организацией", - "qwenCodeOauthPath": "Вы должны указать допустимый путь к учетным данным OAuth" + "qwenCodeOauthPath": "Вы должны указать допустимый путь к учетным данным OAuth", + "openAiNativeCodexOauthPath": "Необязательно: Путь к auth.json ChatGPT Codex. Когда пусто, по умолчанию ~/.codex/auth.json." }, "placeholders": { "apiKey": "Введите API-ключ...", diff --git a/webview-ui/src/i18n/locales/tr/settings.json b/webview-ui/src/i18n/locales/tr/settings.json index 429599d7ea..a6bfc5ae65 100644 --- a/webview-ui/src/i18n/locales/tr/settings.json +++ b/webview-ui/src/i18n/locales/tr/settings.json @@ -399,6 +399,13 @@ "authenticatedMessage": "Roo Code Cloud hesabın üzerinden güvenli bir şekilde kimlik doğrulandı.", "connectButton": "Roo Code Cloud'a Bağlan" }, + "openAiNativeCodex": { + "oauthPathLabel": "OAuth kimlik bilgileri yolu", + "oauthPathDescription": "ChatGPT Codex auth.json kimlik bilgilerinizin yolu. Boş bırakılırsa varsayılan {{defaultPath}} (Windows: C:\\\\Users\\\\USERNAME\\\\.codex\\\\auth.json).", + "oauthCliDescription": "ChatGPT Codex, resmi Codex CLI aracılığıyla ChatGPT web kimlik bilgilerinizi kullanır. auth.json oluşturulması için Codex CLI ile kimlik doğrulaması yapın. Özel bir konum kullanıyorsanız, burada tam dosya yolunu ayarlayın.", + "oauthConnectDescription": "Kimlik doğrulamasından sonra Roo, auth.json'dan erişim belirtecini okuyacak ve ChatGPT Responses (Codex) ile bağlantı kuracak.", + "learnMoreLinkText": "ChatGPT hakkında daha fazla bilgi edinin" + }, "openRouter": { "providerRouting": { "title": "OpenRouter Sağlayıcı Yönlendirmesi", @@ -828,7 +835,8 @@ "providerNotAllowed": "Sağlayıcı '{{provider}}' kuruluşunuz tarafından izin verilmiyor", "modelNotAllowed": "Model '{{model}}' sağlayıcı '{{provider}}' için kuruluşunuz tarafından izin verilmiyor", "profileInvalid": "Bu profil, kuruluşunuz tarafından izin verilmeyen bir sağlayıcı veya model içeriyor", - "qwenCodeOauthPath": "Geçerli bir OAuth kimlik bilgileri yolu sağlamalısın" + "qwenCodeOauthPath": "Geçerli bir OAuth kimlik bilgileri yolu sağlamalısın", + "openAiNativeCodexOauthPath": "İsteğe bağlı: ChatGPT Codex auth.json yolu. Boş olduğunda, varsayılan ~/.codex/auth.json'dur." }, "placeholders": { "apiKey": "API anahtarını girin...", diff --git a/webview-ui/src/i18n/locales/vi/settings.json b/webview-ui/src/i18n/locales/vi/settings.json index 35fd639ba6..5282d45bdf 100644 --- a/webview-ui/src/i18n/locales/vi/settings.json +++ b/webview-ui/src/i18n/locales/vi/settings.json @@ -399,6 +399,13 @@ "authenticatedMessage": "Đã xác thực an toàn thông qua tài khoản Roo Code Cloud của bạn.", "connectButton": "Kết nối với Roo Code Cloud" }, + "openAiNativeCodex": { + "oauthPathLabel": "Đường dẫn thông tin xác thực OAuth", + "oauthPathDescription": "Đường dẫn đến thông tin xác thực auth.json ChatGPT Codex của bạn. Mặc định {{defaultPath}} nếu để trống (Windows: C:\\\\Users\\\\USERNAME\\\\.codex\\\\auth.json).", + "oauthCliDescription": "ChatGPT Codex sử dụng thông tin xác thực web ChatGPT của bạn thông qua CLI Codex chính thức. Xác thực với CLI Codex để tạo auth.json. Nếu bạn sử dụng vị trí tùy chỉnh, hãy đặt đường dẫn tệp đầy đủ ở đây.", + "oauthConnectDescription": "Sau khi xác thực, Roo sẽ đọc token truy cập từ auth.json và kết nối với ChatGPT Responses (Codex).", + "learnMoreLinkText": "Tìm hiểu thêm về ChatGPT" + }, "openRouter": { "providerRouting": { "title": "Định tuyến nhà cung cấp OpenRouter", @@ -828,7 +835,8 @@ "providerNotAllowed": "Nhà cung cấp '{{provider}}' không được phép bởi tổ chức của bạn", "modelNotAllowed": "Mô hình '{{model}}' không được phép cho nhà cung cấp '{{provider}}' bởi tổ chức của bạn", "profileInvalid": "Hồ sơ này chứa một nhà cung cấp hoặc mô hình không được phép bởi tổ chức của bạn", - "qwenCodeOauthPath": "Bạn phải cung cấp đường dẫn thông tin xác thực OAuth hợp lệ" + "qwenCodeOauthPath": "Bạn phải cung cấp đường dẫn thông tin xác thực OAuth hợp lệ", + "openAiNativeCodexOauthPath": "Tùy chọn: Đường dẫn đến auth.json của ChatGPT Codex. Khi trống, mặc định là ~/.codex/auth.json." }, "placeholders": { "apiKey": "Nhập khóa API...", diff --git a/webview-ui/src/i18n/locales/zh-CN/settings.json b/webview-ui/src/i18n/locales/zh-CN/settings.json index abb3e44637..befdac0fcc 100644 --- a/webview-ui/src/i18n/locales/zh-CN/settings.json +++ b/webview-ui/src/i18n/locales/zh-CN/settings.json @@ -399,6 +399,13 @@ "authenticatedMessage": "已通过 Roo Code Cloud 账户安全认证。", "connectButton": "连接到 Roo Code Cloud" }, + "openAiNativeCodex": { + "oauthPathLabel": "OAuth 凭据路径", + "oauthPathDescription": "ChatGPT Codex auth.json 凭据的路径。如果留空则默认为 {{defaultPath}}(Windows: C:\\\\Users\\\\USERNAME\\\\.codex\\\\auth.json)。", + "oauthCliDescription": "ChatGPT Codex 通过官方 Codex CLI 使用你的 ChatGPT 网页凭据。使用 Codex CLI 进行认证以创建 auth.json。如果使用自定义位置,请在此设置完整文件路径。", + "oauthConnectDescription": "认证后,Roo 将从 auth.json 读取访问 Token 并连接到 ChatGPT Responses(Codex)。", + "learnMoreLinkText": "了解更多关于 ChatGPT" + }, "openRouter": { "providerRouting": { "title": "OpenRouter 提供商路由", @@ -828,7 +835,8 @@ "providerNotAllowed": "提供商 '{{provider}}' 不允许用于您的组织", "modelNotAllowed": "模型 '{{model}}' 不允许用于提供商 '{{provider}}',您的组织不允许", "profileInvalid": "此配置文件包含您的组织不允许的提供商或模型", - "qwenCodeOauthPath": "您必须提供有效的 OAuth 凭证路径" + "qwenCodeOauthPath": "您必须提供有效的 OAuth 凭证路径", + "openAiNativeCodexOauthPath": "可选:ChatGPT Codex auth.json 路径。为空时默认为 ~/.codex/auth.json。" }, "placeholders": { "apiKey": "请输入 API 密钥...", diff --git a/webview-ui/src/i18n/locales/zh-TW/settings.json b/webview-ui/src/i18n/locales/zh-TW/settings.json index 91f7c5677a..c03a243cb8 100644 --- a/webview-ui/src/i18n/locales/zh-TW/settings.json +++ b/webview-ui/src/i18n/locales/zh-TW/settings.json @@ -399,6 +399,13 @@ "authenticatedMessage": "已透過 Roo Code Cloud 帳戶安全認證。", "connectButton": "連接到 Roo Code Cloud" }, + "openAiNativeCodex": { + "oauthPathLabel": "OAuth 憑證路徑", + "oauthPathDescription": "您的 ChatGPT Codex auth.json 憑證路徑。如果留空則預設為 {{defaultPath}}(Windows: C:\\\\Users\\\\USERNAME\\\\.codex\\\\auth.json)。", + "oauthCliDescription": "ChatGPT Codex 透過官方 Codex CLI 使用您的 ChatGPT 網頁憑證。使用 Codex CLI 進行認證以建立 auth.json。如果您使用自訂位置,請在此設定完整檔案路徑。", + "oauthConnectDescription": "認證後,Roo 將從 auth.json 讀取存取權杖並連接到 ChatGPT Responses(Codex)。", + "learnMoreLinkText": "深入了解 ChatGPT" + }, "openRouter": { "providerRouting": { "title": "OpenRouter 供應商路由", @@ -828,7 +835,8 @@ "providerNotAllowed": "供應商 '{{provider}}' 不允許用於您的組織。", "modelNotAllowed": "模型 '{{model}}' 不允許用於供應商 '{{provider}}',您的組織不允許", "profileInvalid": "此設定檔包含您的組織不允許的供應商或模型", - "qwenCodeOauthPath": "您必須提供有效的 OAuth 憑證路徑" + "qwenCodeOauthPath": "您必須提供有效的 OAuth 憑證路徑", + "openAiNativeCodexOauthPath": "可選:ChatGPT Codex auth.json 路徑。當空白時,預設為 ~/.codex/auth.json。" }, "placeholders": { "apiKey": "請輸入 API 金鑰...",