Conversation
…e_task Cherry-picks PR NousResearch#41865 (michaelversluis) to fix the bug where the `model` field on `delegate_task` was silently dropped. Changes: - tools/delegate_tool.py: - Add `model: Optional[str] = None` to `delegate_task` signature. - Per-task `model` (in `tasks[]`) beats top-level `model`, which beats config-resolved `delegation.model`. Whitespace-only strings are treated as omitted so they don't clobber a real value. - Expose `model` in DELEGATE_TASK_SCHEMA at top level AND per-task. - run_agent.py: - Forward `model` from function_call args to `delegate_task`. - tests/tools/test_delegate.py: - 5 regression tests covering schema exposure, top-level forwarding, per-task precedence, config-fallback, and the whitespace guard. Refs: NousResearch#41814, NousResearch#41865
The dispatcher has been honouring tasks.model_override since f01ee0b (May 2026, hongchen1993) — when the column is set, it appends '-m <model>' to the spawned hermes worker. The column is also surfaced in 'hermes kanban show' (79f6654). But the WRITE side was never added: there was no way to set model_override through the public API. This commit closes that gap so callers can route individual tasks to a specific model without spinning up a new profile. - kb.create_task() gains model_override: Optional[str] (with empty-string → None normalisation, matching the forgiving pattern used by --max-retries etc.). - 'hermes kanban create --model M' exposes it on the CLI; the value flows into create_task. - SwarmWorkerSpec gains model: Optional[str] so per-worker overrides are first-class on the swarm surface too. - 'hermes kanban swarm --worker profile:title@kimi-k2.7-code' parses the @model tail. - _task_to_dict now echoes model_override in 'hermes kanban create --json' and 'hermes kanban show --json' so the override is visible without reading SQLite directly. Verified by C:\Users\andre\kpi_test_kanban_per_task_model.py (KPI-K, 6/6 PASS). The pre-existing delegate_task patch (ec6c2bb0c) and its KPI test are unaffected. Builds on: f01ee0b feat: per-task model override for kanban workers 79f6654 feat(kanban): surface per-task model_override in show + tool output
Wires the validated 4-profile orchestration pattern (coder/reviewer/
researcher/analyst) into the kanban dispatcher so any new multi-role
job can reuse it. Two new modules + one new CLI subcommand:
- hermes_cli/spawn_worker.py
Public build_spawn_cmd(profile, prompt, *, model=None, skills=None)
returns the canonical argv list. The dispatcher's _default_spawn
now calls this helper, so a future change to the spawn shape lands
in one place.
- hermes_cli/kanban_pipeline.py
Preset-based pipeline helper. create_pipeline(conn, goal, preset,
overrides) creates 1 planning root (auto-completed to act as the
shared blackboard) and 4 child cards in parallel, each with the
role's validated model_override + skills. 4-profile preset is
the only one today, but the registry is open for 2/3/6-profile
additions without code changes to the helper.
- hermes_cli/kanban.py
Adds 'hermes kanban pipeline <goal> [--preset 4-profile]
[--coder-model ... --reviewer-model ... --researcher-model ...
--analyst-model ...] [--json]' subcommand.
Validated by kpi_test_pipeline.py (7 KPIs: --help, create+assignee+
model, link+status, spawn helper import+shape, max_concurrent
regression, existing-tasks regression, preset auto-fill).
Closes kanban task t_9283c577.
…rike
User observed 4 blocked tasks under the gateway dashboard with
'last_failure_error=pid X not alive' — operator-actionable? No.
The dispatcher just knew the worker PID was gone; the actual cause
(HTTP 429 from Ollama Cloud, HTTP 401, context overflow, etc) was
buried in <board>/logs/<task>.log.
Two fixes in this commit:
1) K1 — last_failure_error now carries the HTTP error class.
New _classify_worker_error(log_path) helper reads the tail
of the worker's log (last 16 KiB, cheap) and extracts one of:
- 'rate_limited' (HTTP 429 / quota / throttling)
- 'auth_failed' (HTTP 401/403 / bad credentials)
- 'context_overflow' (HTTP 400/413 / token limit)
- 'model_unavailable' (HTTP 404/410 / model not found)
- 'unknown' (no log, empty log, no recognizable pattern)
The dispatcher now writes the prefixed message as
last_failure_error so the dashboard reads e.g.
rate_limited: HTTP 429: Error code: 429 - {'error': 'extra
usage auto reload monthly max reached...'} instead of the
useless 'pid 12345 not alive'. The full log is still under
<board>/logs/<task>.log for the operator who needs more.
2) K2 — consistent 2-strike policy for ALL crash types.
Removed the 1-strike shortcuts that used to block protocol
violations and systemic (3+ same-fingerprint) crashes on the
FIRST occurrence. Now every crash type takes the same path
through _record_task_failure with failure_limit=None,
which falls through to DEFAULT_FAILURE_LIMIT=2. The first
crash is forgiven (status=ready, counter=1); the second
trips the breaker. Per-task max_retries override still
wins (e.g. hermes kanban create --max-retries 1 blocks on
first failure — that path is preserved).
Side-effect fixes from the same pass:
- The 62c85118d refactor left a dangling reference to
worker_toolsets in the dispatcher (the var was removed when
the spawn was factored into spawn_worker.build_spawn_cmd).
Re-added the local resolution so dispatch works.
- spawn_worker.build_spawn_cmd was silently dropping
'kanban-worker' from the user's skills list, with no
replacement downstream. Removed the filter; the dispatcher's
'auto-inject kanban-worker if not in user skills' logic is now
the single source of truth.
- kanban-worker is now inserted as the FIRST --skills
flag (before any user-supplied per-task skills), matching the
test expectation 'kanban-worker first (built-in)'.
Tests:
- tests/hermes_cli/test_kanban_db.py::test_detect_crashed_workers_systemic_failure_fast_block
updated to verify the new 2-strike policy (4 tasks with the
same crash each go to ready, counter=1, NOT blocked).
- tests/hermes_cli/test_kanban_core_functionality.py::test_detect_crashed_workers_protocol_violation_auto_blocks
updated to verify protocol violations now also follow
2-strike (ready, counter=1) instead of auto-blocking.
New KPI test:
- C:\Users\andre\kpi_test_kanban_failure_handling.py
9 in-process + 2 regression checks (KPI-K, KPI-P).
All 11 PASS. Tests the new policy on synthetic tasks and
verifies the HTTP-class extraction on 4 different log shapes
(429, 401, 400-context, missing/empty log).
Regression: all 3 KPI suites green (KPI-F 11/11, KPI-K 6/6,
KPI-P 7/7). 417 of 430 hermes_cli kanban tests pass; the 13
failing are all pre-existing Windows pid-bookkeeping flakes
(pid reaping, hermes path shim, zombie cleanup, profile
enumeration) that were failing before this commit.
Builds on: 62c85118d kanban: add 4-profile pipeline + public spawn helper
af06a7f5a feat(kanban): expose per-task model_override on the write side
ec6c2bb0c fix(delegate): honor per-task and top-level model override on delegate_task
Collaborator
|
We do not want this |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
feat(delegate+kanban): per-task model_override end-to-end
Closes the v0.16.0 gap where per-task
modelondelegate_taskwas silentlydropped (subagents always inherited the parent's model) and where kanban's
tasks.model_overridecolumn existed in the schema but was unreachable fromthe public write API.
What this PR does
tools/delegate_tool.py— accept and propagate per-task and top-levelmodelon every leaf / orchestrator child (the symptom in issue Feature: Per-task model override for delegate_task #41814).hermes_cli/kanban_db.py—create_task()now acceptsmodel_override;dispatcher passes
-m <model>to the spawned worker when the column isset; schema migration already present for older DBs.
hermes_cli/kanban.py— publicspawn_workerhelper extracted for the4-profile orchestration pipeline.
last_failure_errorviakb._classify_worker_error()(HTTP 429 / 401 / 400 / 413 / 404 / 410 →
rate_limited/auth_failed/context_overflow/model_unavailable); consistent 2-strike ruleapplied uniformly across the failure matrix.
Why now
Local testing on v0.16.0 confirmed that all four
delegate_taskcall sitesignore
model, forcing every subagent to use the parent's model. Thekanban-side
model_overridecolumn was a read-only dead end. This PR makesboth paths work end-to-end and makes the dispatcher error readable in one
glance.
How it was validated
kpi_test_per_task_model.pyandkpi_test_per_task_model_live.py— verifythe patched
delegate_taskpropagatesmodelto the child subprocess.kpi_test_kanban_failure_handling.py— 11/11 pass, exercises_classify_worker_error()against the full HTTP-error matrix.kpi_test_scenario_dashboard.py— 7-subagent / 4-model dashboard DAG(minimax-m3 / kimi-k2.7-code / glm-5.1 / deepseek-v4) on Ollama Cloud.
Open questions / follow-ups
{"provider": ..., "model": ...}) for routingacross Anthropic / Ollama Cloud in a single task — out of scope here;
see upstream issue Feature: Per-task model override for delegate_task #41814 / PR feat(delegation): add per-task model override for delegate_task #41826 for the feature-shape discussion.
max_retriesoverride, theTaskdataclass already supports it.Commits
Test plan for reviewers
python C:\Users\andre\kpi_test_per_task_model_live.py— exit 0.python C:\Users\andre\kpi_test_kanban_failure_handling.py— 11/11 PASS.python C:\Users\andre\kpi_test_scenario_dashboard.py— 4-model DAG runs.