openclaw - ✅(Solved) Fix AM `modelFallbackPolicy` deprecation warning text misleads about `modelFallback` semantics [2 pull requests, 2 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#74587Fetched 2026-04-30 06:22:36
View on GitHub
Comments
2
Participants
2
Timeline
9
Reactions
2
Timeline (top)
cross-referenced ×3referenced ×3commented ×2closed ×1

When config.modelFallbackPolicy is set in the AM plugin config, the gateway logs:

active-memory: config.modelFallbackPolicy is deprecated and no longer changes runtime behavior; set config.modelFallback explicitly if you want a fallback model

The phrase "if you want a fallback model" reads naturally as runtime failover (fall back to model B when model A errors/times-out). The actual semantics in getModelRef are different: modelFallback is chain-resolution fallback — it's only consulted when no other model resolves at all.

Error Message

if (parsed) return parsed; // first non-null wins, no error-recovery modelFallback is only consulted when config.model, currentRunModel, AND configuredDefaultModel are all undefined. There is no error-recovery / retry-with-different-model path here. If the resolved model errors or times out, the embedded run surfaces the error — modelFallback is never substituted in.

Root Cause

When config.modelFallbackPolicy is set in the AM plugin config, the gateway logs:

active-memory: config.modelFallbackPolicy is deprecated and no longer changes runtime behavior; set config.modelFallback explicitly if you want a fallback model

The phrase "if you want a fallback model" reads naturally as runtime failover (fall back to model B when model A errors/times-out). The actual semantics in getModelRef are different: modelFallback is chain-resolution fallback — it's only consulted when no other model resolves at all.

Fix Action

Fixed

PR fix notes

PR #74627: active-memory: clarify modelFallback semantics in deprecation warning (#74587)

Description (problem / solution / changelog)

Summary

  • Problem: The active-memory deprecation warning printed when config.modelFallbackPolicy is set says "set config.modelFallback explicitly if you want a fallback model". That phrasing reads as runtime failover (fall back to model B when model A errors/times out), but modelFallback is actually the last-resort step in chain resolution inside getModelRef (only consulted when config.model, current run model, and configured default model all fail to resolve).
  • Why it matters: As reported in #74587, users debug sessions for hours assuming modelFallback provides runtime failover before reading source reveals the mismatch.
  • What changed: One-line text change to the deprecation warning to spell out chain-resolution semantics and add an explicit "not runtime failover" note. This is Option A from the issue.
  • What did NOT change (scope boundary): No runtime behavior, no schema, no docs. The existing docs/concepts/active-memory.md "Model fallback policy" section already documents the resolution order correctly.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #74587
  • This PR fixes a bug or regression

Root Cause (if applicable)

  • Root cause: The deprecation warning was written in terms of "fallback model" without distinguishing chain-resolution last-resort from runtime failover. The implementation in getModelRef (extensions/active-memory/index.ts:2031-2044) treats config.modelFallback as the 4th candidate in a first-non-null-wins chain, with no error-recovery substitution.
  • Missing detection / guardrail: Existing test only asserts on expect.stringContaining("config.modelFallbackPolicy is deprecated"), which does not pin the explanatory tail of the message — so the misleading phrasing was never caught by tests.
  • Contributing context: The naming modelFallback is overloaded across the broader product, and the original deprecation note inherited that overload without disambiguating.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Existing coverage already sufficient
  • Target test or file: extensions/active-memory/index.test.ts ("uses config.modelFallback when no session or agent model resolves")
  • Scenario the test should lock in: Warning is emitted when modelFallbackPolicy is set; this PR keeps the existing assertion green (it matches the unchanged prefix substring).
  • Why this is the smallest reliable guardrail: The user-visible behavior is the warning text itself; the test pins the prefix substring, leaving the explanatory tail editable without churn. Tightening the assertion to the full string would couple tests to copy and add maintenance cost without catching real regressions.
  • Existing test that already covers this: Yes (above).
  • If no new test is added, why not: Pure copy change to a single user-facing string with no behavior change. Existing assertion remains green.

Test Plan

  • pnpm test extensions/active-memory/index.test.ts — 94/94 pass
  • pnpm check:changed — clean (typecheck, oxlint, runtime sidecar guard, import-cycle guard)
  • pnpm exec oxfmt --write --threads=1 extensions/active-memory/index.ts — clean

Changed files

  • extensions/active-memory/index.ts (modified, +1/-1)

PR #74602: fix(active-memory): clarify modelFallbackPolicy deprecation warning text

Description (problem / solution / changelog)

Closes #74587. AI-assisted, fully tested.

The previous deprecation warning ("set config.modelFallback explicitly
if you want a fallback model") read naturally as runtime failover —
model A errors → switch to model B. The actual semantics in
`getModelRef` are different: `modelFallback` is the *last candidate
in the chain-resolution walk*, consulted only when `config.model`, the
current run's model, AND the agent's configured default have all
resolved to nothing. There is no error-recovery / retry-with-different-model
path.

The issue filer reports ~1 hour of debug cycles before reading source
revealed the gap; users without source access can debug for much
longer assuming runtime failover exists.

## Fix

Rewrite the warning string to:

1. State the deprecation (preserved).
2. Describe modelFallback's actual semantics — chain-resolution
   last-resort, gated on the three earlier candidates resolving to
   nothing.
3. Explicitly disclaim the wrong mental model — "it is NOT a runtime
   failover that substitutes a different model when the resolved
   model errors out" — so a quick read can't lead the operator astray.

No behavior change, only operator-facing copy.

## Tests

`extensions/active-memory/index.test.ts` extends the existing
deprecation-warning assertion to pin both:

- positive copy (`chain-resolution`, `last-resort`)
- negative disclaimer (`NOT a runtime failover`)

So a future reword that reintroduces the failover-implying language
fails the test instead of silently regressing.

`pnpm test extensions/active-memory/index.test.ts` — 94 passed.
`pnpm exec oxfmt --check` — clean. `pnpm exec oxlint` — 0 warnings,
0 errors.

## AI-assisted PR

- [x] Mark as AI-assisted (Claude). Lightly tested via targeted Vitest
  extension shard; not exercised against a live AM/Ollama rollout
  because this is a log-string update, not behavior.
- [x] Confirm I understand what the code does: yes — `getModelRef`
  walks four candidates and returns the first non-null parse;
  `modelFallback` is purely a default-when-empty selector.

Closes #74587

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • extensions/active-memory/index.test.ts (modified, +16/-0)
  • extensions/active-memory/index.ts (modified, +12/-1)
  • extensions/active-memory/openclaw.plugin.json (modified, +1/-1)

Code Example

active-memory: config.modelFallbackPolicy is deprecated and no longer changes runtime behavior; set config.modelFallback explicitly if you want a fallback model

---

function getModelRef(api, agentId, config, ctx) {
    const currentRunModel = ctx?.modelProviderId && ctx?.modelId ? `${ctx.modelProviderId}/${ctx.modelId}` : void 0;
    const configuredDefaultModel = resolveAgentEffectiveModelPrimary(api.config, agentId) ? resolveDefaultModelForAgent({ ... }) : void 0;
    const defaultProvider = configuredDefaultModel?.provider ?? "openai";
    const candidates = [
        config.model,                                                                    // 1st priority
        currentRunModel,                                                                 // 2nd priority
        configuredDefaultModel ? `${configuredDefaultModel.provider}/${configuredDefaultModel.model}` : void 0,  // 3rd priority
        config.modelFallback                                                             // 4th priority — last resort
    ];
    for (const candidate of candidates) {
        const parsed = parseModelCandidate(candidate, defaultProvider);
        if (parsed) return parsed;  // first non-null wins, no error-recovery
    }
}

---

active-memory: config.modelFallbackPolicy is deprecated and no longer changes runtime behavior;
set config.modelFallback explicitly if you want a model to use when no other model
(config.model, current run model, or configured default model) is resolved
RAW_BUFFERClick to expand / collapse

AM modelFallbackPolicy deprecation warning text misleads about modelFallback semantics

Version

OpenClaw 2026.4.26 (commit be8c246).

Plugin

active-memory (stock plugin, dist/extensions/active-memory/index.js).

Summary

When config.modelFallbackPolicy is set in the AM plugin config, the gateway logs:

active-memory: config.modelFallbackPolicy is deprecated and no longer changes runtime behavior; set config.modelFallback explicitly if you want a fallback model

The phrase "if you want a fallback model" reads naturally as runtime failover (fall back to model B when model A errors/times-out). The actual semantics in getModelRef are different: modelFallback is chain-resolution fallback — it's only consulted when no other model resolves at all.

Source-level reality

dist/extensions/active-memory/index.js — function getModelRef (line 858 in this build), candidates array (lines 865-870):

function getModelRef(api, agentId, config, ctx) {
    const currentRunModel = ctx?.modelProviderId && ctx?.modelId ? `${ctx.modelProviderId}/${ctx.modelId}` : void 0;
    const configuredDefaultModel = resolveAgentEffectiveModelPrimary(api.config, agentId) ? resolveDefaultModelForAgent({ ... }) : void 0;
    const defaultProvider = configuredDefaultModel?.provider ?? "openai";
    const candidates = [
        config.model,                                                                    // 1st priority
        currentRunModel,                                                                 // 2nd priority
        configuredDefaultModel ? `${configuredDefaultModel.provider}/${configuredDefaultModel.model}` : void 0,  // 3rd priority
        config.modelFallback                                                             // 4th priority — last resort
    ];
    for (const candidate of candidates) {
        const parsed = parseModelCandidate(candidate, defaultProvider);
        if (parsed) return parsed;  // first non-null wins, no error-recovery
    }
}

modelFallback is only consulted when config.model, currentRunModel, AND configuredDefaultModel are all undefined. There is no error-recovery / retry-with-different-model path here. If the resolved model errors or times out, the embedded run surfaces the error — modelFallback is never substituted in.

Empirical confirmation

Tested 2026-04-29 against 2026.4.26:

  • Set modelFallback: "ollama-cloud/minimax-m2.5", leave config.model unset
  • Trent's session model (gpt-5.5 via openai-codex) resolves currentRunModel cleanly
  • AM run uses gpt-5.5 (per status line activeProvider=openai-codex activeModel=gpt-5.5), times out at 15s budget
  • modelFallback was NEVER substituted in — even on timeout

Impact

Users (myself included) read the deprecation warning and assume modelFallback provides runtime failover. Sessions are debugged for hours under that assumption before reading source code reveals the mismatch. Cost: ~1 hour of debug cycles in our case before catching it; could be much worse for users without source access.

Suggested fix

One of:

Option A (cheapest): rewrite the deprecation warning to clarify chain-resolution semantics.

active-memory: config.modelFallbackPolicy is deprecated and no longer changes runtime behavior;
set config.modelFallback explicitly if you want a model to use when no other model
(config.model, current run model, or configured default model) is resolved

Option B (better): add a doc paragraph at docs/concepts/active-memory.md explicitly titled "Model resolution chain" that lays out the priority order — config.modelcurrentRunModelconfiguredDefaultModelconfig.modelFallback — and explicitly notes "modelFallback is NOT runtime failover; it is the last-resort default if no other model resolves."

Option C (best, larger change): if runtime failover is desired separately, introduce config.runtimeFailoverModel (or similar) with its own resolution path and clear naming. Then modelFallback retains its current role as resolution-chain last-resort.

We would expect Option A to be the cheapest fix and Option B to be the most useful for users.

Reporter

islandpreneur007, with diagnostic support from Trent.

extent analysis

TL;DR

The deprecation warning for modelFallbackPolicy should be rewritten to clarify that modelFallback is used as a last-resort default when no other model resolves, rather than implying runtime failover.

Guidance

  • Review the current deprecation warning and consider rewriting it to match one of the suggested options (A, B, or C) to avoid misleading users about the semantics of modelFallback.
  • Verify the change by testing the updated warning message and ensuring it accurately reflects the behavior of modelFallback.
  • Consider adding documentation to explicitly explain the model resolution chain and the role of modelFallback to prevent similar misunderstandings in the future.
  • If runtime failover is a desired feature, consider introducing a new configuration option (e.g., config.runtimeFailoverModel) to provide a clear and separate solution.

Example

No code changes are suggested at this point, but an updated deprecation warning could look like this:

active-memory: config.modelFallbackPolicy is deprecated and no longer changes runtime behavior;
set config.modelFallback explicitly if you want a model to use when no other model
(config.model, current run model, or configured default model) is resolved

Notes

The suggested fix focuses on clarifying the deprecation warning and documentation to avoid user confusion. Introducing a new configuration option for runtime failover would require additional design and implementation considerations.

Recommendation

Apply workaround: Rewrite the deprecation warning to clarify the semantics of modelFallback, as suggested in Option A, to provide a quick and inexpensive fix.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix AM `modelFallbackPolicy` deprecation warning text misleads about `modelFallback` semantics [2 pull requests, 2 comments, 2 participants]