diff --git a/src/components/microservices/code-queue/src/code-agent/codex.ts b/src/components/microservices/code-queue/src/code-agent/codex.ts index cfd9bb9b..114b4000 100644 --- a/src/components/microservices/code-queue/src/code-agent/codex.ts +++ b/src/components/microservices/code-queue/src/code-agent/codex.ts @@ -1,13 +1,14 @@ // 重构前 index.ts 只读参考:commit 6a04144d3f5103014f75b637d7e6bc2f45bf007f,blob 56e590c1a6b5ca7ad128bf2c992f60e46c355a58;可用 `git show 6a04144d3f5103014f75b637d7e6bc2f45bf007f:src/components/microservices/code-queue/src/index.ts` 查看。 import { spawn, type ChildProcessWithoutNullStreams } from "node:child_process"; +import { existsSync, readFileSync } from "node:fs"; import * as readline from "node:readline"; import type { AppServerExit, CodexEventSummary, CodexRunResult, JsonValue, QueueTask, RuntimeConfig, SessionCommandOutput, TerminalStatus } from "../types"; import type { ActiveRun, CodeAgentClient } from "./common"; import { extractRecord, extractString, terminalStatus, textInput } from "./common"; export interface CodexPortContext { - config: Pick; + config: Pick; activeRuns: Map; appendOutput: (task: QueueTask, channel: "system" | "assistant" | "reasoning" | "command" | "diff" | "tool" | "error", text: string, method?: string, itemId?: string, append?: boolean) => unknown; addEvent: (task: QueueTask, event: CodexEventSummary) => void; @@ -49,6 +50,62 @@ function appServerCwdForTask(task: QueueTask): string { return task.executionMode === "windows-native" ? windowsPathFromWslMount(task.cwd) : task.cwd; } +const codexProxyEnvKeys = ["HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY", "http_proxy", "https_proxy", "all_proxy"]; +const defaultCodexDirectHosts = ["hyueapi.com", ".hyueapi.com"]; + +function splitEnvList(value: string | undefined, fallback: string[]): string[] { + const raw = value === undefined || value.trim().length === 0 ? fallback : value.split(","); + return Array.from(new Set(raw.map((item) => item.trim().toLowerCase()).filter(Boolean))); +} + +function directHostNeedle(host: string): string { + return host.replace(/^\./u, "").toLowerCase(); +} + +function readTextIfPresent(path: string): string { + try { + return existsSync(path) ? readFileSync(path, "utf8") : ""; + } catch { + return ""; + } +} + +function codexNetworkConfigText(): string { + return [ + "OPENAI_BASE_URL", + "OPENAI_API_BASE", + "OPENAI_RESPONSES_URL", + "CODEX_OPENAI_BASE_URL", + "CODEX_BASE_URL", + ].map((key) => process.env[key] ?? "").concat([ + readTextIfPresent(`${ctx().config.codexHome.replace(/\/+$/u, "")}/config.toml`), + readTextIfPresent(ctx().config.sourceCodexConfig), + ]).join("\n").toLowerCase(); +} + +function shouldRunCodexDirect(): boolean { + const configText = codexNetworkConfigText(); + if (configText.length === 0) return false; + return splitEnvList(process.env.CODE_QUEUE_CODEX_DIRECT_HOSTS, defaultCodexDirectHosts) + .some((host) => configText.includes(directHostNeedle(host))); +} + +function codexAppServerEnv(task: QueueTask): NodeJS.ProcessEnv { + const env: NodeJS.ProcessEnv = { + ...process.env, + CODEX_HOME: ctx().config.codexHome, + CODEX_INTERNAL_ORIGINATOR_OVERRIDE: "unidesk_code_queue", + }; + if (!shouldRunCodexDirect()) return env; + for (const key of codexProxyEnvKeys) delete env[key]; + const directHosts = splitEnvList(process.env.CODE_QUEUE_CODEX_DIRECT_HOSTS, defaultCodexDirectHosts).join(","); + env.NO_PROXY = [env.NO_PROXY, directHosts].filter((part) => part !== undefined && part.length > 0).join(","); + env.no_proxy = [env.no_proxy, directHosts].filter((part) => part !== undefined && part.length > 0).join(","); + ctx().appendOutput(task, "system", `codex app-server direct network enabled for ${directHosts}\n`, "codex/network"); + ctx().logger("info", "codex_app_server_direct_network", { taskId: task.id, directHosts }); + return env; +} + class AppServerClient { private child: ChildProcessWithoutNullStreams; private nextId = 1; @@ -67,7 +124,7 @@ class AppServerClient { this.child = ctx().providerIsMain(task.providerId) ? spawn("codex", ["app-server", "--listen", "stdio://"], { cwd: task.cwd, - env: { ...process.env, CODEX_HOME: ctx().config.codexHome, CODEX_INTERNAL_ORIGINATOR_OVERRIDE: "unidesk_code_queue" }, + env: codexAppServerEnv(task), stdio: "pipe", }) : spawn("bun", ["scripts/cli.ts", "ssh", task.providerId, remoteCommand], {