feat: openclaw-style secrets (env.vars + \) and per-task model routing
- Replace python-dotenv with config.json env.vars block + \ substitution - Add models section for per-task model routing (heartbeat, subagent, default) - Heartbeat/subagent tasks can use different models/providers than main chat - Remove python-dotenv from dependencies - Update all docs to reflect new config approach - Reorganize docs into project/ and research/ subdirectories
This commit is contained in:
@@ -62,6 +62,11 @@ class HeartbeatRunner:
|
|||||||
if not self._config.enabled:
|
if not self._config.enabled:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
# Clear previous heartbeat jobs to avoid duplicates on restart
|
||||||
|
removed = self._scheduler.remove_by_channel_type("heartbeat")
|
||||||
|
if removed:
|
||||||
|
logger.info(f"Heartbeat: cleared {removed} stale job(s) from previous run")
|
||||||
|
|
||||||
self._ensure_heartbeat_file()
|
self._ensure_heartbeat_file()
|
||||||
tasks = self._parse_heartbeat_md()
|
tasks = self._parse_heartbeat_md()
|
||||||
|
|
||||||
|
|||||||
@@ -220,6 +220,17 @@ class Scheduler:
|
|||||||
"""List only recurring cron jobs."""
|
"""List only recurring cron jobs."""
|
||||||
return self._store.list_recurring()
|
return self._store.list_recurring()
|
||||||
|
|
||||||
|
def remove_by_channel_type(self, channel_type: str) -> int:
|
||||||
|
"""Remove all jobs with the given channel_type. Returns count removed."""
|
||||||
|
ids = self._store.remove_by_channel_type(channel_type)
|
||||||
|
for job_id in ids:
|
||||||
|
for prefix in ("once-", "cron-"):
|
||||||
|
try:
|
||||||
|
self._scheduler.remove_job(f"{prefix}{job_id}")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return len(ids)
|
||||||
|
|
||||||
# -------------------------------------------------------------------
|
# -------------------------------------------------------------------
|
||||||
# Internal
|
# Internal
|
||||||
# -------------------------------------------------------------------
|
# -------------------------------------------------------------------
|
||||||
|
|||||||
@@ -147,6 +147,22 @@ class JobStore:
|
|||||||
conn.commit()
|
conn.commit()
|
||||||
return cursor.rowcount
|
return cursor.rowcount
|
||||||
|
|
||||||
|
def remove_by_channel_type(self, channel_type: str) -> list[str]:
|
||||||
|
"""Remove all jobs with the given channel_type. Returns removed IDs."""
|
||||||
|
with self._conn() as conn:
|
||||||
|
rows = conn.execute(
|
||||||
|
"SELECT id FROM jobs WHERE channel_type = ?", (channel_type,)
|
||||||
|
).fetchall()
|
||||||
|
ids = [row["id"] for row in rows]
|
||||||
|
if ids:
|
||||||
|
conn.execute(
|
||||||
|
"DELETE FROM jobs WHERE channel_type = ?", (channel_type,)
|
||||||
|
)
|
||||||
|
conn.commit()
|
||||||
|
if ids:
|
||||||
|
logger.info(f"Removed {len(ids)} jobs with channel_type={channel_type}")
|
||||||
|
return ids
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _row_to_job(row: sqlite3.Row) -> ScheduledJob:
|
def _row_to_job(row: sqlite3.Row) -> ScheduledJob:
|
||||||
return ScheduledJob(
|
return ScheduledJob(
|
||||||
|
|||||||
Reference in New Issue
Block a user