feat: per-task model override for kanban workers

- Add model_override field to Task class and tasks schema
- Add migration for existing databases
- Spawn worker with -m model when model_override is set
This commit is contained in:
hongchen1993 2026-05-18 20:12:21 -07:00 committed by Teknium
parent e0309f7378
commit f01ee0b575

View file

@ -599,6 +599,7 @@ class Task:
# JSON array of skill names. None = use only the defaults; empty
# list = explicitly no extra skills.
skills: Optional[list] = None
model_override: Optional[str] = None
# Per-task override for the consecutive-failure circuit breaker.
# The value is the failure count at which the breaker trips — e.g.
# ``max_retries=1`` blocks on the first failure (zero retries),
@ -668,6 +669,7 @@ class Task:
row["current_step_key"] if "current_step_key" in keys else None
),
skills=skills_value,
model_override=row["model_override"] if "model_override" in keys and row["model_override"] else None,
max_retries=(
row["max_retries"] if "max_retries" in keys else None
),
@ -792,6 +794,10 @@ CREATE TABLE IF NOT EXISTS tasks (
-- Appended to the dispatcher's built-in `--skills kanban-worker`.
-- NULL or empty array = no extras.
skills TEXT,
-- Per-task model override. When set, the dispatcher passes -m <model>
-- to the worker, overriding the profile's default model. NULL = use
-- the profile default.
model_override TEXT,
-- Per-task override for the consecutive-failure circuit breaker.
-- The value is the failure count at which the breaker trips e.g.
-- ``max_retries=1`` blocks on the first failure. NULL (the common
@ -1077,6 +1083,9 @@ def _migrate_add_optional_columns(conn: sqlite3.Connection) -> None:
# they were getting before the column existed).
_add_column_if_missing(conn, "tasks", "max_retries", "max_retries INTEGER")
if "model_override" not in cols:
conn.execute("ALTER TABLE tasks ADD COLUMN model_override TEXT")
# task_events gained a run_id column; back-fill it as NULL for
# historical events (they predate runs and can't be attributed).
ev_cols = {row["name"] for row in conn.execute("PRAGMA table_info(task_events)")}
@ -4348,6 +4357,8 @@ def _default_spawn(
for sk in task.skills:
if sk and sk != "kanban-worker":
cmd.extend(["--skills", sk])
if task.model_override:
cmd.extend(["-m", task.model_override])
cmd.extend([
"chat",
"-q", prompt,