Merge pull request #134 from openqj/feat-longtask-docker-resume-env

修法:Docker 断点续跑透传密钥环境(SUB2API_API_KEY 缺失空转)
This commit is contained in:
openqj authored and GitHub committed 2026-10-29 12:48:12 +08:00
commit 49f3ff7cb6
2 files changed
+43 -1

No files matched your search

+8 -1
View File
@@ -1440,6 +1440,11 @@ class DockerExecutor(Executor):
创建,续跑容器不带同一 --model-provider 时 Server 的
provider 表里没有它,thread/resume 报 provider not found
(2026-10-29 probe15 实弹)。
密钥环境也必须透传:密钥类变量只按名进 docker run
命令(-e SUB2API_API_KEY 不带值),值靠 _docker_cli_env
放进 CLI 子进程环境;本方法此前漏传 env,容器内 key
为空,每轮瞬间报 Missing SUB2API_API_KEY、无限空转
(2026-10-29 长任务实弹:断点后 274 轮全失败)。
"""
if not isinstance(task, dict) or task.get("id") is None:
raise ValueError("任务缺少 id")
@@ -1453,7 +1458,9 @@ class DockerExecutor(Executor):
network=network,
extra_env=extra_env)
try:
result = self._call_runner(cmd, timeout=timeout)
result = self._call_runner(
cmd, timeout=timeout,
env=self._docker_cli_env(extra_env))
except Exception as exc:
if exc.__class__.__name__ == "TimeoutExpired":
self.kill_container(task)
+35
View File
@@ -490,6 +490,41 @@ class P1WorkerTestCase(unittest.TestCase):
"--model-provider" in cmd and "sub2api" in cmd
for cmd in self.calls))
# 12d. Docker 断点续跑必须把密钥环境透传给 runner:
# 密钥类变量只按名进 docker run(-e SUB2API_API_KEY 不带值),
# 值靠 _docker_cli_env 放进 CLI 子进程环境;漏传 env 时容器
# 内 key 为空,每轮瞬间报 Missing SUB2API_API_KEY(2026-10-29
# 长任务实弹:断点后 274 轮全失败、无限空转)。
def test_docker_breakpoint_forwards_secret_env_to_runner(self):
seen = {}
def dfake(cmd, timeout=None, env=None):
seen["cmd"] = list(cmd)
seen["env"] = env
return SimpleNamespace(
returncode=0,
stdout="goal met after rounds\n"
"usage input=10 cached=0 cache_write=0 output=5 "
"reasoning=0 total=15 completions=1\n",
stderr="")
task = {"id": "T1", "prompt": "orig goal"}
docker = DockerExecutor(runner=dfake, env=FAKE_ENV)
with mock.patch("cloud.sandbox.shutil.which",
return_value="/usr/bin/docker"):
docker.goal_resume_breakpoint_task(
task, model_provider="sub2api",
extra_env={"SUB2API_API_KEY": "secret-placeholder",
"SUB2API_BASE_URL": "https://example.test"})
# 命令里密钥只按名出现,不带值(不进 argv)。
self.assertIn("SUB2API_API_KEY", seen["cmd"])
self.assertNotIn("SUB2API_API_KEY=secret-placeholder",
seen["cmd"])
# runner 的 CLI 环境里必须有值,否则容器内 key 为空。
self.assertIsNotNone(seen["env"])
self.assertEqual(seen["env"].get("SUB2API_API_KEY"),
"secret-placeholder")
# 13. 开新目标:goal-resume 带 --goal-text(旧行为保留)
def test_goal_resume_new_goal_keeps_goal_text(self):
calls = []