390 lines
17 KiB
Markdown
390 lines
17 KiB
Markdown
# Master Server 运维
|
||
|
||
本文记录 Master Server 的架构与判定规则。已安装的 Codex wrapper 负责命令语法,
|
||
本文负责 profile 边界、安全规则和验收标准。通用 server 生命周期与 GC 命令仍由
|
||
`unidesk-ops` skill 负责。禁止在本文记录 Secret、一次性故障流水或带日期的
|
||
changelog。
|
||
|
||
## 执行边界
|
||
|
||
- Master Server 是生产入口和控制面。
|
||
- 本机默认只执行轻量源码修改、Git 操作、状态检查、健康检查、日志、诊断、
|
||
JSON CLI 控制动作和本地 profile wrapper 维护。
|
||
- 重型构建和仓库级检查必须放到 G14、D601、CI/CD 或目标运行面。
|
||
- 本机 `/root/unidesk` checkout 可用于轻量 UniDesk CLI、`trans`、`tran`
|
||
和 helper 修改。
|
||
|
||
## Codex Provider Profile
|
||
|
||
- `mycx` 与 `oncx` 是 `/usr/local/bin/` 下的稳定系统 Codex wrapper。
|
||
- 两者复用同一个系统 `codex` binary。
|
||
- 两者的认证 home 已隔离,长期约束见“系统 Wrapper 与共享状态”。
|
||
- `dscx`、`mxcx` 和 `acx` 是 `/root/.local/bin/` 下的隔离 profile
|
||
wrapper。
|
||
- 它们是 host 级工具,不属于 UniDesk service 代码。
|
||
- `acx` 是统一多模型入口。
|
||
- `gocx` 保留为 OpenCode Zen Go 兼容入口。
|
||
- 旧的 `dscx-go`、`dfcx-go` 和 `glcx-go` 只保留兼容入口。
|
||
|
||
- `dscx`:
|
||
- 使用 `CODEX_HOME=/root/.codex-deepseek-v4-pro`;
|
||
- 使用模型 `deepseek-v4-pro` 和 Codex 自定义 provider `deepseek`;
|
||
- 使用本机 Moon Bridge `http://127.0.0.1:38440/v1`。
|
||
- `mxcx`:
|
||
- 使用 `CODEX_HOME=/root/.codex-minimax-m3`;
|
||
- 使用模型 `MiniMax-M3` 和 Codex 自定义 provider `minimax`;
|
||
- 使用本机 Moon Bridge `http://127.0.0.1:38441/v1`。
|
||
- `acx`:
|
||
- 使用 `CODEX_HOME=/root/.codex-acx`;
|
||
- 默认模型是 `gpt-5.5-only`;
|
||
- GPT alias 通过 Codex 自定义 provider 直连 OpenAI-compatible Responses 上游;
|
||
- OpenCode Zen Go alias 仍通过本机 ACX router 到达 `gocx` / Moon Bridge。
|
||
- `gocx`:
|
||
- 使用 `CODEX_HOME=/root/.codex-opencode-go-all`;
|
||
- 默认模型是 `glm-5.1`;
|
||
- 使用 Codex 自定义 provider `opencode`;
|
||
- 使用本机 Moon Bridge `http://127.0.0.1:38447/v1`。
|
||
- `dscx-go`:
|
||
- 使用 `CODEX_HOME=/root/.codex-opencode-go`;
|
||
- 使用模型 `deepseek-v4-pro`;
|
||
- 使用本机 Moon Bridge `http://127.0.0.1:38443/v1`。
|
||
- `dfcx-go`:
|
||
- 使用 `CODEX_HOME=/root/.codex-opencode-flash`;
|
||
- 使用模型 `deepseek-v4-flash`;
|
||
- 使用本机 Moon Bridge `http://127.0.0.1:38444/v1`。
|
||
- `glcx-go`:
|
||
- 使用 `CODEX_HOME=/root/.codex-opencode-glm`;
|
||
- 使用模型 `glm-5.1`;
|
||
- 使用本机 Moon Bridge `http://127.0.0.1:38446/v1`。
|
||
|
||
- `acx` 的 `model-catalog.json`:
|
||
- 包含全部 OpenCode Zen Go upstream slug;
|
||
- 包含 `gpt-5.5-only` 和 `gpt-5.5-sub2api`;
|
||
- 允许在同一 profile 中通过 `/model` 或 `-m <model>` 切换。
|
||
- `acx` 的 GPT 路由:
|
||
- `gpt-5.5-only` 直连 `only` OpenAI-compatible Responses endpoint;
|
||
- `gpt-5.5-sub2api` 直连 Sub2API pool endpoint;
|
||
- 两者的 upstream model 都是 `gpt-5.5`;
|
||
- GPT 请求禁止经过 Moon Bridge 或 ACX router。
|
||
- GPT direct provider:
|
||
- 必须通过 `ACX_GPT_DIRECT_API_KEY` 一类环境键接收 API key;
|
||
- wrapper 从对应的 `/root/.codex/auth.json.<profile>` 读取;
|
||
- 禁止回退到 `/root/.codex-acx/auth.json`;
|
||
- `/root/.codex-acx/auth.json` 只允许保存本地 router dummy key。
|
||
- 隔离的 Moon Bridge 与 router wrapper:
|
||
- 从 profile auth 文件读取 upstream API key;
|
||
- 仅在兼容路径确有需要时由 wrapper 注入环境变量;
|
||
- 生成配置放在 profile 的 `.tmp/`,权限必须是 `0600`;
|
||
- 此兼容规则不适用于 `mycx` 的 Pika command-backed auth。
|
||
- 每个 profile:
|
||
- 必须在 `config.toml` 中设置 `model_catalog_json`;
|
||
- 必须指向包含当前模型的 profile-local `model-catalog.json`;
|
||
- 缺失时 Codex 会回退到默认 metadata,并输出
|
||
`Model metadata ... not found`。
|
||
- Profile context metadata:
|
||
- 必须与真实 upstream limit 对齐;
|
||
- 必须让 Codex auto-compact 在 provider 拒绝请求前触发。
|
||
- 当前 Master Server profile baseline:
|
||
- `acx` 暴露的 GPT profile 使用
|
||
`model_context_window = 272000` 和
|
||
`model_auto_compact_token_limit = 240000`;
|
||
- `deepseek-v4-pro` 与 `deepseek-v4-flash` 使用
|
||
`model_context_window = 1000000` 和
|
||
`model_auto_compact_token_limit = 900000`;
|
||
- `glm-5.1`、`MiniMax-M3` 及其他本地 Moon Bridge profile 使用
|
||
`model_context_window = 200000` 和
|
||
`model_auto_compact_token_limit = 180000`。
|
||
- Wrapper 生成的 Moon Bridge / router metadata:
|
||
- 必须与 profile `config.toml` 和 `model-catalog.json` 对齐;
|
||
- 不一致时 Codex 与本地 admission layer 会对 compact 和请求大小产生分歧。
|
||
- Codex API 通道的 `NO_PROXY` / `no_proxy`:
|
||
- 必须保留 `hyueapi.com` 和 `.hyueapi.com`。
|
||
|
||
### 系统 Wrapper 与共享状态(`mycx` / `oncx`)
|
||
|
||
- `mycx` 与 `oncx`:
|
||
- 复用同一个系统 `codex` binary;
|
||
- 使用不同的认证 `CODEX_HOME`;
|
||
- 共享 SQLite session index 和 durable transcript。
|
||
- `/usr/local/bin/mycx`:
|
||
- 使用 `CODEX_HOME=/root/.codex`;
|
||
- 选择 profile `pika`;
|
||
- 可写 profile 文件是 `/root/.codex/pika.config.toml`。
|
||
- `/usr/local/bin/oncx`:
|
||
- 使用 `CODEX_HOME=/root/.codex-only`;
|
||
- 使用 `CODEX_SQLITE_HOME=/root/.codex`;
|
||
- 选择 profile `only`;
|
||
- 可写 profile 文件是 `/root/.codex-only/only.config.toml`。
|
||
- `oncx` 的账号认证:
|
||
- 只使用 `/root/.codex-only/auth.json`;
|
||
- `cli_auth_credentials_store` 必须是 `file`;
|
||
- `forced_login_method` 必须是 `chatgpt`;
|
||
- `auth.json` 权限必须是 `0600`;
|
||
- wrapper 必须清理 `OPENAI_API_KEY`、`CODEX_API_KEY`、
|
||
`CODEX_ACCESS_TOKEN` 和 `CRS_OAI_KEY`;
|
||
- `oncx login`、`oncx login status` 和 `oncx logout` 必须直接操作
|
||
隔离 home,禁止附加仅适用于 runtime command 的 `--profile`。
|
||
- `oncx` 的共享状态:
|
||
- `/root/.codex-only/sessions` 链接到 `/root/.codex/sessions`;
|
||
- `/root/.codex-only/archived_sessions` 链接到
|
||
`/root/.codex/archived_sessions`;
|
||
- `history.jsonl`、`skills` 和 `plugins` 链接到共享 home;
|
||
- shell snapshot、认证文件和 profile 配置保持隔离。
|
||
- `/root/.codex/config.toml` 与 `/root/.codex/auth.json`:
|
||
- 由 `codex-pool configure-local` 管理;
|
||
- 只代表 Sub2API consumer;
|
||
- 禁止作为 `oncx` 的 ChatGPT 登录凭据。
|
||
- Webterm:
|
||
- `config/platform-infra/webterm.yaml` 启动 `mycx`;
|
||
- wrapper path 或启动方式变更必须保留原入口并执行 Webterm launch check。
|
||
- Shell startup 文件:
|
||
- 禁止定义同名 function 覆盖这些 executable;
|
||
- 禁止在启动时重新生成 profile 文件;
|
||
- wrapper 变更后,旧 Codex 进程必须退出;
|
||
- 旧 shell 必须清除残留 function 或启动新 shell后再验收。
|
||
|
||
- Profile-v2 持久化:
|
||
- `/model` 把 `model` 与 reasoning effort 写入当前 profile 文件;
|
||
- `mycx` 与 `oncx` 必须独立记住最后一次选择;
|
||
- `-m`、`-c model...` 和 `-c model_reasoning_effort...` 只允许临时覆盖;
|
||
- 新启动、profile 切换和 resume 必须分别诊断。
|
||
- Codex 官方认证边界:
|
||
- `--profile` 只覆盖 profile TOML,不隔离 `auth.json`;
|
||
- file-based credential storage 的 `auth.json` 由 `CODEX_HOME` 决定;
|
||
- 账号登录与 API-key consumer 必须使用不同的 `CODEX_HOME`;
|
||
- 依据见
|
||
[Codex Manual](https://developers.openai.com/codex/codex-manual.md#configuration-auth-and-models)。
|
||
|
||
- Session discovery:
|
||
- 共享 SQLite 和 transcript 不保证 `/resume` 结果完全相同;
|
||
- picker 还会按 provider ID、cwd、source 和 archive state 过滤;
|
||
- provider ID 是持久化且大小写敏感的 session bucket key;
|
||
- `--all` 只移除 cwd 限制,不移除 provider 限制;
|
||
- Codex 升级后必须重新验证此契约;
|
||
- resume 使用当前 profile 的有效 model、provider 和 reasoning override;
|
||
- resume 不保证恢复 session 最后记录的模型。
|
||
- Rollout JSONL:
|
||
- 是 durable history;
|
||
- 可以重新填充 SQLite index;
|
||
- 禁止只修改 `state_5.sqlite` 合并 provider bucket;
|
||
- history migration 必须停止活动 Codex 进程;
|
||
- 必须用结构化 JSON parser 修改 rollout metadata;
|
||
- 必须事务化更新 SQLite index;
|
||
- 必须保留 provenance 并在 reindex 后验证相同 session ID 集合。
|
||
- Provider identity:
|
||
- 是兼容性契约;
|
||
- 修改 `CODEX_HOME`、profile name、provider ID 或大小写前必须预检历史;
|
||
- 会产生新隐藏 bucket 时必须告警或阻断;
|
||
- 禁止让不同真实 backend 仅为合并 picker list 而冒充同一 provider。
|
||
|
||
- Pika 认证:
|
||
- 必须使用 `[model_providers.Pika.auth]` 的 command-backed provider auth;
|
||
- credential source 是 `/root/.codex/auth.json.pika`;
|
||
- 文件权限必须是 `0600`;
|
||
- 禁止把 Pika API key 导出到 wrapper 或 Codex 环境;
|
||
- shell snapshot 权限必须是 `0600`;
|
||
- shell snapshot 禁止包含可复用 credential;
|
||
- 发现 plaintext snapshot 时必须删除副本并轮换 credential。
|
||
|
||
- Secret-safe 诊断只允许报告:
|
||
- 有效 `CODEX_HOME`;
|
||
- wrapper path;
|
||
- 当前 profile 文件;
|
||
- provider ID;
|
||
- model 与 reasoning;
|
||
- 按 provider 统计的 session 数量;
|
||
- credential presence 或 fingerprint;
|
||
- 相关文件权限。
|
||
- Profile 持久化验收:
|
||
- 选择一个非 baseline `/model`;
|
||
- 退出后重新启动相同 wrapper;
|
||
- 确认选择保持;
|
||
- 确认另一 profile 文件未变化;
|
||
- 确认临时 CLI override 不写回 profile。
|
||
- `oncx` 认证验收:
|
||
- `oncx login status` 必须显示 `Logged in using ChatGPT`;
|
||
- 注入无效 API-key 环境变量后仍必须显示 ChatGPT 登录;
|
||
- `oncx exec --ephemeral '<smoke prompt>'` 必须完成真实 Responses turn;
|
||
- 共享 `codex login status` 必须继续显示 Sub2API API-key 登录;
|
||
- 全程禁止输出 token 或完整 API key。
|
||
- `mycx` 认证验收:
|
||
- 对应 API-key 环境变量缺失时,Pika command-backed auth 仍必须可用。
|
||
- `/resume` 差异诊断:
|
||
- 先比较 `CODEX_HOME`、provider ID、cwd、source 和 archive filter;
|
||
- 禁止在这些边界未核对前归因为 storage loss 或 cache。
|
||
|
||
相关调查证据与源码级依据保留在
|
||
[UniDesk issue #1640](https://github.com/pikasTech/unidesk/issues/1640),本文是当前长期规则的
|
||
唯一权威入口。
|
||
|
||
## Moon Bridge
|
||
|
||
Moon Bridge 安装在 `/root/.local/bin/moonbridge`。该 binary 暴露 OpenAI Responses
|
||
endpoint,并把 Codex 请求桥接到 provider-specific upstream API。已安装的 profile
|
||
wrapper 负责 bridge 命令语法,本文只记录运行边界。
|
||
|
||
- 已安装 patch build 的本地源码:
|
||
- 路径是 `/root/src/moon-bridge-sanitize`;
|
||
- 修改时必须保持范围收敛;
|
||
- 必须运行 package-level test;
|
||
- 必须构建 replacement binary;
|
||
- 必须备份旧 binary;
|
||
- 必须重启受影响的 profile bridge;
|
||
- 仍受 Master Server 重型构建限制。
|
||
|
||
### Profile 架构
|
||
|
||
- `dscx bridge-start`:
|
||
- 渲染 profile 配置;
|
||
- 在 `127.0.0.1:38440` 启动 Moon Bridge。
|
||
- `mxcx bridge-start`:
|
||
- 渲染 profile 配置;
|
||
- 在 `127.0.0.1:38441` 启动 Moon Bridge。
|
||
- `acx route-start`:
|
||
- 渲染 ACX router 配置;
|
||
- 在 `127.0.0.1:38448` 启动本地 routing service;
|
||
- 只服务仍需 OpenCode Zen Go bridge path 的非 GPT alias。
|
||
- `gocx bridge-start`:
|
||
- 渲染多模型 OpenCode Zen Go profile 配置;
|
||
- 在 `127.0.0.1:38447` 启动 Moon Bridge。
|
||
- `dscx-go bridge-start`:
|
||
- 在 `127.0.0.1:38443` 启动 Moon Bridge。
|
||
- `dfcx-go bridge-start`:
|
||
- 在 `127.0.0.1:38444` 启动 Moon Bridge。
|
||
- `glcx-go bridge-start`:
|
||
- 在 `127.0.0.1:38446` 启动 Moon Bridge。
|
||
- Wrapper 启动 bridge:
|
||
- 使用 `setsid`;
|
||
- 使用 profile-local PID 文件;
|
||
- 日志写入 `<CODEX_HOME>/logs/moonbridge/`。
|
||
- `dscx` 路由:
|
||
- 通过 Moon Bridge 使用 Anthropic-compatible upstream;
|
||
- 使用 `deepseek_v4` extension。
|
||
- `mxcx` 路由:
|
||
- 通过 Moon Bridge 使用 `openai-response` upstream passthrough。
|
||
- OpenCode Zen Go 路由:
|
||
- `acx` 把模型路由到 `gocx` / Moon Bridge;
|
||
- `gocx`、`dscx-go`、`dfcx-go` 和 `glcx-go` 使用
|
||
`openai-chat` upstream;
|
||
- upstream 是 `https://opencode.ai/zen/go/v1/chat/completions`;
|
||
- Codex 侧保持 `wire_api = "responses"`。
|
||
- `acx` GPT 路由:
|
||
- 必须直连 OpenAI-compatible Responses endpoint;
|
||
- 禁止经过 Moon Bridge 或本地 ACX router;
|
||
- GPT mode 下 `acx status` 必须报告 `mode=gpt-direct`;
|
||
- 必须报告 `routerRequired=false`;
|
||
- `127.0.0.1:38448` 不应存在 listener。
|
||
- OpenCode Zen Go model ID:
|
||
- 必须使用 upstream slug,例如 `glm-5.1`;
|
||
- `GLM-5.1` 一类 display name 不是 profile model identifier。
|
||
- OpenCode Zen Go bridge:
|
||
- 禁止保留手写 bridge script;
|
||
- 禁止保留静态替代 `moonbridge.config.yml`;
|
||
- 唯一支持路径是 wrapper 生成的 `.tmp/moonbridge.generated.yml` 和
|
||
`/root/.local/bin/moonbridge`;
|
||
- 生成的 provider 配置必须显式设置 `user_agent`。
|
||
- Moon Bridge context-window admission:
|
||
- oversized request 必须在本地 Responses path 被拒绝;
|
||
- 预期状态是 HTTP `400`;
|
||
- 错误类型是 `invalid_request_error`;
|
||
- 错误 code 是 `context_length_exceeded`;
|
||
- 禁止表现为 upstream-translated `502 Bad Gateway`。
|
||
- MiniMax:
|
||
- 未经 tool-enabled smoke 证明可用,禁止把 Codex CLI 切到
|
||
`openai-chat`。
|
||
|
||
### Profile 验收
|
||
|
||
- `*-go raw-smoke`:
|
||
- 直接验证 upstream OpenCode Zen Go Chat Completions API。
|
||
- `*-go bridge-smoke`:
|
||
- 验证本地 Moon Bridge 的 `/v1/responses` translation path。
|
||
- `*-go exec '在吗'`:
|
||
- 验证真实 Codex profile;
|
||
- 输出禁止包含 `Model metadata ... not found`;
|
||
- 最新 session 必须使用 profile catalog 提供的
|
||
`model_context_window`。
|
||
- ACX GPT 验收:
|
||
- 使用 `acx status`、`acx models`、
|
||
`acx gpt-only exec '在吗'`、`acx gpt-sub2api exec '在吗'` 和
|
||
默认 `acx exec '在吗'`;
|
||
- 必须完成真实 Codex Responses turn;
|
||
- repeated 或 resume traffic 必须出现非零 `cached_input_tokens`;
|
||
- 禁止依赖 `127.0.0.1:38448` listener。
|
||
- ACX OpenCode Zen Go alias 验收:
|
||
- 使用 `acx route-start`、`acx route-status`、`acx models` 和
|
||
`acx -m <opencode-model> exec '在吗'`;
|
||
- 验证 router 到 `gocx` 的路径。
|
||
- `gocx` 模型验收:
|
||
- 使用 `gocx raw-smoke [model]`;
|
||
- 使用 `gocx bridge-smoke [model]`;
|
||
- 使用 `gocx -m <model> exec '在吗'`;
|
||
- 省略 `[model]` 时默认使用 `glm-5.1`。
|
||
- `ReasoningSummaryDelta without active item`:
|
||
- 是 reasoning summary event 的独立 adapter noise;
|
||
- 不等同于 model metadata 缺失;
|
||
- 不能单独证明 profile 不可用。
|
||
|
||
### OpenAI Responses Tool Argument Sanitizer
|
||
|
||
- Moon Bridge:
|
||
- 负责 MiniMax 风格错误 tool argument JSON 的在线 sanitizer;
|
||
- 作用于 `openai-response` passthrough path;
|
||
- 是第一道防线;
|
||
- wrapper-level session cleanup 只处理 sanitizer 安装前已损坏的 JSONL。
|
||
- Sanitizer:
|
||
- 递归扫描 `ResponsesRequest.input`;
|
||
- upstream 前修复 tool-call `arguments`;
|
||
- 在 completed event 中修复 response-side `arguments`;
|
||
- 禁止修改 delta chunk;
|
||
- 无法恢复时回退到 `{}`;
|
||
- response rewrite 必须删除 upstream `Content-Length`。
|
||
|
||
## MiniMax Session 恢复
|
||
|
||
- `mxcx`:
|
||
- 为损坏的 MiniMax-backed session JSONL 提供 cleanup 与 guard layer;
|
||
- wrapper 负责命令语法;
|
||
- 本节只记录行为规则。
|
||
- `mxcx resume`:
|
||
- 调用 Codex 前自动执行 `session-clean` 和 `session-guard`;
|
||
- 使用 `CODEX_HOME=/root/.codex-minimax-m3`。
|
||
- `session-clean`:
|
||
- 只处理无效 tool-call `arguments`;
|
||
- 包括 malformed JSON、MiniMax sentinel text 和 schema-invalid case;
|
||
- 必须保留行顺序、非 tool message、reasoning、output、token record 和
|
||
session metadata;
|
||
- 禁止 compact、summarize、truncate 或 reorder transcript。
|
||
- 新的无效 `arguments`:
|
||
- 必须由 Moon Bridge sanitizer 在线阻止;
|
||
- `session-clean` 只用于恢复既有损坏 session。
|
||
- `session-guard`:
|
||
- 注入 `mxcx-minimax-tool-and-apply-patch-guard-v2`;
|
||
- 禁止重复注入。
|
||
|
||
## MiniMax Apply-Patch 操作
|
||
|
||
- MiniMax-backed session:
|
||
- 必须使用与其他 agent 相同的 UniDesk 远端文本 patch 契约;
|
||
- route 在前,operation 在后;
|
||
- 默认使用 `apply-patch` v2。
|
||
- 稳定写入形式:
|
||
- `trans <provider>:/absolute/workspace apply-patch < patch.diff`。
|
||
- 只读检查:
|
||
- 使用 `trans <provider>:/absolute/workspace nl -ba file` 或同等有界命令。
|
||
- `apply-patch` 报告 `failed to find expected lines` 时:
|
||
- 先读取目标当前精确内容;
|
||
- 再用更小的 `Update File` hunk 重试;
|
||
- 或使用 `@@ <unique anchor>`;
|
||
- 或拆成多个小 hunk;
|
||
- 这是正常 stale-context 恢复,禁止因此切换工具。
|
||
- 文本 patch 失败时禁止使用:
|
||
- `download` / `upload`;
|
||
- 远端 Python、Perl 或 sed heredoc;
|
||
- `cat >` 或 `tee` 整文件覆盖;
|
||
- `apply-patch-v1`。
|
||
- 仅在以下情况允许例外:
|
||
- `apply-patch` 本身不可用;
|
||
- 目标不是文本;
|
||
- 目标是批量机械生成内容。
|