Summary
When heartbeat.model (or compaction.model) is configured to use a different model than the session primary, the new live session model switch detection overrides it back to the primary model before the API call is even made. This regression was introduced between the image published around March 28-29 and the 2026.3.28 tagged release.
Config
{
"agents": {
"defaults": {
"model": {
"primary": "litellm-claude/anthropic-claude-sonnet-4-6"
},
"heartbeat": {
"every": "45m",
"target": "last",
"lightContext": true,
"model": "litellm-claude/anthropic-claude-haiku-4-5"
},
"compaction": {
"mode": "safeguard",
"model": "litellm-claude/anthropic-claude-haiku-4-5"
}
}
}
}
Expected behavior
Heartbeat and compaction runs should use the configured model override (Haiku) even when the active session is on a different model (Sonnet).
Actual behavior
The embedded runner detects a model mismatch between the heartbeat model (Haiku) and the persisted session model (Sonnet), throws a LiveSessionModelSwitchError before making the API call, which propagates to runWithModelFallback. The fallback system classifies this as reason=unknown and falls back to the primary model (Sonnet).
Logs
[agent/embedded] live session model switch detected before attempt for <session-id>: litellm-claude/anthropic-claude-haiku-4-5 -> litellm-claude/anthropic-claude-sonnet-4-6
[model-fallback/decision] model fallback decision: decision=candidate_failed requested=litellm-claude/anthropic-claude-haiku-4-5 candidate=litellm-claude/anthropic-claude-haiku-4-5 reason=unknown next=litellm-claude/anthropic-claude-sonnet-4-6
[model-fallback/decision] model fallback decision: decision=candidate_succeeded requested=litellm-claude/anthropic-claude-haiku-4-5 candidate=litellm-claude/anthropic-claude-sonnet-4-6 reason=unknown next=none
Root cause (from source analysis)
In src/agents/pi-embedded-runner/run.ts, the resolvePersistedLiveSelection() function resolves the session's default model (Sonnet) via resolveDefaultModelForAgent(). When shouldTrackPersistedLiveSelection is true and the heartbeat's model differs from the persisted session model, a LiveSessionModelSwitchError is thrown at line ~465.
The model-fallback system (src/agents/model-fallback.ts) catches this error but cannot classify it (it's not an HTTP error), so it reports reason=unknown and moves to the next candidate — which is always the config primary (Sonnet), auto-added by resolveFallbackCandidates().
Impact
- Heartbeat and compaction always run on the expensive primary model regardless of config
isolatedSession: true on heartbeat does not work around this on 2026.3.28
- Affects all agents using a different model for heartbeat/compaction than the session primary
Workaround
Pin to a version prior to 2026.3.28.
Environment
- Running on AWS ECS Fargate (headless containers)
- LiteLLM proxy for model routing
- Multiple agents affected (not agent-specific)
Summary
When
heartbeat.model(orcompaction.model) is configured to use a different model than the session primary, the new live session model switch detection overrides it back to the primary model before the API call is even made. This regression was introduced between the image published around March 28-29 and the2026.3.28tagged release.Config
{ "agents": { "defaults": { "model": { "primary": "litellm-claude/anthropic-claude-sonnet-4-6" }, "heartbeat": { "every": "45m", "target": "last", "lightContext": true, "model": "litellm-claude/anthropic-claude-haiku-4-5" }, "compaction": { "mode": "safeguard", "model": "litellm-claude/anthropic-claude-haiku-4-5" } } } }Expected behavior
Heartbeat and compaction runs should use the configured model override (Haiku) even when the active session is on a different model (Sonnet).
Actual behavior
The embedded runner detects a model mismatch between the heartbeat model (Haiku) and the persisted session model (Sonnet), throws a
LiveSessionModelSwitchErrorbefore making the API call, which propagates torunWithModelFallback. The fallback system classifies this asreason=unknownand falls back to the primary model (Sonnet).Logs
Root cause (from source analysis)
In
src/agents/pi-embedded-runner/run.ts, theresolvePersistedLiveSelection()function resolves the session's default model (Sonnet) viaresolveDefaultModelForAgent(). WhenshouldTrackPersistedLiveSelectionis true and the heartbeat's model differs from the persisted session model, aLiveSessionModelSwitchErroris thrown at line ~465.The model-fallback system (
src/agents/model-fallback.ts) catches this error but cannot classify it (it's not an HTTP error), so it reportsreason=unknownand moves to the next candidate — which is always the config primary (Sonnet), auto-added byresolveFallbackCandidates().Impact
isolatedSession: trueon heartbeat does not work around this on2026.3.28Workaround
Pin to a version prior to
2026.3.28.Environment