[OMEGA-313] feat: scheduled agent tasks (omegaclaw-cron) - #276
[OMEGA-313] feat: scheduled agent tasks (omegaclaw-cron)#276amiroussama wants to merge 2 commits into
Conversation
… + webhooks Adds a scheduler for time-based agent tasks: cron / interval / one-shot jobs and webhook subscriptions, persisted in a SQLite jobs DB, with HMAC-verified webhook delivery and the `omegaclaw-cron` CLI to add/list/remove/run jobs. Job runs are recorded via the session store for auditability. `is_safe_skill_name` is inlined (validates job/subscription ids used as filesystem path segments) so the scheduler carries no dependency on the skills subsystem. Depends on singnet#274 (session_store) — included in this branch and drops out on rebase once it merges. Pure-Python, stdlib sqlite3/hmac. Autotests/test_scheduler.py (host-runnable) + run_mandatory. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
982b656 to
d45af28
Compare
paul-v-snet
left a comment
There was a problem hiding this comment.
It looks like this does not actually work.
Similarly to PR #274, the implemented module looks isolated within itself, and I don’t see a single entry point for either the agent or the user.
The CLI tool allows creating a job, but this does not initiate its automatic execution (via tick/run_due or anything else). So it looks like a job manager has been implemented, but not an operator for those jobs. What I mean is that I don’t see any mechanisms that would actually operate them - timers, counters, or anything else. This would be fine if there were some component that periodically called tick or run_due on its own, but nothing does so: the agent - there are no connections to it in the form of the necessary skills or shell instructions, the main loop - no changes were made to it, the user - as far as I can see, cmd_tick is not connected to any loop anywhere in the project, so the only way to trigger a check is to manually execute this command inside the agent container, which does not look like the intended usage scenario.
Even if someone were to call cmd_tick at the required interval, the result would not reach the agent proactively. delivery_fn defaults to None, in which case delivery is simply skipped silently. For alert_fn, there is a stub that calls print() to the stdout of the process that invoked tick, but this does not solve the problem either.
Similarly, regarding runners, only _default_runner is implemented, which just echoes the prompt and does nothing else.
So, in the end, we have a mechanism for creating and scheduling jobs, but no way to actually operate them, automatically trigger their execution, or automatically receive their results (via a callback or alert). This makes it unclear what the intended role of this component is and what it can actually do in its current implementation.
Additionally, during job execution (_execute_one), a working directory is created (which is not used afterwards and is not managed from anywhere), but there is no check that this directory is accessible for reading/writing according to the profile/policy.
Moreover, os.makedirs() is called outside the try/except block that wraps the rest of the job execution. An unhandled exception at this step would bring down the entire run_due(), including other jobs that were supposed to run during the same tick.
And since the CLI create command does not allow specifying --workdir at all, a new temporary directory is created via tempfile.mkdtemp on every execution and is never removed - meaning this also results in an unbounded growth of the number of directories on disk over time.
Could you please provide clarification on all of these points?
Thank you.
…mp-dir leak Addresses PR singnet#276 review (paul-v-snet): the module scheduled jobs but nothing operated them, and per-run setup could abort a whole tick. - run_forever() + `omegaclaw-cron daemon`: the operator that loops run_due() so due jobs actually fire on their own (bounded by --max-ticks; injectable sleep_fn for deterministic tests). - Durable default delivery/alert sinks (memory/cron_outbox.jsonl) so a run's output/failure is captured instead of silently dropped when no hook is wired. Real channel push remains the documented extension seam. - _execute_one: workdir resolution + os.makedirs + runner now run inside one try/finally, so a bad job fails ONLY itself and can't abort the run_due tick. - Ephemeral temp workdirs are removed after each run (no unbounded /tmp growth); an explicit --workdir is validated against the io-policy read_write roots. - CLI: `create --workdir/--delivery`, new `daemon` subcommand, `tick` wires the default sinks. - Tests: +5 (failure isolation, temp-dir cleanup, workdir policy, daemon fires a due job, outbox delivery). 21/21 pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@paul-v-snet thanks for the careful review — you're right on every point, and the core one is fair: this shipped the job store + scheduling primitives but nothing that actually operates them. Pushed a fix (b06ba43) addressing all of it: The missing operator. Added Results reaching somewhere. The Temp-dir leak. An ephemeral temp workdir is now removed after each run (no more unbounded Tests: +5 covering failure isolation, temp-dir cleanup, workdir policy (in/out/undeterminable), the daemon firing a due job, and outbox delivery — 21/21 pass ( Let me know if the runner-seam scoping works for you or if you'd rather see a minimal real runner in this PR too. |
Description
Fixes #275. Adds a scheduler for time-based agent tasks.
src/scheduler.py— cron / interval / one-shot jobs and webhook subscriptions, persisted in a SQLite jobs DB, with HMAC-verified webhook delivery. Job runs are recorded via the session store; stored text is scrubbed via the shared redactor.is_safe_skill_nameis inlined (validates job/subscription ids that become filesystem path segments) so the scheduler carries no dependency on the skills subsystem.scripts/omegaclaw-cron— CLI to add / list / remove / run jobs.Depends on #266 (redaction) and #274 (session_store) — both files are included in this branch and drop out on rebase as those PRs merge.
How Has This Been Tested?
Autotests/test_scheduler.py(pure-Python, stdlibsqlite3/hmac, host-runnable), registered inrun_mandatory— cron/interval/one-shot scheduling + next-run computation, job add/list/remove/run, webhook HMAC verification (valid/invalid signatures), the transient-webhook-id-never-deletes-a-durable-job regression, and id path-safety. Run:cd Autotests && python3 test_scheduler.py→ 16/16 pass.Checklist