Skip to content

gut(providers): remove decoratively-wired Pi-era per-message model override flow (#2339)#2351

Merged
alexey-pelykh merged 1 commit intomainfrom
gut/2339-pi-model-override-flow
Apr 13, 2026
Merged

gut(providers): remove decoratively-wired Pi-era per-message model override flow (#2339)#2351
alexey-pelykh merged 1 commit intomainfrom
gut/2339-pi-model-override-flow

Conversation

@alexey-pelykh
Copy link
Copy Markdown

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: ChannelBridge selects the CLI runtime via resolveAgentRuntimeOrThrow(cfg, agentId) and ChannelMessage (the bridge's input payload) has no model field. 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.ts
  • src/channels/model-overrides.test.ts
  • src/infra/heartbeat-runner.model-override.test.ts

Schema 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 filters
  • agents.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 (resolveChannelModelOverride consumption), hasResolvedHeartbeatModelOverride / hasSessionModelOverride locals, unused resolveModelRefFromString import
  • get-reply-directives.ts: dead hasResolvedHeartbeatModelOverride type param (was declared but never read in the body)
  • heartbeat-runner.ts: heartbeatModelOverride local + conditional replyOpts construction
  • get-reply.test-mocks.ts: resolveChannelModelOverride mock

Tests updated

  • config.plugin-validation.test.ts: removed modelByChannel from a validation test case
  • plugin-auto-enable.test.ts: removed ignores channels.modelByChannel test (feature no longer exists)
  • config.legacy-config-detection.accepts-imessage-dmpolicy.test.ts: swapped heartbeat.model in a legacy-config fixture for target (the test intent is to flag top-level heartbeat, not the model subfield)
  • reply.triggers...native-stop.e2e.test.ts: removed the heartbeat-override model case; kept the stored-override (session /model) case

Docs

  • docs/gateway/configuration-reference.md: removed "Channel model overrides" section
  • docs/gateway/heartbeat.md: removed model field from config sample and field-notes list
  • src/config/legacy.rules.ts: updated error message that enumerated heartbeat subfields

Left alone (verified separate paths, per issue guidance)

  • sessionEntry.modelOverride / sessionEntry.providerOverride — session-level /model directive, unrelated to channel overrides; still live via /cron/isolated-agent/run.ts and directive-handling.fast-lane.ts
  • onModelSelected callback — fires on any model selection (including fallback); not tied to channel overrides
  • fallbackTransition state — tracks primary→fallback model transitions in agent-runner.ts; independent path

Follow-ups deferred to #2342, #2343, #2344, #2345 (ChannelBridge regressions tracked separately by #2089's audit).

Acceptance criteria

  • Decision documented (Option B — gut) with rationale
  • Files deleted / modified per gut: remove decoratively-wired Pi-era per-message model override flow #2339 scope
  • pnpm check passes (format + tsgo + lint)
  • pnpm test passes (721 files / 6323 tests)
  • Verification grep: git grep -rn \"modelByChannel\\|heartbeatModelOverride\\|resolveChannelModelOverride\" src/ — zero hits
  • Repo-wide grep (including docs) — zero hits

Test plan

  • Full pnpm check green
  • Full pnpm test green (no regressions)
  • CI zombie-import gate (validated in PR CI)
  • LIVE smoke tests for middleware/runtime (this PR touches src/auto-reply and src/infra/heartbeat-runner.ts — recommend running `LIVE=1 pnpm test:live` in the PR drive loop)

🤖 Generated with Claude Code

…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>
@alexey-pelykh alexey-pelykh merged commit 4e924b8 into main Apr 13, 2026
10 checks passed
@alexey-pelykh alexey-pelykh deleted the gut/2339-pi-model-override-flow branch April 13, 2026 12:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

gut: remove decoratively-wired Pi-era per-message model override flow

1 participant