Initial commit

This commit is contained in:
2026-05-24 22:53:05 +09:00
commit c7ffc45bc6
8 changed files with 1060 additions and 0 deletions
+170
View File
@@ -0,0 +1,170 @@
# codexClient.cjs 说明
## 文件作用
这个文件是后端与本机 Codex CLI / `@openai/codex-sdk` 的适配层。它负责检查登录状态、启动登录、退出登录、构造 Codex 请求线程、执行普通回复和流式回复,并把这些能力导出给 Express 路由使用。
## 主要常量和状态
- `PROJECT_ROOT`:项目根目录。
- `CODEX_WORKSPACE`:专门给 Codex SDK 使用的工作目录 `.codex-chat-workspace`
- `DEFAULT_MODEL`:来自环境变量 `CODEX_MODEL` 的默认模型。
- `DEFAULT_REASONING_EFFORT`:来自环境变量 `CODEX_REASONING_EFFORT` 的默认推理强度。
- `AUTH_STATUS_CACHE_MS`:登录状态缓存时间。
- `sdkPromise`:缓存动态导入的 Codex SDK。
- `authStatusCache`:缓存最近一次登录状态。
- `loginState`:保存当前或最近一次登录命令的运行状态和日志。
文件加载时会创建 `CODEX_WORKSPACE` 目录。
## 主要函数
### `getCodexBin()`
查找 Codex CLI 可执行文件。优先使用项目内 `node_modules/.bin/codex`,找不到时回退到全局 `codex` 命令。
### `getCodexHomeHint()`
返回 Codex 本地配置目录提示。优先使用 `CODEX_HOME` 环境变量,否则使用用户目录下的 `.codex`
### `appendLoginLine(chunk)`
把登录命令输出追加到 `loginState.lines`。它会跳过空行,并且只保留最近 120 行,避免日志无限增长。
### `runCodexCommand(args, options)`
执行 Codex CLI 命令的通用封装:
- 使用 `spawn` 启动命令。
-`CODEX_WORKSPACE` 下运行。
- 收集 stdout 和 stderr。
- 支持传入 stdin。
- 支持超时,超时后终止子进程。
- 最终返回退出码、信号、输出和错误对象。
它主要用于登录状态检查和退出登录。
### `loadCodexSdk()`
动态导入 `@openai/codex-sdk`,并用 `sdkPromise` 缓存导入结果,避免重复加载。
### `normalizeInput(input)`
清洗前端传入的消息数组:
- 只保留对象类型且有字符串 `role` 的项。
-`content` 转为字符串。
- 去掉空内容消息。
### `roleTitle(role)`
把请求角色转换成写入提示词的标题:
- `developer``system` 显示为开发者指令。
- `assistant` 显示为 assistant。
- 其他角色显示为 user。
### `buildCodexPrompt(input)`
把结构化消息数组转换成单个 Codex prompt
- 先标准化输入。
- 将每条消息转换成 `### 角色标题` 加正文的文本块。
- 在开头加入本地网页聊天工具的约束说明。
- 要求模型只回复最后一条 user 消息,不混入其他会话上下文。
### `normalizeModel(model)`
合并请求体模型名和环境变量默认模型,并返回修剪后的字符串。
### `normalizeReasoningEffort(value)`
校验推理强度,只允许 `minimal``low``medium``high``xhigh`。非法值会回退到 `medium`
### `createThreadOptions(body)`
创建 Codex SDK thread 运行选项:
- 使用只读沙箱。
- 禁用审批。
- 固定工作目录为 `CODEX_WORKSPACE`
- 跳过 Git 仓库检查。
- 禁用网络和 Web 搜索。
- 透传推理强度和可选模型。
这些设置降低本地聊天代理对用户文件和网络的影响范围。
### `createCodexClient()`
创建 Codex SDK 客户端,并关闭原始 agent reasoning 输出,让前端只展示面向用户的最终回答。
### `hasUsableAuth(status)`
判断 Codex 是否可用:既要安装 CLI,也要处于已登录状态。
### `getAuthStatus(options)`
检查 Codex 登录状态:
- 默认使用短期缓存,`force` 为真时强制刷新。
- 执行 `codex login status`
- 根据退出码判断是否已登录。
- 返回安装状态、登录状态、认证模式输出、提示消息、Codex home 和检查时间。
### `ensureLoggedIn()`
在执行聊天请求前校验 Codex 可用性。CLI 未安装时抛出 503 错误;未登录时抛出 401 错误。
### `startLogin(options)`
启动 Codex 登录流程:
- 如果已有登录进程在跑,直接返回当前登录状态。
- 默认启动 `codex login`
- `deviceAuth` 为真时追加 `--device-auth`
- 保存进程 pid、开始时间、结束时间、退出码、信号和输出日志。
- 登录进程结束后清空认证状态缓存。
### `getLoginState()`
返回当前登录状态快照,供前端轮询展示。
### `logoutCodex()`
执行 `codex logout`,清空认证状态缓存,并返回命令结果。
### `runCodexOnce(body, signal)`
执行一次性聊天请求:
- 先确认 Codex 已登录。
-`buildCodexPrompt` 生成 prompt。
- prompt 为空时抛出 400 错误。
- 创建 Codex client 和 thread。
- 调用 `thread.run(prompt, { signal })`
- 返回最终文本、thread id 和 usage。
### `runCodexStream(body, signal, handlers)`
执行流式聊天请求:
- 校验登录和 prompt。
- 调用 `thread.runStreamed(prompt, { signal })`
- 遍历 SDK 返回的事件流。
- 对 agent message 计算增量文本,并调用 `handlers.onDelta(delta)`
- 记录 `turn.completed` 的 usage。
- 遇到 SDK 错误事件时抛出后端错误。
- 返回完整文本、thread id 和 usage。
## 导出接口
该文件导出:
- `getAuthStatus`
- `getLoginState`
- `logoutCodex`
- `runCodexOnce`
- `runCodexStream`
- `startLogin`
这些函数由 `server/index.cjs` 的 API 路由调用。