mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-23 10:42:00 +00:00
fix(cron): deliver max-iteration fallback reports
This commit is contained in:
parent
3972701424
commit
ae7e857420
2 changed files with 62 additions and 2 deletions
|
|
@ -2189,13 +2189,27 @@ def run_job(job: dict) -> tuple[bool, str, str, Optional[str]]:
|
|||
# would otherwise be delivered as if it were the agent's reply and the
|
||||
# job's `last_status` set to "ok". Raise so the except handler below
|
||||
# builds the proper failure tuple. (issue #17855)
|
||||
if result.get("failed") is True or result.get("completed") is False:
|
||||
turn_exit_reason = str(result.get("turn_exit_reason") or "")
|
||||
final_response_text = (result.get("final_response") or "").strip()
|
||||
max_iteration_summary = (
|
||||
result.get("failed") is not True
|
||||
and result.get("completed") is False
|
||||
and turn_exit_reason.startswith("max_iterations_reached(")
|
||||
and bool(final_response_text)
|
||||
)
|
||||
if result.get("failed") is True or (result.get("completed") is False and not max_iteration_summary):
|
||||
_err_text = (
|
||||
result.get("error")
|
||||
or (result.get("final_response") or "").strip()
|
||||
or final_response_text
|
||||
or "agent reported failure"
|
||||
)
|
||||
raise RuntimeError(_err_text)
|
||||
if max_iteration_summary:
|
||||
logger.warning(
|
||||
"Job '%s' reached the iteration limit but produced a final fallback response; "
|
||||
"delivering the response instead of failing the cron run",
|
||||
job_name,
|
||||
)
|
||||
|
||||
final_response = result.get("final_response", "") or ""
|
||||
# Strip leaked placeholder text that upstream may inject on empty completions.
|
||||
|
|
|
|||
|
|
@ -1394,6 +1394,52 @@ class TestRunJobSessionPersistence:
|
|||
assert error is None
|
||||
assert final_response == "all good"
|
||||
|
||||
def test_run_job_delivers_max_iteration_fallback_summary(self, tmp_path):
|
||||
"""Cron should deliver a usable max-iteration fallback summary.
|
||||
|
||||
A cron run can exhaust the iteration budget, get a final text summary
|
||||
from the no-tools fallback call, and still have ``completed=False`` in
|
||||
the generic agent result. That should not make cron raise the report
|
||||
text as a RuntimeError.
|
||||
"""
|
||||
job = {
|
||||
"id": "summary-job",
|
||||
"name": "summary",
|
||||
"prompt": "finish the report",
|
||||
}
|
||||
fake_db = MagicMock()
|
||||
|
||||
with patch("cron.scheduler._hermes_home", tmp_path), \
|
||||
patch("cron.scheduler._resolve_origin", return_value=None), \
|
||||
patch("dotenv.load_dotenv"), \
|
||||
patch("hermes_state.SessionDB", return_value=fake_db), \
|
||||
patch(
|
||||
"hermes_cli.runtime_provider.resolve_runtime_provider",
|
||||
return_value={
|
||||
"api_key": "***",
|
||||
"base_url": "https://example.invalid/v1",
|
||||
"provider": "openrouter",
|
||||
"api_mode": "chat_completions",
|
||||
},
|
||||
), \
|
||||
patch("run_agent.AIAgent") as mock_agent_cls:
|
||||
mock_agent = MagicMock()
|
||||
mock_agent.run_conversation.return_value = {
|
||||
"final_response": "final fallback report",
|
||||
"completed": False,
|
||||
"failed": False,
|
||||
"turn_exit_reason": "max_iterations_reached(60/60)",
|
||||
}
|
||||
mock_agent_cls.return_value = mock_agent
|
||||
|
||||
success, output, final_response, error = run_job(job)
|
||||
|
||||
assert success is True
|
||||
assert error is None
|
||||
assert final_response == "final fallback report"
|
||||
assert "final fallback report" in output
|
||||
assert "(FAILED)" not in output
|
||||
|
||||
def test_tick_marks_empty_response_as_error(self, tmp_path):
|
||||
"""When run_job returns success=True but final_response is empty,
|
||||
tick() should mark the job as error so last_status != 'ok'.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue