mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
fix: normalize repeat<=0 to None to prevent cron jobs deleting after first run (#2612)
fix: normalize repeat<=0 to None — cron jobs deleted after first run when LLM passes -1
This commit is contained in:
parent
f60ebc7bf2
commit
ca2958ff98
3 changed files with 26 additions and 2 deletions
|
|
@ -383,6 +383,10 @@ def create_job(
|
||||||
"""
|
"""
|
||||||
parsed_schedule = parse_schedule(schedule)
|
parsed_schedule = parse_schedule(schedule)
|
||||||
|
|
||||||
|
# Normalize repeat: treat 0 or negative values as None (infinite)
|
||||||
|
if repeat is not None and repeat <= 0:
|
||||||
|
repeat = None
|
||||||
|
|
||||||
# Auto-set repeat=1 for one-shot schedules if not specified
|
# Auto-set repeat=1 for one-shot schedules if not specified
|
||||||
if parsed_schedule["kind"] == "once" and repeat is None:
|
if parsed_schedule["kind"] == "once" and repeat is None:
|
||||||
repeat = 1
|
repeat = 1
|
||||||
|
|
@ -571,7 +575,7 @@ def mark_job_run(job_id: str, success: bool, error: Optional[str] = None):
|
||||||
# Check if we've hit the repeat limit
|
# Check if we've hit the repeat limit
|
||||||
times = job["repeat"].get("times")
|
times = job["repeat"].get("times")
|
||||||
completed = job["repeat"]["completed"]
|
completed = job["repeat"]["completed"]
|
||||||
if times is not None and completed >= times:
|
if times is not None and times > 0 and completed >= times:
|
||||||
# Remove the job (limit reached)
|
# Remove the job (limit reached)
|
||||||
jobs.pop(i)
|
jobs.pop(i)
|
||||||
save_jobs(jobs)
|
save_jobs(jobs)
|
||||||
|
|
|
||||||
|
|
@ -313,6 +313,24 @@ class TestMarkJobRun:
|
||||||
# Job should be removed after hitting repeat limit
|
# Job should be removed after hitting repeat limit
|
||||||
assert get_job(job["id"]) is None
|
assert get_job(job["id"]) is None
|
||||||
|
|
||||||
|
def test_repeat_negative_one_is_infinite(self, tmp_cron_dir):
|
||||||
|
# LLMs often pass repeat=-1 to mean "infinite/forever".
|
||||||
|
# The job must NOT be deleted after runs when repeat <= 0.
|
||||||
|
job = create_job(prompt="Forever", schedule="every 1h", repeat=-1)
|
||||||
|
# -1 should be normalised to None (infinite) at create time
|
||||||
|
assert job["repeat"]["times"] is None
|
||||||
|
# Running it multiple times should never delete it
|
||||||
|
for _ in range(3):
|
||||||
|
mark_job_run(job["id"], success=True)
|
||||||
|
assert get_job(job["id"]) is not None, "job was deleted after run despite infinite repeat"
|
||||||
|
|
||||||
|
def test_repeat_zero_is_infinite(self, tmp_cron_dir):
|
||||||
|
# repeat=0 should also be treated as None (infinite), not "run zero times".
|
||||||
|
job = create_job(prompt="ZeroRepeat", schedule="every 1h", repeat=0)
|
||||||
|
assert job["repeat"]["times"] is None
|
||||||
|
mark_job_run(job["id"], success=True)
|
||||||
|
assert get_job(job["id"]) is not None
|
||||||
|
|
||||||
def test_error_status(self, tmp_cron_dir):
|
def test_error_status(self, tmp_cron_dir):
|
||||||
job = create_job(prompt="Fail", schedule="every 1h")
|
job = create_job(prompt="Fail", schedule="every 1h")
|
||||||
mark_job_run(job["id"], success=False, error="timeout")
|
mark_job_run(job["id"], success=False, error="timeout")
|
||||||
|
|
|
||||||
|
|
@ -266,8 +266,10 @@ def cronjob(
|
||||||
if base_url is not None:
|
if base_url is not None:
|
||||||
updates["base_url"] = _normalize_optional_job_value(base_url, strip_trailing_slash=True)
|
updates["base_url"] = _normalize_optional_job_value(base_url, strip_trailing_slash=True)
|
||||||
if repeat is not None:
|
if repeat is not None:
|
||||||
|
# Normalize: treat 0 or negative as None (infinite)
|
||||||
|
normalized_repeat = None if repeat <= 0 else repeat
|
||||||
repeat_state = dict(job.get("repeat") or {})
|
repeat_state = dict(job.get("repeat") or {})
|
||||||
repeat_state["times"] = repeat
|
repeat_state["times"] = normalized_repeat
|
||||||
updates["repeat"] = repeat_state
|
updates["repeat"] = repeat_state
|
||||||
if schedule is not None:
|
if schedule is not None:
|
||||||
parsed_schedule = parse_schedule(schedule)
|
parsed_schedule = parse_schedule(schedule)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue