Skip to content

fix(agent-core-v2): restore turn-start model fallback - #364

Merged
elkaix merged 1 commit into
mainfrom
fix/restore-turn-model-fallback
Oct 2, 2026
Merged

elkaix merged 1 commit into
mainfrom
fix/restore-turn-model-fallback

Conversation

@elkaix

@elkaix elkaix commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

Requirement or Bug

Resolve #351

Bug Reproduction Steps

Bind a session to a model, then delete that model (or its provider) from the config. The next turn fails with an unresolved-model error. Before #323 it switched to a ready model.

Root Cause

#323 (upstream reconcile) removed ensureResolvableModel from AgentProfileService.resolveModelContext, together with the ModelFallbackSwitched event, the model_fallback_triggered telemetry event, and the ranking policy. This PR restores them in the current llm-adapter layout. Fundamental fix.

Code Changes

  • llm-adapter/model/default-model-policy.ts: rankDefaultModelCandidates, ported unchanged from the pre-chore: upstream reconcile through reference 99eaa993b #323 kosong/model/defaultModelPolicy.ts.
  • profileService.ts: resolveModelContext(turnId) runs ensureResolvableModel at turn bind. If the bound alias does not resolve, it switches to the first ranked candidate that does resolve, then emits ModelFallbackSwitched, a model-fallback WarningIssued, and model_fallback_triggered telemetry. If no candidate resolves, nothing changes.
  • llmRequesterService.ts: passes turnId when it builds the per-turn config. This is the only caller that passes it. Compaction and credential lookups stay read-only.
  • profileOps.ts and telemetry/events.ts: event and telemetry definitions restored.
  • Tests: test/agent/profile/modelFallback.test.ts ports the five pre-chore: upstream reconcile through reference 99eaa993b #323 cases. Three of them fail without the fix. Two test DI setups get IModelService and IProviderService stubs.

Not restored: the global default-model fallback (settleDefaultModel). As the issue comment says, #323 made default_model never be rewritten, so bringing that back is a product decision.

Behavior Changes and Affected Users

Behavior Before After Who relies on the old behavior Escape hatch
Turn start with a bound model that no longer resolves Turn fails Switches to the best-ranked ready model, with a warning and an event None found. This restores the 2.0-era behavior from #299 Pick the model again with /model
New observable event turn.model_fallback.switched Not emitted Emitted on a switch Not durable, so no wire or state manifest change (regenerated, no drift) None needed

Affected module: agent-core-v2 profile. Full suites pass: agent-core-v2 6498/6498, agent-gateway 1407/1407.

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked a related issue (external PRs: issue must have a maintainer's /approve).
  • I have added tests that prove my feature works.
  • The behavior-change table above is complete, and every removed behavior or flipped default is named in the changeset and either has an escape hatch or was explicitly approved by a maintainer in this PR.
  • Ran gen-changesets skill, or this PR needs no changeset.
  • Ran gen-docs skill, or this PR needs no doc update.

@pkg-pr-new

pkg-pr-new Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
pnpm dlx https://pkg.pr.new/@pymodel/pythinker-code@2c7716d
npx https://pkg.pr.new/@pymodel/pythinker-code@2c7716d

commit: 2c7716d

When the bound model no longer resolves at turn start, switch to the
best-ranked ready model and emit ModelFallbackSwitched, a model-fallback
warning, and model_fallback_triggered telemetry. #323 dropped this.
@elkaix
elkaix force-pushed the fix/restore-turn-model-fallback branch from 74f8b0d to 2c7716d Compare October 2, 2026 23:36
@coderabbitai

coderabbitai Bot commented Oct 2, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 23 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: PyModel/pythinker-code/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: f833ceb2-3303-4a27-be76-793a5c047258
📥 Commits

Reviewing files that changed from the base of the PR and between 81f1070 and 2c7716d.

📒 Files selected for processing (9)
  • .changeset/restore-turn-model-fallback.md
  • packages/agent-core-v2/src/agent/llmRequester/llmRequesterService.ts
  • packages/agent-core-v2/src/agent/profile/profileOps.ts
  • packages/agent-core-v2/src/agent/profile/profileService.ts
  • packages/agent-core-v2/src/app/telemetry/events.ts
  • packages/agent-core-v2/src/llm-adapter/model/default-model-policy.ts
  • packages/agent-core-v2/test/agent/profile/modelFallback.test.ts
  • packages/agent-core-v2/test/session/agentLifecycle/agentLifecycle.test.ts
  • packages/agent-core-v2/test/session/subagent/subagentScopeCache.test.ts
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@elkaix
elkaix merged commit c431d50 into main Oct 2, 2026
25 checks passed
@elkaix
elkaix deleted the fix/restore-turn-model-fallback branch October 2, 2026 23:43
elkaix pushed a commit that referenced this pull request Oct 3, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @pymodel/pythinker-code@2.5.2

### Patch Changes

- [#364](#364)
[`c431d50`](c431d50)
Thanks [@elkaix](https://github.com/elkaix)! - A session whose model was
deleted or lost its provider switches to the best available model at the
next turn, with a warning, instead of failing the turn.

- [#365](#365)
[`81f1070`](81f1070)
Thanks [@elkaix](https://github.com/elkaix)! - Clients that open a
session while a tool approval is pending now show the agent's status
instead of none.
## @pymodel/pythinker-desktop@1.6.2

### Patch Changes

- [#364](#364)
[`c431d50`](c431d50)
Thanks [@elkaix](https://github.com/elkaix)! - A session whose model was
deleted or lost its provider switches to the best available model at the
next turn, with a warning, instead of failing the turn.

- [#365](#365)
[`81f1070`](81f1070)
Thanks [@elkaix](https://github.com/elkaix)! - Clients that open a
session while a tool approval is pending now show the agent's status
instead of none.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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.

Restore per-turn model fallback removed in #323 (ensureResolvableModel / ModelFallbackSwitched)

1 participant