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:
2026-02-21 00:40:29 -05:00
parent d9f4a38015
commit f7ccc153b4
3 changed files with 32 additions and 0 deletions

View File

@@ -220,6 +220,17 @@ class Scheduler:
"""List only recurring cron jobs."""
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
# -------------------------------------------------------------------

View File

@@ -147,6 +147,22 @@ class JobStore:
conn.commit()
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
def _row_to_job(row: sqlite3.Row) -> ScheduledJob:
return ScheduledJob(