hermes: sanitize classifier tool history

This commit is contained in:
jenkins 2026-08-15 13:35:31 -03:00
parent 7dbde8e85d
commit c7dc81c0c3
2 changed files with 40 additions and 13 deletions

View File

@ -79,18 +79,20 @@ def _compact_message(message: dict[str, Any], limit: int) -> dict[str, Any]:
result = copy.deepcopy(message) result = copy.deepcopy(message)
if "content" in result: if "content" in result:
result["content"] = _compact_content(result["content"], limit) result["content"] = _compact_content(result["content"], limit)
tool_calls = result.get("tool_calls") # The local judge only classifies the current boundary. OpenAI-compatible
if isinstance(tool_calls, list): # Ollama validates assistant tool-call JSON and tool/result pairing before
kept: list[dict[str, Any]] = [] # inference, so a bounded or selectively retained transcript can become an
for call in tool_calls[-4:]: # invalid conversation even though its text is sufficient for routing.
if not isinstance(call, dict): # Preserve tool evidence as plain user text and remove protocol metadata.
continue had_tool_calls = bool(result.pop("tool_calls", None))
item = copy.deepcopy(call) result.pop("tool_call_id", None)
function = item.get("function") result.pop("name", None)
if isinstance(function, dict) and isinstance(function.get("arguments"), str): if result.get("role") == "tool":
function["arguments"] = _bounded_text(function["arguments"], 600) result["role"] = "user"
kept.append(item) content = result.get("content")
result["tool_calls"] = kept result["content"] = f"[tool evidence]\n{content or ''}"
elif had_tool_calls and not result.get("content"):
result["content"] = "[assistant requested an external tool]"
return result return result
@ -153,6 +155,8 @@ def compact_payload(payload: dict[str, Any]) -> dict[str, Any]:
# The judge never needs tools or binary inputs. Switchyard supplies a # The judge never needs tools or binary inputs. Switchyard supplies a
# response schema separately, and that contract must remain untouched. # response schema separately, and that contract must remain untouched.
result.pop("tools", None) result.pop("tools", None)
result.pop("tool_choice", None)
result.pop("parallel_tool_calls", None)
return result return result

View File

@ -1229,10 +1229,24 @@ def test_classifier_broker_bounds_history_without_losing_routing_intent(monkeypa
"role": "user", "role": "user",
"content": "Build and verify the Cassandra release safely.", "content": "Build and verify the Cassandra release safely.",
}, },
{"role": "assistant", "content": "working"}, {
"role": "assistant",
"content": None,
"tool_calls": [
{
"id": "call_large",
"type": "function",
"function": {
"name": "large_tool",
"arguments": '{"command":"' + ("x" * 5000) + '"}',
},
}
],
},
{ {
"role": "tool", "role": "tool",
"content": "unbounded test output " * 10000, "content": "unbounded test output " * 10000,
"tool_call_id": "call_large",
}, },
{ {
"role": "user", "role": "user",
@ -1243,6 +1257,8 @@ def test_classifier_broker_bounds_history_without_losing_routing_intent(monkeypa
}, },
], ],
"tools": [{"type": "function", "function": {"name": "large_tool"}}], "tools": [{"type": "function", "function": {"name": "large_tool"}}],
"tool_choice": "auto",
"parallel_tool_calls": True,
"response_format": {"type": "json_object"}, "response_format": {"type": "json_object"},
} }
@ -1252,6 +1268,13 @@ def test_classifier_broker_bounds_history_without_losing_routing_intent(monkeypa
assert compacted["model"] == payload["model"] assert compacted["model"] == payload["model"]
assert compacted["response_format"] == payload["response_format"] assert compacted["response_format"] == payload["response_format"]
assert "tools" not in compacted assert "tools" not in compacted
assert "tool_choice" not in compacted
assert "parallel_tool_calls" not in compacted
assert all(message.get("role") != "tool" for message in compacted["messages"])
assert all("tool_call_id" not in message for message in compacted["messages"])
assert all("tool_calls" not in message for message in compacted["messages"])
assert "[tool evidence]" in encoded
assert "[assistant requested an external tool]" in encoded
assert "Build and verify the Cassandra release safely." in encoded assert "Build and verify the Cassandra release safely." in encoded
assert "Turn this cat into a cute clown." in encoded assert "Turn this cat into a cute clown." in encoded
assert "image attachment available to the selected worker" in encoded assert "image attachment available to the selected worker" in encoded