hermes: deduplicate streamed tool arguments
All checks were successful
Tests / Declarative: Post Actions passed: 251
All checks were successful
Tests / Declarative: Post Actions passed: 251
This commit is contained in:
parent
a72eb481c3
commit
277574b649
@ -25,7 +25,7 @@ spec:
|
||||
ai.bstein.dev/execution: Hermes Kanban with durable direct Codex and Claude Code CLI workers
|
||||
ai.bstein.dev/model-policy: Jetson-assisted AUTO routing, low through xhigh, cross-provider fallback
|
||||
ai.bstein.dev/placement: rpi5 preferred; Jetson deferred until state storage is available
|
||||
ai.bstein.dev/config-rev: "20260812-stream-tool-failover"
|
||||
ai.bstein.dev/config-rev: "20260812-deduplicate-tool-stream"
|
||||
vault.hashicorp.com/agent-inject: "true"
|
||||
vault.hashicorp.com/role: hermes-agent
|
||||
vault.hashicorp.com/agent-inject-secret-anthropic-token: kv/data/atlas/hermes/agent-tokens
|
||||
|
||||
@ -273,17 +273,35 @@ def _normalized_stream(body: bytes, completed: dict[str, Any]) -> bytes:
|
||||
"""Return Responses SSE with the reconstructed terminal response attached."""
|
||||
normalized: list[str] = []
|
||||
replaced_terminal = False
|
||||
skip_event_data = False
|
||||
for line in body.decode("utf-8", errors="replace").splitlines():
|
||||
if line == "event: response.function_call_arguments.done":
|
||||
# Switchyard translates both the argument deltas and this terminal
|
||||
# snapshot into Chat Completions deltas. That duplicates the JSON
|
||||
# object and Hermes mistakes the result for provider truncation.
|
||||
# The preceding deltas are complete and already validated by
|
||||
# ``_completed_response``; suppress only the redundant snapshot.
|
||||
skip_event_data = True
|
||||
continue
|
||||
if line.startswith("data:"):
|
||||
value = line[5:].strip()
|
||||
try:
|
||||
event = json.loads(value)
|
||||
except (TypeError, ValueError, json.JSONDecodeError):
|
||||
event = None
|
||||
if (
|
||||
skip_event_data
|
||||
or isinstance(event, dict)
|
||||
and event.get("type") == "response.function_call_arguments.done"
|
||||
):
|
||||
skip_event_data = False
|
||||
continue
|
||||
if isinstance(event, dict) and event.get("type") == "response.completed":
|
||||
event["response"] = completed
|
||||
line = "data: " + json.dumps(event, separators=(",", ":"))
|
||||
replaced_terminal = True
|
||||
elif line:
|
||||
skip_event_data = False
|
||||
normalized.append(line)
|
||||
if not replaced_terminal:
|
||||
raise RuntimeError("Codex stream ended without a completed event")
|
||||
|
||||
@ -684,6 +684,23 @@ def test_codex_broker_auth_and_request_contract(tmp_path: Path, monkeypatch):
|
||||
"output"
|
||||
] == [completed_item]
|
||||
assert normalized.endswith("\n\n")
|
||||
streamed_function_body = (
|
||||
"event: response.function_call_arguments.delta\n"
|
||||
'data: {"type":"response.function_call_arguments.delta",'
|
||||
'"item_id":"call_1","delta":"{\\"path\\":\\"/tmp\\"}"}\n\n'
|
||||
"event: response.function_call_arguments.done\n"
|
||||
'data: {"type":"response.function_call_arguments.done",'
|
||||
'"item_id":"call_1","arguments":"{\\"path\\":\\"/tmp\\"}"}\n\n'
|
||||
"event: response.completed\n"
|
||||
"data: "
|
||||
+ json.dumps({"type": "response.completed", "response": completed})
|
||||
+ "\n\n"
|
||||
).encode()
|
||||
normalized_function_stream = module._normalized_stream(
|
||||
streamed_function_body, completed
|
||||
).decode()
|
||||
assert "response.function_call_arguments.delta" in normalized_function_stream
|
||||
assert "response.function_call_arguments.done" not in normalized_function_stream
|
||||
with pytest.raises(RuntimeError, match="retryable incomplete response"):
|
||||
module._completed_response(
|
||||
[
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user