← 返回列表
需源码安装
一个用于 DeepSeek Harness 的本地 Codex 路由:它注册一个 LLM 提供方
暂不能直接安装(需源码编译或环境不满足):仓库 package.json 标记 private,未发布到 npm,需从源码安装。 · 最近上游提交 2026/9/22 · 已提供中文文档
DeepSeek Harness 的 Codex 路由:优先使用本地 Codex CLI,回退到 OpenAI 兼容 API
综合分
30.6
GitHub 分
30.6
用户评分
—
★ Stars
1
周下载量
—
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add zhangzhangco/dsh-llm-codex仓库 package.json 标记 private,未发布到 npm,需从源码安装,改用 GitHub 源安装
信任档位:已验证本站已于 2 天前真实安装成功
- 是什么
- dsh 原生插件 · tool
- 装得上吗
- 本站已真实安装成功(非静态推断)
- 安全吗
- 本站尚未对该插件做风险分级(暂未覆盖,不等同于无风险)
- 还在维护吗
- 活跃:最近一次提交在 3 天前
档位由下列信号合成:本站实装验证(真实安装,当前最高到 L4)· 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。下方各区块是它的证据明细。 验证判据与等级说明 →
🟢实装验证通过· 2026/9/24
由本站实装验证器在真实 dsh 环境安装成功,非静态推断。
数据截至 2026/9/23(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
安装兼容性检查需源码安装
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✓npm 包dsh-llm-codex @ 0.1.2
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明
仓库 package.json 标记 private,未发布到 npm,需从源码安装
验证方式:npm registry 存在性 + package.json 静态校验 · 最后验证 2026/9/23 19:05:01
依赖的 DSH / Cordis 模块
@deepseek-ai/schemastery@deepseek-ai/dsh-credentials@deepseek-ai/cordis@deepseek-ai/dsh-llm用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动
README
由 DeepSeek 最新模型翻译生成dsh-llm-codex
License: MIT
一个用于 DeepSeek Harness 的本地 Codex 路由:它注册一个 LLM 提供方
(默认名为 codex-local),其请求会发往本机上安装的 Codex CLI,
并可选择性地回退到一个兼容 OpenAI 的端点。
本插件不属于已发布的 @deepseek-ai/ 发行版。它位于
web profile 中,并通过该 profile 的 patch 层挂载,因此
DSH 安装本身不受影响。
快速开始——一条命令,无需编辑 patch 文件:
dsh plugin --profile web add git+ssh://git@github.com/zhangzhangco/dsh-llm-codex.git
该包声明了 dsh.bundle.patch,因此 dsh plugin 会将其追加到
profile 的 dsh.profile.bundles,其 cordis.patch.yml 会自行挂载
llm-codex 行。重启 profile 后,该路由就会出现在
模型选择器中。其他安装形式(tarball、链接文件夹)见
与另一台机器共享。
本包有意不发布到 npm,并保持
private: true。npm 上的名称 dsh-llm-codex 属于另一位作者的
无关实现;该字段是为了防止覆盖发布。
GitHub 是分发渠道——见
为什么用 GitHub 而不是 npm。
它是什么(以及不是什么)
codex exec 是一个完整的 agent,拥有自己的工具、沙箱、审批和
登录。因此,本适配器将 Codex 暴露为一条文本生成路由:
- 它转发对话(系统提示、历史记录、工具调用和工具
结果均渲染为文本),并返回模型的回答。
- DSH 工具调用不会由 Codex 执行,Codex 的内部工具使用也
不会作为 DSH 工具调用回报。在此路由上的 DSH 会话保留其
自己的工具,但 Codex 一侧仅根据所给文本作答。
- Codex 自己的沙箱决定它可以读取或运行什么;适配器传递
-s -C ,且 sandbox: read-only 是默认值。
如果你希望由 Codex 驱动 DSH 工具,或希望将 Codex 的
工具暴露为 DSH 工具,请改选 MCP 路径。
认证
该路由使用本机上 Codex CLI 的现有登录
($CODEX_HOME/auth.json,ChatGPT OAuth)。无需 API key,也不会从
~/.codex 复制任何内容。
模型目录
该提供方会公布来自 Codex 自身缓存
$CODEX_HOME/models_cache.json 的模型,包括其真实的上下文窗口、推理
级别和输入模态。Codex 刷新该缓存后,新模型就会出现;
无需更改插件。models 可以列出额外的 id,未列出的 id 仍会
作为未知模型透传。
配置
从 ~/.dsh/profiles/web/cordis.patch.yml 挂载:
- insert:
- id: llm-codex
name: dsh-llm-codex
config:
provider: codex-local
Codex's own sandbox (not the harness permission mode). See
选择值之前,请先阅读下文中的“沙箱与文件写入”。
sandbox: read-only
ephemeral: true
transport: auto
reasoningEffort: ''
fallback:
baseURL: ''
apiKeyEnv: CODEX_FALLBACK_API_KEY
| 字段 | 默认值 | 含义 |
|---|---|---|
| provider | codex-local | 向模型选择器显示的路由名称 |
| command | 自动发现 | 要运行的 Codex CLI;留空则自动发现($CODEX_COMMAND、PATH、已知安装位置) |
| args | [] | 在提示词之前传递给 codex exec 的额外 argv |
| model | 空 | 固定使用一个模型;留空则使用目录,然后使用 $CODEX_HOME/config.toml |
| reasoningEffort | 空 | 默认推理强度;会话中的选择优先 |
| sandbox | read-only | read-only、workspace-write 或 danger-full-access |
| cwd | 空 | Codex 工作根目录;留空则使用会话工作区 |
| ephemeral | true | 运行时不将 Codex 线程持久化到 $CODEX_HOME 下 |
| timeoutMs | 600000 | 单次 codex exec 的挂钟时间预算 |
| codexHome | 空 | 子进程的 $CODEX_HOME;留空则继承环境变量 |
| modelsCachePath | $CODEX_HOME/models_cache.json | 目录缓存 |
| models | [] | 缓存缺失时要额外公布的 id |
| defaultContextWindow | 272000 | 未知 id 的容量回退值 |
| transport | auto | auto(先 CLI,再回退)、仅 cli 或仅 api |
| fallback.baseURL | 空 | OpenAI 兼容的基础 URL;留空则禁用回退 |
| fallback.apiKeyEnv | CODEX_FALLBACK_API_KEY | 保存回退密钥的变量 |
| fallback.model | 空 | 回退使用的模型 id;留空则复用请求 id |
| fallback.headers | {} | 额外的请求头 |
| fallback.timeoutMs | 300000 | 回退请求预算 |
沙箱与文件写入
sandbox 为 CLI 路由选择 Codex 自身的沙箱。它与此 harness 的权限模式是
不同的边界,后者会独立地对 DSH 自身的工具进行门控;更改其中一个不会改变另一个。
| 值 | 对 Codex 工具的影响 |
|---|---|
| read-only | 读取并回答;所有文件写入都被拒绝 |
| workspace-write | 在会话工作区内写入;其他目标仍被拒绝 |
| danger-full-access | 完全不使用 Codex 沙箱 |
这两种沙箱模式需要 macOS Seatbelt,并通过 sandbox-exec 应用。如果宿主机
本身已运行在沙箱内,则无法应用嵌套配置文件——调用会失败并报
sandbox_apply: Operation not permitted——随后所有沙箱模式都会拒绝写入,
无论允许哪些根目录:
当沙箱模式无法工作时,会打印 "sandbox_apply: Operation not permitted"。
sandbox-exec -p '(version 1)(allow default)' /bin/echo ok
在此类宿主机上,只有 danger-full-access 能让 Codex 写入,而这意味着 Codex
运行时没有自己的文件系统边界。插件在加载时会检查此能力:当在无法创建沙箱的
宿主机上配置了沙箱模式时,
启动时会记录一条警告并指明修复方法,而运行期间的沙箱拒绝会在失败信息中附加同样的建议。以普通助手文本形式出现的拒绝(“文件系统为只读”)很少带有可机器检查的信号,因此驱动该建议的是能力探测,而不是那段文本。
启用回退
设置一个基础 URL,并将密钥放入指定的环境变量中。Models 设置页面和凭据存储可以提供该变量;该值按请求解析。
fallback:
baseURL: https://api.openai.com/v1
apiKeyEnv: OPENAI_API_KEY
当该服务已挂载时,密钥会通过 harness 凭据接缝按请求解析——因此写在 Models 页面上的值会应用于下一个请求,无需重启——否则回退到进程环境。当没有解析出任何值时,该端点会在不带 Authorization 头的情况下使用,这正是无密钥服务器(例如本地 llama.cpp)所期望的。
本地 llama.cpp 服务器可直接使用。它会流式传输 reasoning_content,该内容映射到 harness 推理块,并忽略所请求的模型 id 和任何 Authorization 头:
transport: api
fallback:
baseURL: http://gpudev:8088/v1
apiKeyEnv: CODEX_FALLBACK_API_KEY
请注意,该提供方仍会通告 Codex 模型目录,因此诸如 gpt-6-astra 之类的模型 id 可能会被发送到提供不同模型的端点。使用 fallback.model 固定回退端点所期望的 id,或将 modelsCachePath/models 指向与之匹配的 id。
将本地端点作为其自身可选路由
使用 transport: api 第二次挂载该插件,以获得一条从不接触 Codex 的路由。它会从 /v1/models 发现该端点所提供的模型,因此选择器会列出该端点实际响应的内容(包括 llama.cpp 服务器报告为 meta.n_ctx 的容量),而不是 Codex 的目录:
- insert:
- id: llm-codex
name: dsh-llm-codex
config:
provider: codex-local
sandbox: read-only
transport: auto
- id: llm-gpudev
name: dsh-llm-codex
config:
provider: gpudev
transport: api
fallback:
baseURL: http://gpudev:8088/v1
apiKeyEnv: GPUDEV_API_KEY
这会生成两个提供方:带有 Codex 模型的 Codex (local),以及带有 qwen3.8-27b-q5 的 gpudev:8088。仅端点路由的显示名称取自端点主机,不需要凭据,并且不声明图像能力,因为回退路径仅发送文本。
发现是建议性的,并缓存一分钟:不可达的端点会使列表为空,而不是使模型解析失败;刷新失败会保留先前的列表。将同一行指向任何 OpenAI 兼容服务器即可。
当仅端点路由没有可发现的内容时,它会回退到
fallback.model,然后是 models。设置 fallback.model 也会固定发送到线上的 id;当它为空时,调用方选择的 id 会按原样发送,而像 llama.cpp 这样的无密钥服务器会忽略它,转而使用唯一已加载的模型。
transport: auto 会先尝试 CLI,只有当 CLI 没有产生任何输出并且以 AUTH、MISSING_CREDENTIAL、TRANSPORT、TIMEOUT、INVALID_REQUEST 或 EMPTY_RESPONSE 失败时,才会回退。部分输出之后的失败会按原样返回,因此内容永远不会被重复。transport: api 会将每个请求路由到端点,绕过 Codex。
安装 / 更新
下面每一种形式都是一次 dsh plugin 调用,它会转发到 profile 目录中的 pnpm,然后根据已安装的内容来协调 dsh.profile.bundles。由于此包声明了 dsh.bundle.patch,挂载行会为你添加——在任何安装路径中都不需要编辑 cordis.patch.yml。
对于本地开发,请将此目录安装为 link 依赖,这样编辑会在下次加载时生效,无需重新安装:
dsh plugin --profile web add link:~/src/dsh-llm-codex
dsh plugin 会将相对的 file:/link: 规范锚定到你的当前目录,而不是 profile,因此在使用相对路径时,请从 profile 外部运行它。
空的 baseURL 加上 transport: cli 就足以让插件保持离线。挂载生效需要重启 profile。
为什么用 GitHub 而不是 npm
没有官方的 DSH 插件注册表:插件就是一个普通的包,发现是通过 GitHub 的 dsh-plugin 主题进行的。此仓库就是以这种方式分发的,而 private: true 保持设置有一个具体原因——npm 上的名称 dsh-llm-codex 已被一个无关的实现(yequ172672/dsh-codex-subscription)占用。以相同名称发布要么会失败,要么会与用户已有的包冲突。请改为从 git 仓库安装;dsh-plugin 主题才是让它可被发现的原因。
与另一台机器共享
该插件是可移植的:它在加载时发现 Codex CLI(先是配置的 command,然后是 $CODEX_COMMAND,然后是 PATH,然后是已知的安装位置),从该机器的 $CODEX_HOME 读取模型目录,并从接收方的 DSH 安装中解析 harness 包。这里没有任何内容硬编码此机器的路径,因此同一个包在任何装有 DSH 且已登录 Codex 的 Mac 上都能工作。
下面的三个选项都是一次 dsh plugin --profile web add 调用。该包自带 cordis.patch.yml 并声明了 dsh.bundle.patch,因此 llm-codex 挂载行是由 bundle 层组合而成的——不要再手写该行,如果你在 0.2.0 之前安装过,请参阅从 0.1.x 升级。
选项 A——一个 tarball(最简单)
构建该包,将 .tgz 复制到另一台 Mac(AirDrop、scp、USB),然后在那台机器上:
dsh plugin --profile web add /path/to/dsh-llm-codex-0.2.0.tgz
pnpm 会把 tarball 复制到它的虚拟存储中,因此 .tgz 只在安装时需要。
用更新的 tarball 重新运行相同的命令即可更新。接收方的 profile 中无需编辑任何内容:挂载行来自该包。
在此目录中运行 npm pack 会生成该 tarball,即使设置了
private: true 也能正常工作——该字段只会阻止发布到 registry。
方案 B —— git 仓库
直接从该仓库安装。SSH 是可靠的形式:它使用已为 GitHub 配置好的
密钥,而 https 形式在本机没有缓存凭据时会因凭据问题而卡住。
dsh plugin --profile web add git+ssh://git@github.com/zhangzhangco/dsh-llm-codex.git
首次安装会进行解析并克隆(此处大约需要一分钟)。之后用以下命令更新:
dsh plugin --profile web update dsh-llm-codex
如果 pnpm 打印出 allowBuilds 键——它默认会阻止依赖构建脚本——请将该键
添加到 ~/.dsh/profiles/web/pnpm-workspace.yaml 并重新运行。
此包不包含构建步骤,因此普通安装通常不需要任何操作。
方案 C —— 用于开发的文件夹
将目录复制过去并链接它,这样编辑无需重新安装即可生效——
即 安装 / 更新 中的 link: 形式。
从 0.1.x 升级
在 0.2.0 之前,该包未声明 dsh.bundle,因此每次安装都需手动完成:
在 ~/.dsh/profiles//cordis.patch.yml 中添加一行 profile 补丁,
内容为 id: llm-codex。从 0.2.0 起,bundle 会提供该行,而两个具有相同 id
的条目在启动时是致命的——加载器会抛出
duplicate loader entry id: llm-codex,profile 无法启动。
因此,从 0.1.x 迁移时,请从你自己的补丁文件中删除 llm-codex 的 insert
行,只保留针对每台机器的覆盖项作为以 id 为目标的补丁:
- id: llm-codex
config:
sandbox: danger-full-access
以 id 为目标的补丁会替换整个 config 值;config.js 中的 Schemastery schema
会用默认值填充每个省略的键,因此部分覆盖就足够了。无需启动任何内容即可检查
组合后的树:
dsh --profile web --dump-config
不会随之迁移的内容
- 凭据。 apiKeyEnv 指定的是一个引用;其值存在于该机器的环境或凭据存储中。
- $CODEX_HOME。 Codex 的登录状态和模型缓存是每台机器独立的——如果 Codex
尚未登录,请在那里运行 codex login。
- profile 的 link: 路径。 package.json 会为链接的依赖记录绝对路径;
在新机器上请改用 tarball 或 git 形式安装,而不是复制该路径。
验证
- dsh --profile web --dump-config —— llm-codex 行已被组合。
- 启动该 profile;启动日志会输出
dsh-llm-codex: route codex-local ready (transport=…, command=…),其中指明了
发现机制所选择的 Codex CLI。
- 模型选择器会在 Codex (local) 下列出 Codex 模型。
- 一次调用:codex exec --json --ephemeral -s read-only -C "$PWD" "Reply with exactly: pong"。
已知限制
- 没有增量流式输出。 codex exec --json 发出的是已完成项,而不是
token 增量,因此一个回合会以整条消息增量的形式到达。用量和结束
原因是精确的。
- 默认使用 --ephemeral。 每次调用都是一个全新的 Codex 线程,对话会作为
提示文本重放;没有恢复机制,因此 Codex 侧的
记忆不会跨回合保留。
- 不支持图像。 图像块会被渲染为 [image attachment …]
占位符;codex exec 将图像作为文件参数接收,而不是 JSON 项。
- 在 CLI 路径上,工具 schema 会被忽略。 回退路径确实会发送
它们,并将流式工具调用映射回来。
- Codex 的工具在 harness 沙箱之外运行。 在 CLI 路径上,Codex 是一个
独立进程,拥有自己的沙箱,因此 harness 工作区边界
无法约束它。在 Codex 无法创建自己的沙箱的情况下,写入需要
danger-full-access,并且运行不受限制;回退路径
完全不执行任何工具。
通过 App Server 实现真正的流式输出
在 llm-codex 配置中设置 cliBackend: app-server,以使用 Codex 的 stdio
App Server 协议。为保持兼容性,默认值仍为 exec。现有的
transport: auto | cli | api 设置继续用于选择 CLI 还是 API 路由。
args 仅适用于 exec;appServerArgs 仅适用于 app-server(例如
-c 覆盖项)。现有的 exec 专用标志绝不会被盲目转发。
每个请求拥有一个隔离的进程和临时线程(除非显式禁用 ephemeral)。
文本增量会立即转发;完成时只会追加尚未接收到的尾部内容。可见的推理摘要具有独立的块索引。
适配器会保留模型、effort、cwd、CODEX_HOME 和沙箱设置。
App Server 使用 approvalPolicy: never:沙箱限制仍然有效,
但它无法请求提升权限。意外的交互式请求会以失败关闭方式处理;
这不是审批桥接。Codex 工具仍然在 DSH 的
工具调用记录之外运行,与 exec 后端完全一样。
取消、超时、消费者提前退出和完成都会清理进程。
不会通过 exec 进行自动重试。现有的 API 回退仅在
配置了的情况下、且在输出之前才被允许。Codex 内部的网络/WebSocket 重试是
另一个独立的延迟来源;切换接口并不能消除它们。
有两种失败模式会被显式处理,二者都已针对真实回合验证过:
- 该协议没有顶层致命错误通知,因此如果服务器关闭了一个线程
而没有发出 turn/completed,否则就会一直停滞直到
timeoutMs(默认 10 分钟)。现在,针对活动线程的 thread/closed
会立即使请求失败。正常的临时回合绝不会发出它——
观察到的顺序将 turn/completed 放在最后。
- 带有 willRetry: true 的 error 通知是传输层重试
(WebSocket → HTTPS),并且不是失败;判定结果仍会通过
turn/completed 到达。前三个会被回显到 stderr,并截断,因此一个首 token
耗时两分钟的轮次在日志中是可解释的,而不会看起来像静默停滞。
图像保留旧的文本附件占位符行为;此更改不实现原生图像附件转发。
协议参考:https://learn.chatgpt.com/docs/app-server
已在 macOS 上通过两种独立方式针对 Codex CLI 0.154.0 验证:
- 生成的协议包(codex app-server generate-json-schema --out DIR
--experimental)确认了此模块使用的每个方法和字段:客户端请求
initialize / initialized / thread/start / turn/start /
turn/interrupt,通知 item/agentMessage/delta、
item/reasoning/summaryTextDelta、item/completed、thread/tokenUsage/updated
和 turn/completed,以及确切的参数名(clientInfo、threadId、
turnId、itemId、delta、summaryIndex、input、effort、sandbox、
approvalPolicy、ephemeral)。AskForApproval 确实接受 never,
而 SandboxMode 确实接受三个 CLI 沙箱名称。
- 一次实时握手和流式轮次:initialize → initialized →
thread/start → turn/start 均被接受,并且一个真实轮次在 23 秒内
交付了 565 个增量文本增量(612 个字符),而不是单个数据块。
然而,首个 token 在 122 秒时才到达,因为 Codex 在生成之前重试了
其传输(WebSocket → HTTPS);该延迟存在于 Codex 自身的网络栈中,
并且不会被此后端消除。
开发:npm ci --ignore-scripts,然后 npm test。
可选的真实请求:node scripts/probe-stream.mjs (使用 CLI 登录)。
回滚:设置 cliBackend: exec 并重启 DSH。profile package.json 和
pnpm-lock.yaml 在链接安装之前会作为 .bak- 备份在自身旁边,
因此包安装回滚意味着恢复这两个文件并运行 pnpm install。