HOMELAB-1548: fix(subagents): honor explicit Agent model overrides, default fleet to deepseek-v4-flash #15
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "plane/HOMELAB-1548-model-override"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixes HOMELAB-1548.
Root cause
resolveAgentInvocationConfig()resolved the spawn model asagentConfig?.model ?? params.model— the agent type's frontmatter pin beat the explicit call param. Every agent in~/.pi/agent/agents/*.mdpinsmodel: deepseek/deepseek-flash, soAgent({ model: "opencode-go/glm-5.3-flash" })(and any other override) was silently ignored and ran deepseek-flash. This is also why the 2026-09-14 fleet contract documented "model overrides are NOT honored" — it was a precedence bug, not a harness limitation.Changes
src/core/invocation-config.ts— precedence flipped:params.model ?? agentConfig.model.modelFromParamsis true whenever the caller passed a model, so unresolvable/out-of-scope overrides now hard-error instead of silently falling back to the pin.src/core/agent-runner.ts—resolveDefaultModel()fallback chain is now frontmatter → machine default (defaultModel) → parent session model; exported for tests.getDefaultModel/setDefaultModelmodule state added.src/core/settings.ts+src/suite-settings.ts— new coredefaultModelknob (subagents.json, global+project merged; empty = inherit parent). Surfaced on the unified settings page.src/core/index.ts— tool-layer resolution applies the same chain (so scope validation + UI model tag see the effective model);model:param description updated.src/swarm/tiers.ts—simple/balanced/premiumdefault tier models →deepseek/deepseek-flash, so an omittedmodel:/tier:onagent_swarmnever silently spawns the kimi fleet. Tiers remain configurable per settings.README.md— documented the resolution chain + new knob + updated tier defaults.tests/core/invocation-config.test.ts(precedence both directions, loud failures),tests/core/default-model.test.ts(fallback chain, unavailable/slashless specs, parent last resort, state trimming), tier fixture updates.Verification
npm run typecheckclean;npm test→ 50 files / 403 tests passed.-e <worktree>/pi-swarm-suite/src/index.ts):general-purpose(frontmatter pindeepseek/deepseek-flash) +model: "opencode-go/glm-5.3-flash"→ transcriptdetails.modelName: "glm-5.3-flash". Override honored (before: deepseek, modelName absent).model: "bogus/nope-123"→Model not found: "bogus/nope-123"returned, no spawn. Loud failure (before: silently ran the pin).verify-nomodelagent (no frontmatter pin) on aopencode-go/glm-5.3-flashparent, no param → randeepseek v4.1 flashviadefaultModel. Machine default engaged (before: inherited glm).Machine default is set in
~/.pi/agent/subagents.json(defaultModel: "deepseek/deepseek-flash") — out-of-repo config, applied alongside this PR.- invocation-config: explicit Agent({model}) now wins over the agent type's frontmatter pin (was agentConfig.model ?? params.model); modelFromParams is set whenever the param is passed, so bad/out-of-scope overrides hard-error instead of silently running the pin. - agent-runner: resolveDefaultModel() chain is now frontmatter → machine default (`defaultModel` in subagents.json) → parent; exported for tests. - settings/suite page: new core `defaultModel` knob (empty = inherit parent). - tiers: simple/balanced/premium defaults → deepseek/deepseek-flash so an omitted model/tier never silently spawns the kimi fleet. - tests: precedence, fallback chain, fixtures; 403 tests green. Verified live (headless pi, this tree): general-purpose (pin deepseek-flash) with model opencode-go/glm-5.3-flash ran on glm-5.3-flash; bogus model returned "Model not found" before spawning; a no-pin agent on a glm parent ran on deepseek v4.1 flash via defaultModel.