feat: agent definition v2 (registry, persistence, developerInstructions channel)

Registry: POST /tasks accepts agent_name, loading <name>.json
from repo-root agents/ (traversal-guarded, skill-pack re-validated);
agent and agent_name together is a 400. Persistence: tasks gains
agent_name/agent_version/agent_instructions (migrate + PG schema),
returned by GET /tasks; stored prompt stays clean. Channel: local
and docker dispatch pass --developer-instructions to host.py
dispatch -> create_thread(developerInstructions=...); run/fork do
not re-send. Cloud executor has no such channel, so the worker
falls back to the v1 marked header in the in-memory dispatch
prompt only (DB prompt stays clean). Goal/coordinator tasks
still reject instructions.

Tests: test_agent_def_v2.py (7 tests) + updated v1 suite.
This commit is contained in:
host committed 2026-11-04 18:01:44 +00:00
1 parent 7bb3c37a10
commit 1672ab9ff2
8 files changed
+361 -35

No files matched your search

+21
View File
@@ -134,6 +134,8 @@ import time
import uuid
from types import SimpleNamespace
from cloud.agent_def import AgentDefinition as _AgentDefinition
from cloud.agent_def import format_instructions_header as _agent_header
from cloud.auth import AuthStore
from cloud.coordinator import build_report as _coord_build_report
from cloud.coordinator import DEFAULT_POLL_INTERVAL as _COORD_POLL_INTERVAL
@@ -412,6 +414,10 @@ def _task_from_row(row):
"coordinator_parts": _coord_parse_parts(_col("coordinator_parts")),
"parent_task_id": _col("parent_task_id"),
"coordinator_part": _col("coordinator_part"),
# agent 定义 v2:老行缺列时 None = 未用定义,不炸。
"agent_name": _col("agent_name"),
"agent_version": _col("agent_version"),
"agent_instructions": _col("agent_instructions"),
}
@@ -5864,6 +5870,21 @@ class Worker:
task_id, decision.tier, decision.source,
decision.applied))
task["model"] = decision.chosen_model or self.model
# agent 指令通道(v2):local/docker 由 sandbox 的
# --developer-instructions 派发,prompt 保持干净;通用
# cloud 执行器没有这个通道,只能在这里把 v1 的带标记
# 头拼进内存里的派发 prompt(只改本轮 task 副本,不写
# 库,库 prompt 保持干净),否则 cloud 任务会比 v1
# 倒退成指令全丢。已带头的 prompt 不重复拼。
if task.get("executor") == "cloud" \
and task.get("agent_instructions") \
and not (task.get("prompt") or "").startswith("[Agent:"):
task["prompt"] = _agent_header(
_AgentDefinition(
name=task.get("agent_name") or "agent",
version=task.get("agent_version"),
instructions=task["agent_instructions"]),
task.get("prompt") or "")
actual_model = task["model"]
# 有限重试与真实 fallback 的优先级:取消不重试;一次尝试失败
# 且可 fallback、且显式配了 fallback_models 时,优先真换模型