feat(v3): T26 两级智能体(大模型规划/审查 + 本地小模型执行,D7)
- run_dual 编排:规划者两阶段 JSON(plan/review,失败回喂重试一次再降级),
redo 时裁决意见回喂执行者,交接上限 agent.max_handoffs(默认 2)
- 交接文档 agent_runs/{id}/handoff.json(智能体版交流文本:instructions/acceptance/exchanges)
- /agent 新增 executor_pool_id;规划者==执行者条目拒绝;整体 token_cap 覆盖两级调用
- ToolLoop 增 emit_final 开关(内层循环不发终态,防前端 SSE 提前收口)
- 前端:执行者选择器 + phase/message 事件渲染(阶段徽标 + 双色消息卡)
- 测试 +3(done/redo/执行者故障),全量 277 passed
- fix(tests): test_config_get_put_reset 增加设置备份/恢复隔离,防止清掉用户真实配置
This commit is contained in:
+36
-2
@@ -530,13 +530,44 @@ try:
|
||||
workspace_dir = agent_cfg.get("workspace_dir", "agent_workspace")
|
||||
|
||||
chat, model, used_pool_id = _resolve_agent_chat(pool_id)
|
||||
|
||||
# 两级模式(D7):显式指定执行者(本地小模型)时,规划=chat、执行=executor_chat
|
||||
executor_pool_id = str((req or {}).get("executor_pool_id") or "").strip()
|
||||
executor_chat = None
|
||||
executor_model = ""
|
||||
if executor_pool_id:
|
||||
entry = get_pool().get(executor_pool_id)
|
||||
if entry is None:
|
||||
raise HTTPException(status_code=400,
|
||||
detail=f"执行者条目不存在: {executor_pool_id}")
|
||||
if entry["backend"] == "mock":
|
||||
raise HTTPException(status_code=400,
|
||||
detail="mock 模型不能担任执行者,请选择 llama_server 或 openai 条目")
|
||||
from gateway.agent import OpenAICompatChat
|
||||
executor_chat = OpenAICompatChat(
|
||||
base_url=entry["base_url"] or "http://127.0.0.1:8901/v1",
|
||||
api_key=entry.get("api_key") or None,
|
||||
model=entry["model"],
|
||||
temperature=float(entry.get("temperature", 0.3)),
|
||||
max_tokens=int(entry.get("max_tokens", 4096)))
|
||||
executor_model = f"{entry['name']}({entry['model']})"
|
||||
|
||||
if executor_chat is not None and executor_pool_id == used_pool_id:
|
||||
raise HTTPException(status_code=400,
|
||||
detail="规划者与执行者是同一个模型,两级模式无意义;请更换执行者条目")
|
||||
|
||||
service = get_agent_service()
|
||||
request_id = new_request_id()
|
||||
mode = "dual" if executor_chat is not None else "single"
|
||||
info = service.register(request_id, task, model, used_pool_id,
|
||||
workspace=workspace_dir)
|
||||
workspace=workspace_dir,
|
||||
executor_model=executor_model, mode=mode)
|
||||
if info is None:
|
||||
raise HTTPException(status_code=503, detail="智能体同时运行任务已达上限")
|
||||
|
||||
s = settings_store().to_dict()
|
||||
agent_cfg = s.get("agent", {})
|
||||
|
||||
async def _run():
|
||||
try:
|
||||
await service.run(
|
||||
@@ -546,6 +577,8 @@ try:
|
||||
token_cap=int(agent_cfg.get("token_cap", 20000)),
|
||||
allow_shell=bool(agent_cfg.get("allow_shell", False)),
|
||||
shell_timeout_s=int(agent_cfg.get("shell_timeout_s", 20)),
|
||||
executor_chat=executor_chat,
|
||||
max_handoffs=int(agent_cfg.get("max_handoffs", 2)),
|
||||
)
|
||||
except Exception as exc:
|
||||
import traceback
|
||||
@@ -557,7 +590,8 @@ try:
|
||||
|
||||
info.asyncio_task = asyncio.create_task(_run())
|
||||
return {"request_id": request_id, "status": "running", "model": model,
|
||||
"workspace": workspace_dir}
|
||||
"workspace": workspace_dir, "mode": mode,
|
||||
"executor_model": executor_model}
|
||||
|
||||
@app.get("/agent/fs", tags=["agent"])
|
||||
async def agent_fs_browse(path: str = ""):
|
||||
|
||||
Reference in New Issue
Block a user