gut(providers): remove decoratively-wired Pi-era per-message model override flow (#2339)#2351
Merged
alexey-pelykh merged 1 commit intomainfrom Apr 13, 2026
Merged
Conversation
…erride flow (#2339) Per-message model overrides (channel + heartbeat) were wired through the reply pipeline but had no observable effect: ChannelBridge selects the CLI runtime via `resolveAgentRuntimeOrThrow(cfg, agentId)` and ChannelMessage has no `model` field. Overrides were computed but never changed agent execution. Rationale (Option B from the issue): the CLI runtime binding is an agent-level config decision, not a channel or message decision. Per RemoteClaw's Middleware Boundary Principle — agents bring their own model selection; RemoteClaw provides channel routing and session management. Gutted: - src/channels/model-overrides.{ts,test.ts} - src/infra/heartbeat-runner.model-override.test.ts - channels.modelByChannel schema (types + zod + help + labels + validation) - agents.defaults.heartbeat.model schema field (zod + types + docs) - GetReplyOptions.heartbeatModelOverride - hasResolvedHeartbeatModelOverride threading in get-reply / directives - HeartbeatSummary.model (consumer read same gutted field) - resolveChannelModelOverride consumption block in get-reply.ts - heartbeat-override e2e test case (stored /model override case retained) - modelByChannel doc section in configuration-reference.md - heartbeat.model mention in heartbeat.md Session-level `/model` overrides (sessionEntry.modelOverride) are unrelated and remain intact. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.
Summary
Closes #2339.
Removes the Pi-era per-message model override pathway (channel overrides + heartbeat override) that was wired into the reply pipeline but had no observable effect:
ChannelBridgeselects the CLI runtime viaresolveAgentRuntimeOrThrow(cfg, agentId)andChannelMessage(the bridge's input payload) has nomodelfield. Override values were computed for UX notification / cli-session keying, but never changed agent execution.Decision: Option B (gut)
Rationale: Per RemoteClaw's Middleware Boundary Principle — agents bring their own model selection; RemoteClaw provides channel routing and session management. The CLI runtime binding is an agent-level config decision, not a channel or message decision.
Option A (repair) was rejected: redefining semantics as per-channel runtime selection would need ChannelBridge to honor the override and would reintroduce complexity that was deliberately removed in the gutting waves.
Changes
Deleted
src/channels/model-overrides.tssrc/channels/model-overrides.test.tssrc/infra/heartbeat-runner.model-override.test.tsSchema removal
channels.modelByChannel— types (types.channels.ts), zod (zod-schema.providers.ts), help/labels (schema.help.ts,schema.labels.ts), validation allowlist (validation.ts), doctor / plugin-auto-enable exclusion filtersagents.defaults.heartbeat.model— types (types.agent-defaults.ts), zod (zod-schema.agent-runtime.ts)GetReplyOptions.heartbeatModelOverride(auto-reply/types.ts)HeartbeatSummary.model(consumer read the same gutted field)Wiring removal
get-reply.ts: heartbeat override block, channel override block (resolveChannelModelOverrideconsumption),hasResolvedHeartbeatModelOverride/hasSessionModelOverridelocals, unusedresolveModelRefFromStringimportget-reply-directives.ts: deadhasResolvedHeartbeatModelOverridetype param (was declared but never read in the body)heartbeat-runner.ts:heartbeatModelOverridelocal + conditional replyOpts constructionget-reply.test-mocks.ts:resolveChannelModelOverridemockTests updated
config.plugin-validation.test.ts: removedmodelByChannelfrom a validation test caseplugin-auto-enable.test.ts: removedignores channels.modelByChanneltest (feature no longer exists)config.legacy-config-detection.accepts-imessage-dmpolicy.test.ts: swappedheartbeat.modelin a legacy-config fixture fortarget(the test intent is to flag top-levelheartbeat, not the model subfield)reply.triggers...native-stop.e2e.test.ts: removed theheartbeat-overridemodel case; kept thestored-override(session/model) caseDocs
docs/gateway/configuration-reference.md: removed "Channel model overrides" sectiondocs/gateway/heartbeat.md: removedmodelfield from config sample and field-notes listsrc/config/legacy.rules.ts: updated error message that enumerated heartbeat subfieldsLeft alone (verified separate paths, per issue guidance)
sessionEntry.modelOverride/sessionEntry.providerOverride— session-level/modeldirective, unrelated to channel overrides; still live via/cron/isolated-agent/run.tsanddirective-handling.fast-lane.tsonModelSelectedcallback — fires on any model selection (including fallback); not tied to channel overridesfallbackTransitionstate — tracks primary→fallback model transitions inagent-runner.ts; independent pathFollow-ups deferred to #2342, #2343, #2344, #2345 (ChannelBridge regressions tracked separately by #2089's audit).
Acceptance criteria
pnpm checkpasses (format + tsgo + lint)pnpm testpasses (721 files / 6323 tests)git grep -rn \"modelByChannel\\|heartbeatModelOverride\\|resolveChannelModelOverride\" src/— zero hitsTest plan
pnpm checkgreenpnpm testgreen (no regressions)src/auto-replyandsrc/infra/heartbeat-runner.ts— recommend running `LIVE=1 pnpm test:live` in the PR drive loop)🤖 Generated with Claude Code