Skip to content

fix: preserve selected models through hot reloads and fallbacks#103510

Merged
steipete merged 3 commits into
mainfrom
codex/model-pin-root-fix
Jul 10, 2026
Merged

fix: preserve selected models through hot reloads and fallbacks#103510
steipete merged 3 commits into
mainfrom
codex/model-pin-root-fix

Conversation

@steipete

Copy link
Copy Markdown
Contributor

Closes #103324.

Supersedes #103417. This replacement retains Ayaan Zaidi's (@obviyus) turn-local fallback commit with original authorship and incorporates his root-cause investigation.

What Problem This Solves

Fixes an issue where Telegram could confirm a /model selection from hot-reloaded config, but the next turn still used the Gateway's startup snapshot. The selected model was then rejected, and fallback could permanently overwrite the user's explicit session pin.

This was observed when selecting openai/gpt-5.6-luna: /model and /status showed Luna, while the next message ran another provider and persisted that fallback over the pin.

Why This Change Was Made

Fallback candidates are now turn-local and never replace an explicit user model selection. Each Telegram authorization operation owns one live config snapshot; independently, each assembled agent turn captures once after debounce/media/text batching and carries that exact object through routing, context construction, model resolution, and dispatch. Native commands likewise use one live snapshot for auth, routing, delivery settings, and execution. Complete reply-config metadata is tracked out of band so frozen configs and identity-keyed caches remain valid.

This keeps the sound first commit from #103417 while replacing its later approaches:

  • A late global config read inside reply dispatch would create two config authorities within one turn, override explicit caller/SDK configuration, and break object-identity caches. The live snapshot belongs at the channel turn boundary instead.
  • Globally reordering expired OAuth profiles would change explicit account precedence and could silently switch identity or billing account. OAuth expiry is refreshable at use, and provider rotation can try sibling profiles without rewriting configured order.

User Impact

Telegram model selections made after a config hot reload take effect on the next assembled turn without requiring a Gateway restart. If the selected model fails, OpenClaw may use a fallback for that turn and show the existing notice, but later turns retry the user's pinned model instead of silently replacing it. Hot-reloaded Telegram authorization policy is applied consistently, and auth-profile ordering remains unchanged.

Evidence

  • Regression coverage starts the bot without Luna, hot-adds openai/gpt-5.6-luna, selects it through the Telegram model callback, and proves the next debounced turn dispatches with the exact post-batching live config while preserving the user pin.
  • Callback coverage proves a sender allowed by startup config is rejected after the live allowlist removes them.
  • Native-command and grouped-media coverage prove auth, preflight, routing, settings, and execution retain their owning snapshot.
  • Frozen-config coverage proves complete reply configs retain object identity and own keys without another global config read.
  • Fallback E2E coverage proves a failed openai/gpt-5.6-luna turn can use another provider without changing the persisted user selection.
  • Focused validation:
    • node scripts/run-vitest.mjs extensions/telegram/src/bot.test.ts extensions/telegram/src/bot-native-commands.session-meta.test.ts extensions/telegram/src/bot-native-commands.group-auth.test.ts extensions/telegram/src/bot-native-commands.test.ts extensions/telegram/src/bot.create-telegram-bot.channel-post-media.test.ts extensions/telegram/src/bot.media.stickers-and-fragments.e2e.test.ts (178 passed)
    • node scripts/run-vitest.mjs src/auto-reply/reply/get-reply.config-override.test.ts src/auto-reply/reply/get-reply.fast-path.test.ts src/auto-reply/reply/agent-runner.runreplyagent.e2e.test.ts
    • .agents/skills/autoreview/scripts/autoreview --mode local --codex-bin <Codex 0.144.1> (clean, no actionable findings)
    • git diff --check

Sanitized AWS Crabbox was unavailable because this environment had no usable AWS credentials or instance role; secretless PR CI is the authoritative remote proof.

@openclaw-barnacle openclaw-barnacle Bot added channel: telegram Channel integration: telegram agents Agent runtime and tooling size: XL maintainer Maintainer-authored PR labels Jul 10, 2026
@steipete

Copy link
Copy Markdown
Contributor Author

Land-ready proof for 3d748c828881854ec202f57c9e1c5d4bc7536187:

  • Exact-head CI completed with 67 passing checks, 0 failures, and 0 pending: https://github.com/openclaw/openclaw/actions/runs/29076181449
  • Focused Telegram regression sweep: 178 passed.
  • CI follow-up proof: 46 focused Telegram tests plus the exact extensions test typecheck passed.
  • Focused reply-config, fast-path, and fallback E2E suites passed; the earlier combined auto-reply/Telegram sweep passed 456 tests.
  • git diff --check passed.
  • Fresh autoreview found no accepted/actionable findings.
  • Repo-native review artifacts validated, and OPENCLAW_TESTBOX=1 scripts/pr prepare-run 103510 accepted the exact-head hosted evidence.

Sanitized AWS Crabbox was unavailable because this environment has no usable AWS credentials or instance role; secretless exact-head PR CI is the authoritative remote proof. This replacement preserves @obviyus's turn-local fallback commit/authorship while fixing config freshness at the Telegram operation/turn boundary.

@steipete
steipete merged commit d133f28 into main Jul 10, 2026
97 checks passed
@steipete
steipete deleted the codex/model-pin-root-fix branch July 10, 2026 07:26
@steipete

Copy link
Copy Markdown
Contributor Author

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 10, 2026
…claw#103510)

* fix(agents): keep model fallback turn-local instead of persisting over user pins

* fix(telegram): use live config snapshots per operation

Co-authored-by: Ayaan Zaidi <[email protected]>

* test(telegram): fix config snapshot type coverage

---------

Co-authored-by: Ayaan Zaidi <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling channel: telegram Channel integration: telegram maintainer Maintainer-authored PR size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Model fallback silently rewrites user session model pin; expired OAuth profile poisons availability probe

2 participants