Skip to content

Conversation

@daniel-lxs
Copy link
Member

@daniel-lxs daniel-lxs commented Nov 7, 2025

Problem

Fixes #4430

When clicking Save in Settings during an active task, context condensing would trigger immediately even when the configured threshold was 100%. This happened because the extension unconditionally rebuilt the running task's API handler, causing transient changes to model metadata (contextWindow, maxTokens) which triggered the allowedTokens fast-path in context condensing logic.

Root Cause

The issue was NOT about UI component unmounting or model info flicker (PR #9101). The actual problem:

  1. Settings Save calls upsertProviderProfile or activateProviderProfile
  2. These methods unconditionally rebuilt the API handler: task.api = buildApiHandler(providerSettings)
  3. Rebuilding updates model metadata even when provider/model unchanged
  4. Context condensing has two triggers:
    • contextPercent >= threshold (user's 100% setting)
    • prevContextTokens > allowedTokens (fast-path based on contextWindow/maxTokens)
  5. Transient metadata changes triggered the fast-path, causing immediate condensing regardless of threshold

Solution

Added guards in both methods to only rebuild the API handler when provider OR model ID actually changes:

if (task && task.apiConfiguration) {
    const currentProvider = task.apiConfiguration.apiProvider
    const newProvider = providerSettings.apiProvider
    const currentModelId = getModelId(task.apiConfiguration)
    const newModelId = getModelId(providerSettings)

    if (currentProvider !== newProvider || currentModelId !== newModelId) {
        task.api = buildApiHandler(providerSettings)
    }
}

Changes

  • Added getModelId import to ClineProvider
  • Added guard in upsertProviderProfile to prevent unnecessary handler rebuilds
  • Added guard in activateProviderProfile to prevent unnecessary handler rebuilds
  • Added comprehensive test suite (9 tests, all passing) to verify behavior

Testing

Impact

This targeted fix prevents the "condense on save" behavior while preserving handler rebuilds when genuinely needed (provider or model change).


Important

Fixes unnecessary context condensing by ensuring API handler rebuilds only on provider/model changes in ClineProvider.

  • Behavior:
  • Code Changes:
    • Adds updateTaskApiHandlerIfNeeded() in ClineProvider to check for provider/model changes before rebuilding.
    • Modifies upsertProviderProfile and activateProviderProfile to use the new guard.
  • Testing:
    • Adds ClineProvider.apiHandlerRebuild.spec.ts with 9 tests to verify handler rebuild logic.
    • Tests ensure handler is rebuilt only when provider or model changes, and not when unchanged.
    • Confirms no errors occur when no task is running.

This description was created by Ellipsis for 5a2be5b. You can customize this summary. It will automatically update as commits are pushed.

…unchanged

Fixes #4430

The issue was that saving settings during an active task would unconditionally rebuild the API handler in both upsertProviderProfile and activateProviderProfile, even when the provider and model hadn't changed. This caused transient changes to model metadata (contextWindow, maxTokens) which triggered the allowedTokens fast-path in context condensing logic, causing immediate condensing regardless of the configured threshold.

Changes:
- Added guard in upsertProviderProfile to only rebuild API handler when provider OR model changes
- Added guard in activateProviderProfile to only rebuild API handler when provider OR model changes
- Added comprehensive test suite to verify handler is not rebuilt unnecessarily

This prevents the "condense on save" behavior reported in issue #4430 while still rebuilding the handler when genuinely needed (provider or model change).
@daniel-lxs daniel-lxs self-assigned this Nov 7, 2025
@hannesrudolph hannesrudolph added the Issue/PR - Triage New issue. Needs quick review to confirm validity and assign labels. label Nov 7, 2025
@daniel-lxs daniel-lxs marked this pull request as ready for review November 8, 2025 02:04
@daniel-lxs daniel-lxs requested review from cte, jr and mrubens as code owners November 8, 2025 02:04
@dosubot dosubot bot added size:XL This PR changes 500-999 lines, ignoring generated files. bug Something isn't working labels Nov 8, 2025
@roomote
Copy link
Contributor

roomote bot commented Nov 8, 2025

Rooviewer Clock   See task on Roo Cloud

Review complete. Code duplication successfully resolved with clean DRY refactoring. No new issues found.

  • Guard logic incorrectly handles undefined model IDs, causing unnecessary rebuilds when comparing undefined !== "model" evaluates to true
Previous reviews

Mention @roomote in a comment to request specific changes to this pull request or fix all unresolved issues.

- Capture original API reference before upsertProviderProfile call
- Assert against original reference instead of self-comparison
- Addresses ellipsis-dev review comment
@daniel-lxs
Copy link
Member Author

daniel-lxs commented Nov 8, 2025

Review Response

@ellipsis-dev comment: FIXED - Updated test to capture original API reference and assert against it instead of self-comparison.

@roomote comment: INCORRECT - The current logic handles all cases correctly:

Why roomote's suggestion would break the fix:

Current logic (currentModelId !== newModelId):

  • Both undefined: undefined !== undefinedfalse → No rebuild (correct)
  • Both same: "gpt-4" !== "gpt-4"false → No rebuild (correct)
  • Different: "gpt-4" !== "claude"true → Rebuild (correct)
  • User selects model: undefined !== "gpt-4"true → Rebuild (correct - NEW model selected!)
  • User clears model: "gpt-4" !== undefinedtrue → Rebuild (correct - model REMOVED!)

Roomote's suggested logic (currentModelId !== undefined && newModelId !== undefined && currentModelId !== newModelId):

  • Both undefined: Skip check → No rebuild (correct by accident)
  • Both same: "gpt-4" !== "gpt-4"false → No rebuild (correct)
  • Different: "gpt-4" !== "claude"true → Rebuild (correct)
  • User selects model: undefined !== undefined fails first check → No rebuild (BUG! Should rebuild)
  • User clears model: "gpt-4" !== undefined fails second check → No rebuild (BUG! Should rebuild)

The undefined transitions ARE valid model changes:

  • Selecting a model (undefined → "gpt-4") changes the effective model used by the task
  • Clearing a model ("gpt-4" → undefined) also changes it
  • Both require handler rebuild to reflect the new model metadata

The current implementation is correct. All tests pass including the new comprehensive test suite.

@roomote
Copy link
Contributor

roomote bot commented Nov 8, 2025

Fixaroo Clock   See task on Roo Cloud

Analysis Complete: PR Author Is Correct

After thorough analysis of the guard logic and the getModelId implementation, the PR author's response is accurate and no changes are needed.

The Guard Logic Is Correct

The current implementation:

if (currentProvider !== newProvider || currentModelId !== newModelId) {
    task.api = buildApiHandler(providerSettings)
}

Why undefined Transitions Are Valid Model Changes

The getModelId function returns string | undefined:

export const getModelId = (settings: ProviderSettings): string | undefined => {
	const modelIdKey = modelIdKeys.find((key) => settings[key])
	return modelIdKey ? settings[modelIdKey] : undefined
}

All scenarios work correctly:

  1. Both undefined: undefined !== undefinedfalse → No rebuild (correct)
  2. Both same: "gpt-4" !== "gpt-4"false → No rebuild (correct)
  3. Different models: "gpt-4" !== "claude"true → Rebuild (correct)
  4. User selects model: undefined !== "gpt-4"trueRebuild (correct!)
  5. User clears model: "gpt-4" !== undefinedtrueRebuild (correct!)

Why The Reviewer's Concern Is Unfounded

The reviewer's suggested check for undefined would break scenarios 4 and 5, where:

  • A user selects a model for the first time (undefined"gpt-4")
  • A user clears their model selection ("gpt-4"undefined)

Both are legitimate model changes that require rebuilding the API handler to reflect the new configuration.

Conclusion

The PR correctly fixes issue #4430 by preventing unnecessary API handler rebuilds when the provider and model haven't actually changed, while still rebuilding when they do change (including transitions to/from undefined). The implementation is sound and all tests pass.

No code changes required.

@daniel-lxs daniel-lxs moved this from Triage to PR [Needs Review] in Roo Code Roadmap Nov 8, 2025
@hannesrudolph hannesrudolph added PR - Needs Review and removed Issue/PR - Triage New issue. Needs quick review to confirm validity and assign labels. labels Nov 8, 2025
@dosubot dosubot bot added the lgtm This PR has been approved by a maintainer label Nov 8, 2025
@mrubens mrubens merged commit 78fc212 into main Nov 8, 2025
11 checks passed
@github-project-automation github-project-automation bot moved this from New to Done in Roo Code Roadmap Nov 8, 2025
@mrubens mrubens deleted the fix/prevent-condense-on-settings-save branch November 8, 2025 03:58
@github-project-automation github-project-automation bot moved this from PR [Needs Review] to Done in Roo Code Roadmap Nov 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working lgtm This PR has been approved by a maintainer PR - Needs Review size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

[BUG] Context condensing triggers on settings Save during active task

4 participants