mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-10 05:10:45 +08:00
feat(scheduler): add scheduled jobs with channel-aware delivery
Introduce persisted cron/interval jobs, gateway scheduler loop, worker turns, and admin CRUD/edit UI. Route proactive reminders via the originating chat channel (WhatsApp vs WeChat), harden Weixin outbound with durable queue and PG-compatible polling, and fix chat UI to show each scheduled reminder separately. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
5336f8835f
commit
47813f6a94
45 changed files with 4956 additions and 43 deletions
|
|
@ -217,6 +217,15 @@ def _run_startup_hooks(app: FastAPI) -> None:
|
|||
_log_info(f"[startup-prebuild] scheduler_started interval_s={_prewarm_interval_seconds()}")
|
||||
except Exception as exc:
|
||||
_log_warn(f"[startup-prebuild] scheduler_start_failed: {exc}")
|
||||
try:
|
||||
from svc.persistence.assistant_store import get_assistant_store
|
||||
from runtime.scheduler.service import ensure_scheduler_started
|
||||
|
||||
store = get_assistant_store()
|
||||
sid = ensure_scheduler_started(store=store)
|
||||
_log_info(f"[scheduled-jobs] scheduler_started thread={sid}")
|
||||
except Exception as exc:
|
||||
_log_warn(f"[scheduled-jobs] scheduler_start_failed: {exc}")
|
||||
_relocate_root_scan_artifacts()
|
||||
startup_targets = _resolve_startup_workspace_dirs(cfg)
|
||||
initialize_hooks_runtime(cfg=cfg, workspace_dir=startup_targets[0][1])
|
||||
|
|
@ -302,6 +311,31 @@ def create_app() -> FastAPI:
|
|||
changed = store.ack_channel_outbound_message(message_id=msg_id, ok=ok, error=err)
|
||||
return {"ok": changed}
|
||||
|
||||
@app.get("/weixin/outbound/pending")
|
||||
def weixin_outbound_pending(account_id: str = "", limit: int = 20) -> dict[str, Any]:
|
||||
from svc.persistence.assistant_store import get_assistant_store
|
||||
|
||||
store = get_assistant_store()
|
||||
lister = getattr(store, "list_pending_weixin_outbound_messages", None)
|
||||
if not callable(lister):
|
||||
return {"ok": True, "items": []}
|
||||
items = lister(account_id=str(account_id or "").strip(), limit=limit)
|
||||
return {"ok": True, "items": items}
|
||||
|
||||
@app.post("/weixin/outbound/ack")
|
||||
def weixin_outbound_ack(payload: dict[str, Any]) -> dict[str, Any]:
|
||||
from svc.persistence.assistant_store import get_assistant_store
|
||||
|
||||
body = payload if isinstance(payload, dict) else {}
|
||||
msg_id = str(body.get("id") or "").strip()
|
||||
if not msg_id:
|
||||
return {"ok": False, "error": "missing id"}
|
||||
ok = bool(body.get("ok", True))
|
||||
err = str(body.get("error") or "").strip()
|
||||
store = get_assistant_store()
|
||||
changed = store.ack_channel_outbound_message(message_id=msg_id, ok=ok, error=err)
|
||||
return {"ok": changed}
|
||||
|
||||
@app.post("/wecom/inbound")
|
||||
async def wecom_inbound(payload: dict[str, Any]) -> dict[str, Any]:
|
||||
payload = payload if isinstance(payload, dict) else {}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue