#23738: feat(fallback): first-class transition visibility + low-noise automated notices
docs
commands
agents
size: L
Cluster:
Model Fallbacks and Rate Limiting
## Summary
This PR adds first-class visibility when model fallback begins, plus optional low-noise notices for automated contexts.
### What changed
1. **Transition-start signal/event (`primary -> fallback`)**
- Added `onTransition` callback support to `runWithModelFallback(...)`.
- Emits new lifecycle phase: `fallback_start` when transitioning to the next model candidate (including primary -> first fallback).
- Wired into:
- `runAgentTurnWithFallback` (auto-reply runtime events)
- `agent` command execution path (lifecycle + runtime log line)
- isolated cron agent runs (lifecycle + warn log)
2. **Surfaced in runtime/status context**
- Fallback state now tracks `fallbackNoticeStartedAt` in session state.
- Status output now shows fallback duration (`since ...`) when active.
3. **Optional low-noise automated notify behavior (deduped)**
- New config flag: `agents.defaults.modelFallbackNotifyAutomated` (default: disabled).
- When enabled:
- heartbeat/automated reply flow emits a compact `Model Fallback started` notice **once per transition**
- isolated cron flow prepends/emits the same compact notice **once per transition**
- No repeated notice spam while fallback remains active.
4. **Transition + dedupe tests**
- Added tests for:
- transition callback emission in model fallback core
- cooldown-triggered transition emission
- `fallback_start` lifecycle emission
- heartbeat automated notice dedupe
- cron automated notice dedupe
- fallback start timestamp tracking/preservation
- status fallback duration rendering
5. **Docs/config references**
- Updated failover docs with `fallback_start` lifecycle semantics and automated notify behavior.
- Added config label/help/schema entries for `agents.defaults.modelFallbackNotifyAutomated`.
## Backward compatibility
- Default behavior is preserved unless `agents.defaults.modelFallbackNotifyAutomated` is explicitly enabled.
- Existing `fallback` / `fallback_cleared` behavior remains intact.
## Validation
- `pnpm exec tsc -p tsconfig.json --noEmit`
- `pnpm vitest run --config vitest.unit.config.ts src/agents/model-fallback.test.ts src/auto-reply/fallback-state.test.ts src/auto-reply/status.test.ts src/auto-reply/reply/agent-runner.runreplyagent.test.ts src/cron/isolated-agent/run.skill-filter.test.ts`
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR adds comprehensive fallback transition visibility to OpenClaw's model failover system. The implementation introduces a new `onTransition` callback mechanism in the core fallback runner that fires when switching between model candidates, emits lifecycle events (`fallback_start`, `fallback`, `fallback_cleared`) at key transition points, and tracks fallback state with timestamps in session storage.
Key additions include:
- **Transition callbacks**: `ModelFallbackTransitionHandler` type and `onTransition` parameter wired into auto-reply, CLI agent command, and isolated cron flows
- **Fallback state tracking**: New session fields (`fallbackNoticeSelectedModel`, `fallbackNoticeActiveModel`, `fallbackNoticeReason`, `fallbackNoticeStartedAt`) for deduped notice management
- **Status output enhancement**: Fallback duration display showing "since X ago" when fallback is active
- **Optional automated notices**: New `modelFallbackNotifyAutomated` config flag enabling compact one-time transition notices for heartbeat/cron contexts
- **Comprehensive test coverage**: 103 passing tests across model-fallback, fallback-state, agent-runner, status, and cron test suites
The implementation maintains backward compatibility (default behavior unchanged unless `modelFallbackNotifyAutomated` is enabled) and follows existing patterns for lifecycle event emission and state management.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with no blocking issues identified
- The implementation is well-architected with proper typing, comprehensive test coverage (103 tests passing), and maintains backward compatibility. The transition callback mechanism follows TypeScript best practices with proper async/await handling, the deduplication logic correctly prevents notification spam by tracking state transitions, and all integration points (auto-reply, CLI commands, cron) are consistently wired. The changes are thoroughly documented and align with existing codebase patterns.
- No files require special attention
<sub>Last reviewed commit: ae5e779</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#8390: feat: notify user when fallback model is used (#8182)
by Glucksberg · 2026-02-04
86.0%
#23318: feat(agents): emit model:fallback hook event for fallback visibilit...
by anillBhoi · 2026-02-22
83.8%
#19252: fix(agents): continue model fallback on failover text payloads
by mahsumaktas · 2026-02-17
81.2%
#23816: fix(agents): model fallback skipped during session overrides and pr...
by ramezgaberiel · 2026-02-22
80.6%
#22064: fix(failover): bypass models allowlist for configured fallback models
by winston-bepresent · 2026-02-20
80.0%
#20275: fix(cli): include primary model in allowlist when adding fallbacks
by MFS-code · 2026-02-18
79.8%
#13658: fix: silent model failover with fallback notification
by taw0002 · 2026-02-10
79.6%
#16289: feat: heartbeat model fallback chain support
by Unwatched2345 · 2026-02-14
78.8%
#11349: fix(agents): do not filter fallback models by models allowlist
by liuxiaopai-ai · 2026-02-07
78.6%
#23033: fix: continue to fallbacks when first fallback throws unclassified ...
by ismsaa · 2026-02-21
78.3%