fix(agent): concurrent worker survives a dict error result

_detect_tool_failure now classifies dict results as failures, so the
concurrent worker's failure log line sliced result[:200] on a dict and
raised TypeError; the worker died and the model saw "thread did not
return a result" instead of the tool's own error payload. Stringify the
preview like the sequential path does.
This commit is contained in:
teknium1
2026-09-15 15:11:32 -07:00
committed by Teknium
parent 339fa6d918
commit 1d14418ea2
2 changed files with 24 additions and 1 deletions
+1 -1
View File
@@ -1221,7 +1221,7 @@ class _ConcurrentBatch:
ref.emit_post(agent, result, duration_ms=int(duration * 1000))
is_error, _ = _detect_tool_failure(ref.name, result)
if is_error:
logger.info("tool %s failed (%.2fs): %s", ref.name, duration, result[:200])
logger.info("tool %s failed (%.2fs): %s", ref.name, duration, str(result)[:200])
else:
result_chars = len(result) if isinstance(result, str) else len(str(result))
logger.info(
+23
View File
@@ -249,3 +249,26 @@ def test_abandoned_batch_does_not_dispatch_late(monkeypatch):
assert agent._current_tool is None, (
f"_current_tool left pointing at a dead tool: {agent._current_tool!r}"
)
def test_dict_error_result_reaches_the_model_from_a_concurrent_worker(monkeypatch):
"""A tool returning a dict error payload must not kill the concurrent worker.
``_detect_tool_failure`` classifies dict results as failures; the worker's
failure log line sliced ``result[:200]`` and raised TypeError, so the model
got "thread did not return a result" instead of the tool's own error.
"""
agent = _make_agent(monkeypatch)
agent._tool_guardrails = MagicMock()
agent._tool_guardrails.before_call = lambda name, args: MagicMock(allows_execution=True)
payload = {"exit_code": 2, "output": "", "error": "boom"}
agent._invoke_tool = MagicMock(return_value=payload)
messages: list = []
agent._execute_tool_calls_concurrent(
_FakeAssistantMsg([_FakeToolCall("terminal", "tc_t")]), messages, "task"
)
(tool_msg,) = [m for m in messages if m.get("role") == "tool"]
assert "thread did not return a result" not in str(tool_msg["content"])
agent._invoke_tool.assert_called_once()