fix(api_server): bind chat_id (raw session id) on /v1/runs
/v1/runs bound only session_key at its _bind_api_server_session call, so tools.async_delegation._current_origin_session_id() — which reads the request-scoped HERMES_SESSION_CHAT_ID — returned "" on that route and runs-originated background delegations stayed forced-sync with no wake target. Bind chat_id/session_id the same way the other agent-entry routes do via _run_agent(). Follow-up to #64998 (sweeper review F2).
This commit is contained in:
parent
2cc0ff44b6
commit
0796a981d7
|
|
@ -5101,7 +5101,17 @@ class APIServerAdapter(BasePlatformAdapter):
|
|||
# environment state.
|
||||
approval_token = set_current_session_key(approval_session_key)
|
||||
session_tokens = self._bind_api_server_session(
|
||||
# chat_id carries the raw session id (the
|
||||
# X-Hermes-Session-Id equivalent) exactly like
|
||||
# the other agent-entry routes bind it via
|
||||
# _run_agent(). Without it,
|
||||
# tools.async_delegation reads an empty
|
||||
# HERMES_SESSION_CHAT_ID on /v1/runs and
|
||||
# background delegations stay forced-sync
|
||||
# (no wake target).
|
||||
chat_id=session_id or "",
|
||||
session_key=approval_session_key,
|
||||
session_id=session_id or "",
|
||||
)
|
||||
register_gateway_notify(approval_session_key, _approval_notify)
|
||||
r = agent.run_conversation(
|
||||
|
|
|
|||
|
|
@ -145,6 +145,51 @@ class TestStartRun:
|
|||
assert status["status"] in {"queued", "running", "completed"}
|
||||
assert status["object"] == "hermes.run"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_start_binds_chat_id_for_delegation_wake_target(self, adapter):
|
||||
"""/v1/runs must bind the raw session id as the api_server chat_id
|
||||
(like every other agent-entry route does via _run_agent): the async
|
||||
delegation dispatch reads HERMES_SESSION_CHAT_ID to pick its wake
|
||||
self-post target, and an empty binding forces background delegations
|
||||
on this route back to synchronous execution."""
|
||||
app = _create_runs_app(adapter)
|
||||
captured = {}
|
||||
|
||||
async with TestClient(TestServer(app)) as cli:
|
||||
with patch.object(adapter, "_create_agent") as mock_create:
|
||||
mock_agent = MagicMock()
|
||||
|
||||
def _capture_run(user_message=None, conversation_history=None, task_id=None):
|
||||
from tools.async_delegation import _current_origin_session_id
|
||||
|
||||
captured["origin_session_id"] = _current_origin_session_id()
|
||||
return {"final_response": "done"}
|
||||
|
||||
mock_agent.run_conversation.side_effect = _capture_run
|
||||
mock_agent.session_prompt_tokens = 0
|
||||
mock_agent.session_completion_tokens = 0
|
||||
mock_agent.session_total_tokens = 0
|
||||
mock_create.return_value = mock_agent
|
||||
|
||||
resp = await cli.post(
|
||||
"/v1/runs",
|
||||
json={"input": "hello", "session_id": "runs-raw-sid"},
|
||||
)
|
||||
assert resp.status == 202
|
||||
data = await resp.json()
|
||||
run_id = data["run_id"]
|
||||
|
||||
for _ in range(40):
|
||||
status_resp = await cli.get(f"/v1/runs/{run_id}")
|
||||
status = await status_resp.json()
|
||||
if status["status"] == "completed":
|
||||
break
|
||||
await asyncio.sleep(0.05)
|
||||
|
||||
assert captured.get("origin_session_id") == "runs-raw-sid", (
|
||||
"runs route must bind chat_id so delegation dispatch sees a wake target"
|
||||
)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_start_invalid_json_returns_400(self, adapter):
|
||||
app = _create_runs_app(adapter)
|
||||
|
|
|
|||
Loading…
Reference in New Issue