From 6022f1dada59e074164232ea43df7a94b611d0b5 Mon Sep 17 00:00:00 2001 From: openqj Date: Tue, 27 Oct 2026 02:00:09 +0800 Subject: [PATCH] chore: default model gpt-6.1-sol -> gpt-5.6-terra (#60) Co-authored-by: host --- cloud/tests/test_worker.py | 6 ++++-- cloud/worker.py | 5 ++++- config.xcmapi.example.toml | 4 +++- host-config-docker.json | 2 +- host-config-host.json | 2 +- host-config.example.json | 2 +- host.py | 4 ++-- 7 files changed, 16 insertions(+), 9 deletions(-) diff --git a/cloud/tests/test_worker.py b/cloud/tests/test_worker.py index 86b62f8..1e9f617 100644 --- a/cloud/tests/test_worker.py +++ b/cloud/tests/test_worker.py @@ -536,7 +536,8 @@ class WorkerTestCase(unittest.TestCase): self.assertGreater(report["estimated_tokens"], 0) self.assertEqual(report["actual_tokens"], 0) # 复用 cost.py 的记录结构:估算标 estimated,不冒充 actual。 - self.assertEqual(row[0], "gpt-6.1-sol") + # 模型列跟 worker 默认模型走(2026-10-27 起为 terra)。 + self.assertEqual(row[0], "gpt-5.6-terra") self.assertEqual(row[1], "estimated") self.assertEqual(row[2], 0) @@ -569,8 +570,9 @@ class WorkerTestCase(unittest.TestCase): stderr="") _insert_task(self.db_path, "A") router = ModelRouter(["gpt-6.1-sol", "gpt-6-sol"]) + # 显式指定主模型:fallback 场景不依赖全局默认模型的值。 worker = self._worker(runner=self._recording_runner(fake), - router=router) + router=router, model="gpt-6.1-sol") result = worker.run_one() self.assertEqual(result["status"], "failed") self.assertEqual(len(result["events"]), 1) diff --git a/cloud/worker.py b/cloud/worker.py index 053cb2b..4b017ba 100644 --- a/cloud/worker.py +++ b/cloud/worker.py @@ -142,7 +142,10 @@ TERMINAL_STATUSES = frozenset( {"completed", "failed", "interrupted", "merged", "merge-failed"}) COMPLETED_STATUSES = frozenset({"completed", "merged"}) DEFAULT_ENV_KEY = "XCM_API_KEY" -DEFAULT_MODEL = "gpt-6.1-sol" +# 默认模型(2026-10-27 起为 gpt-5.6-terra):此前默认的 +# gpt-6.1-sol 路由当日实测持续 503,terra 同日实测 1 秒完成; +# 任务未指定模型时 worker 与 host.py 都落到这里。 +DEFAULT_MODEL = "gpt-5.6-terra" # host.py dispatch 的原话是 "task 已存在: ,先换名或 discard 它" #(英文 task + 已存在),取共有子串做判断,不依赖标点。 _ALREADY_EXISTS_MARKER = "已存在" diff --git a/config.xcmapi.example.toml b/config.xcmapi.example.toml index b1f7adf..37c5d5d 100644 --- a/config.xcmapi.example.toml +++ b/config.xcmapi.example.toml @@ -4,7 +4,7 @@ # 或在你自己的机器上把密钥放进 shell 环境 / 密钥管理工具。 # 本文件只记录 provider 形状,值本身不在仓库里。 -model = "gpt-6.1-sol" +model = "gpt-5.6-terra" model_provider = "xcmapi" [model_providers.xcmapi] @@ -16,3 +16,5 @@ wire_api = "responses" # 实测(2026-10-25):/v1/models 返回 5 个模型,含 gpt-6.1-sol; # app-server 回合用 gpt-6.1-sol + effort low 已跑通写文件, # 详见 TEST-REPORT.md。 +# 2026-10-27 起默认模型改为 gpt-5.6-terra:gpt-6.1-sol 路由 +# 当日实测持续 503,terra 同日实测 1 秒完成。 diff --git a/host-config-docker.json b/host-config-docker.json index 579393d..663c503 100644 --- a/host-config-docker.json +++ b/host-config-docker.json @@ -1 +1 @@ -{"_note": "Docker 执行器专用配置(容器内路径,绝不是宿主路径):state 必须用相对路径 work/host-state.json——相对配置文件所在目录 /app 解析,得到 /app/work/host-state.json,经额外挂载落到宿主 /opt/codex-app-server/work/host-state.json,属主是 codexsvc(uid 1003,与容器 --user 1003:1004 一致),容器可写。绝不能用默认的 /app/host-state.json(/app 是只读挂载,锁一开就报 Read-only file system),也绝不能用 /work/host-state.json(/work 挂载的宿主目录由 docker 自动创建、属主 root,容器用户写不进去,同样 1 秒内失败)。此文件曾因 deploy 清理被删过(不在仓库里),导致 Docker 派发静默全灭,所以它必须进仓库、随部署一起发。sandbox 用 danger-full-access:主机内核禁止不可信 user namespace,Docker + 内层 bwrap 双重沙箱不可行,生产隔离层就是 Docker 本身。API key 绝不放这里,只走环境变量。 默认仓库是宿主测试仓库:没有 repo_url 的项目走它;有 repo_url 的项目 worker 会把解析出的检出经 --repo 传进去,覆盖它。 codex_home 必须指到 /var/lib/codex-app-server/codex-home(经额外挂载同路径进容器):那里才有真正的 relay 配置(model_provider xcmapi、base_url、env_key),容器 codex 靠它才知道走 relay;指到空目录会让 codex 直接去 api.openai.com 且无 auth,turn 在连接超时里循环重试直到 host.py 600 秒超时。/var/lib 挂载属主是 codexsvc(uid 1003,与容器 --user 一致),可写。", "approval": "deny", "approval_policy": "never", "effort": "low", "model": "gpt-6.1-sol", "sandbox": "danger-full-access", "state": "work/host-state.json", "repo": "/var/lib/codex-app-server/test-repo", "codex_home": "/var/lib/codex-app-server/codex-home"} \ No newline at end of file +{"_note": "Docker 执行器专用配置(容器内路径,绝不是宿主路径):state 必须用相对路径 work/host-state.json——相对配置文件所在目录 /app 解析,得到 /app/work/host-state.json,经额外挂载落到宿主 /opt/codex-app-server/work/host-state.json,属主是 codexsvc(uid 1003,与容器 --user 1003:1004 一致),容器可写。绝不能用默认的 /app/host-state.json(/app 是只读挂载,锁一开就报 Read-only file system),也绝不能用 /work/host-state.json(/work 挂载的宿主目录由 docker 自动创建、属主 root,容器用户写不进去,同样 1 秒内失败)。此文件曾因 deploy 清理被删过(不在仓库里),导致 Docker 派发静默全灭,所以它必须进仓库、随部署一起发。sandbox 用 danger-full-access:主机内核禁止不可信 user namespace,Docker + 内层 bwrap 双重沙箱不可行,生产隔离层就是 Docker 本身。API key 绝不放这里,只走环境变量。 默认仓库是宿主测试仓库:没有 repo_url 的项目走它;有 repo_url 的项目 worker 会把解析出的检出经 --repo 传进去,覆盖它。 codex_home 必须指到 /var/lib/codex-app-server/codex-home(经额外挂载同路径进容器):那里才有真正的 relay 配置(model_provider xcmapi、base_url、env_key),容器 codex 靠它才知道走 relay;指到空目录会让 codex 直接去 api.openai.com 且无 auth,turn 在连接超时里循环重试直到 host.py 600 秒超时。/var/lib 挂载属主是 codexsvc(uid 1003,与容器 --user 一致),可写。", "approval": "deny", "approval_policy": "never", "effort": "low", "model": "gpt-5.6-terra", "sandbox": "danger-full-access", "state": "work/host-state.json", "repo": "/var/lib/codex-app-server/test-repo", "codex_home": "/var/lib/codex-app-server/codex-home"} \ No newline at end of file diff --git a/host-config-host.json b/host-config-host.json index 7ca9d3e..3ee6f21 100644 --- a/host-config-host.json +++ b/host-config-host.json @@ -1 +1 @@ -{"_note":"宿主级沙箱任务专用配置(LocalExecutor,绝不是容器内路径):codex 在宿主上直接跑,sandbox 用 workspace-write(bwrap 内层沙箱,宿主级已验证 --proc 可用;Docker 容器内因嵌套 pidns 导致 fresh proc mount 内核 EPERM,所以容器任务仍用 danger-full-access + Docker 外层,两者按任务 executor 二选一、绝不叠加)。state 用 work/host-state-host.json——相对配置文件所在目录 /opt/codex-app-server 解析,得到 /opt/codex-app-server/work/host-state-host.json,与 Docker 任务的 host-state.json 区分开,避免状态文件互相干扰。repo 与 codex_home 与 Docker 配置相同(宿主测试仓库与真实 relay home);API key 绝不放这里,只走环境变量。宿主 worker 必须以 aa-exec -p codex-host 运行(见 deploy/host-worker/codex-host-worker.service),否则 bwrap 因 AppArmor userns/mount 限制失败;同时 worker 进程须带 HTTP(S)_PROXY=http://127.0.0.1:8888,让宿主级任务的 relay/git 出口同样走 Tinyproxy 白名单(宿主直连出口不受白名单约束,不带代理就等于绕过)。","approval":"deny","approval_policy":"never","codex_home":"/var/lib/codex-app-server/codex-home","effort":"low","model":"gpt-6.1-sol","repo":"/var/lib/codex-app-server/test-repo","sandbox":"workspace-write","state":"work/host-state-host.json"} \ No newline at end of file +{"_note":"宿主级沙箱任务专用配置(LocalExecutor,绝不是容器内路径):codex 在宿主上直接跑,sandbox 用 workspace-write(bwrap 内层沙箱,宿主级已验证 --proc 可用;Docker 容器内因嵌套 pidns 导致 fresh proc mount 内核 EPERM,所以容器任务仍用 danger-full-access + Docker 外层,两者按任务 executor 二选一、绝不叠加)。state 用 work/host-state-host.json——相对配置文件所在目录 /opt/codex-app-server 解析,得到 /opt/codex-app-server/work/host-state-host.json,与 Docker 任务的 host-state.json 区分开,避免状态文件互相干扰。repo 与 codex_home 与 Docker 配置相同(宿主测试仓库与真实 relay home);API key 绝不放这里,只走环境变量。宿主 worker 必须以 aa-exec -p codex-host 运行(见 deploy/host-worker/codex-host-worker.service),否则 bwrap 因 AppArmor userns/mount 限制失败;同时 worker 进程须带 HTTP(S)_PROXY=http://127.0.0.1:8888,让宿主级任务的 relay/git 出口同样走 Tinyproxy 白名单(宿主直连出口不受白名单约束,不带代理就等于绕过)。","approval":"deny","approval_policy":"never","codex_home":"/var/lib/codex-app-server/codex-home","effort":"low","model":"gpt-5.6-terra","repo":"/var/lib/codex-app-server/test-repo","sandbox":"workspace-write","state":"work/host-state-host.json"} \ No newline at end of file diff --git a/host-config.example.json b/host-config.example.json index f8b1891..5363b08 100644 --- a/host-config.example.json +++ b/host-config.example.json @@ -1 +1 @@ -{"_note":"复制成 host-config.json 再改;API key 绝不放这里,只走环境变量","approval":"deny","approval_policy":"never","codex_home":"","effort":"low","model":"gpt-6.1-sol","repo":"work/prod-repo","sandbox":"workspace-write","state":"host-state.json"} \ No newline at end of file +{"_note":"复制成 host-config.json 再改;API key 绝不放这里,只走环境变量","approval":"deny","approval_policy":"never","codex_home":"","effort":"low","model":"gpt-5.6-terra","repo":"work/prod-repo","sandbox":"workspace-write","state":"host-state.json"} \ No newline at end of file diff --git a/host.py b/host.py index aa1150a..6774c5b 100644 --- a/host.py +++ b/host.py @@ -1459,7 +1459,7 @@ def main(): return init_cfg = { "repo": args.repo or cfg.get("repo") or "", - "model": "gpt-6.1-sol", "effort": "low", + "model": "gpt-5.6-terra", "effort": "low", "sandbox": "workspace-write", "approval_policy": "never", "approval": "deny", "codex_home": "", "state": "host-state.json", @@ -1474,7 +1474,7 @@ def main(): print(f"配置文件已写:{config_path},请按需改 repo/model 后再用") return # 有效配置(init/config 之外的命令都用它) - args.model = args.model or cfg.get("model") or "gpt-6.1-sol" + args.model = args.model or cfg.get("model") or "gpt-5.6-terra" args.effort = args.effort or cfg.get("effort") or "low" args.sandbox = args.sandbox or cfg.get("sandbox") args.approval_policy = args.approval_policy or cfg.get("approval_policy") or "never"