From 8b2f3968dcdd2346851d5f8d20f97cb4f5789aea Mon Sep 17 00:00:00 2001 From: openqj Date: Tue, 27 Oct 2026 01:44:53 +0800 Subject: [PATCH] feat: per-task model/effort/approval + relay models endpoint (#59) Co-authored-by: host --- cloud/README.md | 3 +- cloud/console.html | 49 ++++++++ cloud/db.py | 3 + cloud/relay.py | 77 ++++++++++++ cloud/sandbox.py | 62 ++++++++-- cloud/server.py | 57 ++++++++- cloud/tests/test_relay.py | 81 +++++++++++++ cloud/tests/test_task_options.py | 196 +++++++++++++++++++++++++++++++ cloud/worker.py | 9 +- 9 files changed, 521 insertions(+), 16 deletions(-) create mode 100644 cloud/relay.py create mode 100644 cloud/tests/test_relay.py create mode 100644 cloud/tests/test_task_options.py diff --git a/cloud/README.md b/cloud/README.md index 294ff55..e3461bb 100644 --- a/cloud/README.md +++ b/cloud/README.md @@ -366,8 +366,9 @@ psycopg,写明“需安装 psycopg”),绝不静默回落到 SQLite, | `GET /health` | 无需认证 | `200 {"ok": true, "service": "cloud-control-plane"}` | | `POST /projects` | 认证即可 | body `{name, id?}`;无 id 则生成 uuid;调用者记为 owner(调 `AuthStore.create_project`,同时写 projects 表并记审计 `create_project`);返回 `201` + 项目 | | `GET /projects` | 认证即可 | 只返回调用者是成员的项目:`{"projects": [...]}` | -| `POST /tasks` | `create_task` | body `{project_id, prompt, depends_on?, priority?, idempotency_key?, executor?, goal?, verify_command?, goal_max_rounds?}`;无权限 `403`;同 `project_id + idempotency_key` 已存在则返回已有任务(`200`,不建重复);否则建 `queued` 任务并记审计 `create_task`,返回 `201`;`verify_command` 非空即 goal 模式(见下文“goal 模式”),`goal_max_rounds` 缺省 3、须 ≥1 | +| `POST /tasks` | `create_task` | body `{project_id, prompt, depends_on?, priority?, idempotency_key?, executor?, goal?, verify_command?, goal_max_rounds?, model?, effort?, approval?}`;无权限 `403`;同 `project_id + idempotency_key` 已存在则返回已有任务(`200`,不建重复);否则建 `queued` 任务并记审计 `create_task`,返回 `201`;`verify_command` 非空即 goal 模式(见下文“goal 模式”),`goal_max_rounds` 缺省 3、须 ≥1;`model` 不做白名单(中转目录会变,console 下拉只是建议值),`effort` 只能是 `low/medium/high/xhigh/max`,`approval` 只能是 `ask/auto/full`,三者缺省均为 NULL(= 跟随 worker 配置默认值,行为与过去一致) | | `GET /tasks?project_id=...` | 该项目 `read` | 返回该项目任务列表:`{"tasks": [...]}`;无权限 `403` | +| `GET /relay/models` | 任意已认证用户 | 中转站可用模型列表:服务端凭环境变量 `XCM_API_KEY` 现取 `XCM_RELAY_BASE_URL`(缺省 `https://xcmapi.org/v1`)的 `/v1/models`,只返回模型 id(1 小时缓存),key 绝不进响应;中转挂了或未配 key 时 `502`,不编造列表;console 的模型下拉用它,取不到时回退手动输入 | | `GET /tasks/{id}` | 该任务所属项目 `read` | 无权限 `403`;不存在 `404` | | `POST /tasks/{id}/cancel` | 该项目 `create_task` | `queued` / `running` 改为 `interrupted` 并记审计 `cancel_task`;已是终态(completed / failed / interrupted / merged / merge-failed)返回 `400`;不存在 `404` | | `POST /tasks/{id}/merge` | 该项目 `approve_merge`(maintainer 以上) | 只同步状态,不执行合并:仅 `completed` 可改为 `merged` 并记审计 `merge_task`,其它状态(含已 merged 的重复调用)返回 `409`;不存在 `404`,越权 `403`,无 key `401` | diff --git a/cloud/console.html b/cloud/console.html index eccd679..c863f22 100644 --- a/cloud/console.html +++ b/cloud/console.html @@ -86,6 +86,26 @@ +
+ + + + +