feat(kanban): let a task pin its own thinking depth

A task could already pin a model and provider, but not how hard the worker
thinks: reasoning effort came from the assigned profile's config and nothing
per-task could reach it. Pairing a small model with high effort, or a big one
with thinking off, meant editing the worker profile itself.

Adds a tasks.reasoning_effort column (migrated, NULL = inherit the profile)
with set_reasoning_effort(), a create_task kwarg, and a --reasoning spawn flag.
Kept deliberately independent of model_override: a task may run the profile's
own model at a different depth, and clearing a model override no longer resets
the depth the operator chose. "none" is a value (thinking off), not a clear.

--reasoning is new on the CLI too — the level was only reachable through the
/reasoning slash command, so the dispatcher had no flag to pass. It overrides
agent.reasoning_effort for one run and is never persisted.
This commit is contained in:
Brooklyn Nicholson
2026-08-01 16:09:56 -05:00
parent 57b1eb8c4d
commit 0b69a6ac02
4 changed files with 143 additions and 1 deletions
+19
View File
@@ -4205,6 +4205,7 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin, CLIBillingMixin):
model: str = None,
toolsets: List[str] = None,
provider: str = None,
reasoning: str = None,
api_key: str = None,
base_url: str = None,
max_turns: int = None,
@@ -4222,6 +4223,7 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin, CLIBillingMixin):
model: Model to use (default: from env or claude-sonnet)
toolsets: List of toolsets to enable (default: all)
provider: Inference provider ("auto", "openrouter", "nous", "openai-codex", "zai", "kimi-coding", "minimax", "minimax-cn")
reasoning: Reasoning effort override for this run (none|minimal|low|medium|high|xhigh|max|ultra). Wins over config.
api_key: API key (default: from environment)
base_url: API base URL (default: OpenRouter)
max_turns: Maximum tool-calling iterations shared with subagents (default: 500)
@@ -4487,6 +4489,20 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin, CLIBillingMixin):
# shared chokepoint in hermes_constants (Closes #21256).
from hermes_constants import resolve_reasoning_config
self.reasoning_config = resolve_reasoning_config(CLI_CONFIG, self.model)
# An explicit --reasoning wins over config for this run only (never
# persisted). Kanban's dispatcher uses it to pin a task's thinking
# depth without touching the worker profile's config.yaml. An
# unparseable level is ignored with a warning rather than silently
# swapping in the default — same contract as the config path.
if reasoning is not None and str(reasoning).strip():
_cli_reasoning = _parse_reasoning_config(reasoning)
if _cli_reasoning is None:
logger.warning(
"Unknown --reasoning '%s', keeping the configured level",
reasoning,
)
else:
self.reasoning_config = _cli_reasoning
self.service_tier = _parse_service_tier_config(
CLI_CONFIG["agent"].get("service_tier", "")
)
@@ -17842,6 +17858,7 @@ def main(
skills: str | list[str] | tuple[str, ...] = None,
model: str = None,
provider: str = None,
reasoning: str = None,
api_key: str = None,
base_url: str = None,
max_turns: int = None,
@@ -17870,6 +17887,7 @@ def main(
skills: Comma-separated or repeated list of skills to preload for the session
model: Model to use (default: anthropic/claude-opus-4-20250514)
provider: Inference provider ("auto", "openrouter", "nous", "openai-codex", "zai", "kimi-coding", "minimax", "minimax-cn")
reasoning: Reasoning effort for this run (none|minimal|low|medium|high|xhigh|max|ultra). Overrides agent.reasoning_effort.
api_key: API key for authentication
base_url: Base URL for the API
max_turns: Maximum tool-calling iterations (default: 60)
@@ -17984,6 +18002,7 @@ def main(
model=model,
toolsets=toolsets_list,
provider=provider,
reasoning=reasoning,
api_key=api_key,
base_url=base_url,
max_turns=max_turns,