cloud: production control plane (API, auth/RBAC, queue, sandbox, memory/KB, fallback/cost, webhooks)

This commit is contained in:
host committed 2026-10-26 01:23:21 +08:00
1 parent b97c34465f
commit b74d99e959
17 files changed
+3420

No files matched your search

+122
View File
@@ -0,0 +1,122 @@
"""沙箱执行器:可插拔的任务执行接口。
零第三方依赖,只用 Python 标准库;不重写 agent 逻辑。
- Executor:基类,子类必须实现 execute(task)。
- LocalExecutor:先行实现,复用 host.py 现有 worktree + codex 沙箱,
通过 host.py CLI 子进程做只读查询封装;不直接跑模型。
- DockerExecutor:占位,未接通容器执行。
- CloudExecutor:占位,未接通云端执行。
"""
import shutil
import subprocess
import sys
MAX_STDOUT_CHARS = 2000
class Executor:
"""执行器基类。
task 是 dict,含 id、project_id、repo、prompt、branch(可选)。
execute(task) -> dict,至少含 executor、task_id、status、stdout。
"""
def execute(self, task) -> dict:
raise NotImplementedError("子类必须实现 execute(task)")
def _truncate_stdout(text):
if text is None:
return ""
return str(text)[:MAX_STDOUT_CHARS]
def _default_runner(cmd):
"""subprocess.run 的薄封装:捕获输出、文本模式。"""
return subprocess.run(cmd, capture_output=True, text=True)
class LocalExecutor(Executor):
"""本地执行器:调 host.py CLI 子进程做执行封装。
真正跑模型回合的 dispatch/run 由控制面在确认模型 key 供给后才
调用,本模块只做执行器骨架和 CLI 调用封装。因此 execute() 在此
只发 host.py 的只读命令(例如 status),绝不在 execute 里直接
跑模型回合;需要跑模型时,控制面另行调用 host.py dispatch/run。
构造函数:LocalExecutor(host_py_path, config_path=None, runner=None)。
runner 默认是 subprocess.run 的薄封装;单测可注入假 runner,假
runner 返回 CompletedProcess 风格的 result 对象(含 returncode、
stdout),本类只读这两个字段,不依赖其它字段。
"""
def __init__(self, host_py_path, config_path=None, runner=None):
self.host_py_path = host_py_path
self.config_path = config_path
self.runner = runner if runner is not None else _default_runner
def _command(self, task_id):
cmd = [sys.executable, self.host_py_path]
if self.config_path is not None:
cmd += ["--config", self.config_path]
cmd += ["status", "--task", str(task_id)]
return cmd
def execute(self, task) -> dict:
task_id = task.get("id") if isinstance(task, dict) else None
if task_id is None:
raise ValueError("任务缺少 id")
result = self.runner(self._command(task_id))
returncode = getattr(result, "returncode", 1)
stdout = _truncate_stdout(getattr(result, "stdout", ""))
return {
"executor": "local",
"task_id": task_id,
"status": "completed" if returncode == 0 else "failed",
"stdout": stdout,
"returncode": returncode,
}
class DockerExecutor(Executor):
"""容器执行器(占位,未接通)。
本机无 docker(shutil.which("docker") 为 None)时 raise
RuntimeError("docker not available"),绝不静默降级为本地执行。
有 docker 时也只返回占位失败,不真跑容器。
后续接线:容器挂载(把任务 worktree 以只读/受限写挂载进容器)、
网络隔离(默认无外网,仅放行模型 API 所需出口)、资源限额与
容器回收,届时再替换本占位实现。
"""
def execute(self, task) -> dict:
task_id = task.get("id") if isinstance(task, dict) else None
if task_id is None:
raise ValueError("任务缺少 id")
if shutil.which("docker") is None:
raise RuntimeError("docker not available")
return {
"executor": "docker",
"task_id": task_id,
"status": "failed",
"stdout": "docker executor not implemented: "
"container mount and network isolation pending",
"returncode": None,
}
class CloudExecutor(Executor):
"""云端执行器(占位,未接通)。
execute(task) 一律 raise RuntimeError,绝不假装已接通云端。
接通前提:真实云账号 + 预算上限配置,届时由控制面注入凭证与
限额后再替换本占位实现。
"""
def execute(self, task) -> dict:
raise RuntimeError(
"cloud executor not connected: missing cloud account "
"and budget limit")