fix(tier2): BYPASS PATCH 须带 query agent_id(修 422 missing agent_id)

上一修的 PATCH /sessions/{id} 设 BYPASS 返 422:missing query agent_id——该端点与 SSE stream
一样要 query 参数 agent_id。修:_patch 支持 params,_set_permission_bypass 把 agent_id 作 query 传。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
zizi 2026-06-24 08:55:51 +00:00
parent 9630c1ece7
commit 34b9ce3be0

View File

@ -105,17 +105,20 @@ async def _post(client: Any, base: str, path: str, json_body: dict, *, user_head
return resp.json()
async def _patch(client: Any, base: str, path: str, json_body: dict, *, user_header: str) -> dict:
async def _patch(client: Any, base: str, path: str, json_body: dict, *,
user_header: str, params: dict | None = None) -> dict:
"""打一个 PATCH 到运行中的 Agent Service(部分更新),返回 JSON;非 2xx 抛(带可追溯日志)。"""
headers = {"X-User-Id": user_header} if user_header else {}
resp = await client.patch(f"{base}{path}", json=json_body, headers=headers, timeout=30.0)
resp = await client.patch(f"{base}{path}", json=json_body, headers=headers,
params=params or {}, timeout=30.0)
if resp.status_code >= 300:
print(f"[tier2-bootstrap] PATCH {path} -> {resp.status_code}: {resp.text[:300]}", flush=True)
resp.raise_for_status()
return resp.json()
async def _set_permission_bypass(client: Any, base: str, session_id: str, *, user_header: str) -> None:
async def _set_permission_bypass(client: Any, base: str, session_id: str, agent_id: str,
*, user_header: str) -> None:
"""把会话权限设为 BYPASS(沙箱无人值守档)——服务态等价 CLI studio.py 的 _bypass_state()。
为什么必须设(2026-06-24 实证):tier2 九工具的 FunctionTool 默认 check_permissions 返回 ASK
@ -124,9 +127,13 @@ async def _set_permission_bypass(client: Any, base: str, session_id: str, *, use
but received no event」(agent/_agent.py:931)→ 服务态生成零产出。PATCH /sessions/{id} 把
AgentState.permission_context.mode 设成 "bypass"(app/_router/_session.py:334-343 的更新路径;
PermissionMode.BYPASS 值="bypass"),跳过 ASK,与 CLI 单写口径一致(均运行在受控生成沙箱)。
注:PATCH /sessions/{session_id} 与 SSE stream 同样【要 query 参数 agent_id】(app 路由约定;
2026-06-24 smoke 实证不带会 422 missing query agent_id),故必须把 agent_id 作为 query 传。
"""
await _patch(client, base, f"/sessions/{session_id}",
{"permission_mode": "bypass"}, user_header=user_header)
{"permission_mode": "bypass"}, user_header=user_header,
params={"agent_id": agent_id})
print(f"[tier2-bootstrap] 会话 {session_id} 权限已设 BYPASS(跳过工具 ASK,无人值守自治)。", flush=True)
@ -195,7 +202,7 @@ async def start_new_game(
session = await _post(http, base_url, "/sessions/", session_body, user_header=user_id)
session_id = session.get("session_id") or session.get("id")
# 设会话权限 = BYPASS:tier2 九工具默认 ASK,服务态无人确认,不设则首个工具调用即卡死(实证)。
await _set_permission_bypass(http, base_url, session_id, user_header=user_id)
await _set_permission_bypass(http, base_url, session_id, agent_id, user_header=user_id)
# ④ 发 kick 触发首轮 chat run(fire-and-forget;事件从 SSE 收)。input 为 UserMsg 形状。
chat_body = {
@ -288,7 +295,7 @@ async def iterate_existing_project(
session = await _post(http, base_url, "/sessions/", session_body, user_header=user_id)
session_id = session.get("session_id") or session.get("id")
# 设会话权限 = BYPASS:tier2 九工具默认 ASK,服务态无人确认,不设则首个工具调用即卡死(实证)。
await _set_permission_bypass(http, base_url, session_id, user_header=user_id)
await _set_permission_bypass(http, base_url, session_id, agent_id, user_header=user_id)
# 迭代指令:先 scaffold_init 起手(已存在文件不覆盖),再按 iterate_instruction 改/加,跑门到绿 finish。
text = (