Skip to content

feat(config): add compactModel option to use a separate model for compaction (#1445) - #1629

Merged
kevincodex1 merged 5 commits into
Twigpine:mainfrom
adityachaudhary99:feat/compact-model-config-1445
Jun 16, 2026
Merged

kevincodex1 merged 5 commits into
Twigpine:mainfrom
adityachaudhary99:feat/compact-model-config-1445

Conversation

@adityachaudhary99

@adityachaudhary99 adityachaudhary99 commented Jun 14, 2026 •

Copy link
Copy Markdown
Contributor

Adds a compactModel config key so compaction can use a different
(e.g. cheaper or faster) model than mainLoopModel.

What changed

  • src/utils/config.ts: added compactModel?: string to GlobalConfig
    and GLOBAL_CONFIG_KEYS.
  • src/services/compact/compact.ts:
    • Read compactModel directly from getGlobalConfig() (no threading
      through ToolUseContext.options — minimal footprint).
    • Added modelChangesForCompaction guard in both compactConversation()
      and streamCompactSummary(): when compactModel is set and differs
      from mainLoopModel, bypass the forked-agent cache-sharing path
      (guaranteed miss with a different model anyway).
    • Pass compactModel (falling back to mainLoopModel when unset) to
      queryModelWithStreaming(), including the maxOutputTokensOverride
      guard.

Behaviour

  • compactModel unset → no behaviour change (existing path preserved).
  • compactModel === mainLoopModel → no behaviour change.
  • compactModel set and different → cache-sharing bypassed; streaming
    fallback runs with compactModel.

Closes #1445

Summary by CodeRabbit

  • New Features
    • Added a new Compact Model setting, including a dedicated picker submenu, to control the model used for message compaction.
  • Improvements
    • Compaction now supports an optional compact-model override and disables prompt-cache sharing when the compact model differs from the main loop model.
    • Streaming compaction now derives tool-search behavior and output token limits from the effective compact model.
  • Tests
    • Expanded compaction test coverage to validate compact-model alias resolution, cache-handling behavior, and overridden max output token limits.

…paction

When set and different from mainLoopModel, the forked-agent prompt-cache-sharing
path is bypassed (guaranteed cache miss with different models) and the streaming
fallback uses compactModel for the API call instead.

Closes Twigpine#1445
@coderabbitai

coderabbitai Bot commented Jun 14, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1676f05a-52e0-4396-9212-b08164b825dd

📥 Commits

Reviewing files that changed from the base of the PR and between bbc6aaa and 948ed92.

📒 Files selected for processing (2)
  • src/services/compact/compact.test.ts
  • src/services/compact/compact.ts
📜 Recent review details
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: typecheck
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js,jsx,py}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Keep comments useful and concise in code

Files:

  • src/services/compact/compact.ts
  • src/services/compact/compact.test.ts
**/*

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/services/compact/compact.ts
  • src/services/compact/compact.test.ts
**

⚙️ CodeRabbit configuration file

**: # Contributing to OpenClaude

Thanks for contributing.

OpenClaude is a fast-moving open-source coding-agent CLI with support for multiple providers, local backends, MCP, and a terminal-first workflow. The best contributions here are focused, well-tested, and easy to review.

Before You Start

  • Search existing issues and discussions before opening a new thread.
  • Check open pull requests for work that overlaps with your contribution. If a PR already exists that addresses the same change, open an issue or discussion first to align on direction — duplicate PRs may be closed without review.
  • Use issues for confirmed bugs and actionable feature work.
  • Use discussions for setup help, ideas, and general community conversation.
  • For larger changes, open an issue first so the scope is clear before implementation.
  • For security reports, follow SECURITY.md.

Pull Requests

Every PR needs a reason. Your PR description must include:

  • what changed and why
  • the user or developer impact
  • the exact checks you ran
  • a linked issue when one exists, using Fixes fix: skip assertMinVersion for third-party providers #123, `Closes `#123, or another clear link
  • screenshots when the PR touches UI, terminal presentation, or the VS Code extension
  • which provider path was tested when the PR changes provider behavior

The PR author is responsible for ensuring their PR is merge-ready. PRs with merge conflicts will not be reviewed or approved until the conflicts are resolved.

Issues are the recommended starting point for anything non-trivial — opening one first helps avoid wasted effort if the change is out of scope or already being worked on. Small fixes, doc corrections, and obvious improvements can stand on their own without a linked issue, as long as the PR description explains the intent.

What Gets Closed Without Review

PRs may be closed without review...

Files:

  • src/services/compact/compact.ts
  • src/services/compact/compact.test.ts
{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}

⚙️ CodeRabbit configuration file

{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}: Review tests for meaningful coverage of the changed behavior, isolation of global/env/config state, async cleanup, fake timers, provider profile leaks, and Windows-compatible assumptions. Block when risky runtime changes lack focused regression coverage or tests assert implementation details while missing the user-visible behavior.

Files:

  • src/services/compact/compact.test.ts
🔇 Additional comments (8)
src/services/compact/compact.ts (3)

463-477: LGTM!


1198-1214: LGTM!


1374-1375: LGTM!

Also applies to: 1422-1422, 1426-1429

src/services/compact/compact.test.ts (5)

204-208: LGTM!


326-342: LGTM!


382-389: LGTM!


680-719: LGTM!


721-771: LGTM!


📝 Walkthrough

Walkthrough

Adds an optional compactModel field to GlobalConfig (registered in GLOBAL_CONFIG_KEYS), exposes it via a Settings UI submenu that picks from available models, and wires it into compactConversation and streamCompactSummary. When compactModel differs from mainLoopModel, prompt-cache sharing is disabled and the streaming fallback derives maxOutputTokensOverride from compactModel.

Changes

compactModel config option and compact service wiring

Layer / File(s) Summary
GlobalConfig schema extension
src/utils/config.ts
Adds optional compactModel?: string to GlobalConfig and appends 'compactModel' to GLOBAL_CONFIG_KEYS, registering it as a valid config key.
Cache-sharing gate and model override
src/services/compact/compact.ts
Imports getGlobalConfig and parseUserSpecifiedModel, reads compactModel in both compactConversation and streamCompactSummary, computes modelChangesForCompaction, disables promptCacheSharingEnabled when models differ, and derives maxOutputTokensOverride and isToolSearchEnabled from compactModel ?? mainLoopModel in the streaming fallback.
CompactModel submenu and UI
src/components/Settings/Config.tsx
Adds CompactModel to SubMenu union and defines a managed-enum settings entry for compactModel. Submenu navigation opens a ModelPicker that updates globalConfig via saveGlobalConfig, updates in-memory state, records changes for save/close, logs tengu_compact_model_changed analytics event, and formats display value via compactModelDisplayString helper.
Test harness and verification
src/services/compact/compact.test.ts
Extends CompactMockOptions with optional overrides for getGlobalConfig, queryModelWithStreaming, and getMaxOutputTokensForModel to allow test control over compaction behavior. Adds a test suite verifying that when compactModel differs from mainLoopModel, cache-sharing is disabled and streaming compaction routes through the overridden model with expected token override.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

  • Gitlawb/openclaude#1587: Modifies the same streamCompactSummary forked-agent/prompt-cache-sharing path in compact.ts, adding scoped abort/timeout behavior adjacent to the cache-sharing gates this PR touches.

Suggested labels

enhancement

Suggested reviewers

  • kevincodex1
  • jatmn
🚥 Pre-merge checks | ✅ 5 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Risk Surface Disclosed ⚠️ Warning PR touches provider routing, startup/config-home behavior, and outbound network behavior by adding compactModel config that routes compaction to different models/providers, but provides no risk dis... PR review should document: (1) provider routing can change based on compactModel value, (2) startup behavior affected by new GlobalConfig field, (3) no config validation for invalid models may cause API errors during compaction.
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed Title accurately describes the main change—adding a compactModel config option to enable model selection for compaction operations.
Description check ✅ Passed Description covers what changed, why, and behavior breakdown; missing Testing section checkboxes and Notes section details requested by template.
Linked Issues check ✅ Passed PR fully implements issue #1445: compactModel config added to GlobalConfig, compact services read and use it, cache-sharing disabled on model mismatch, streaming compaction uses override model.
Out of Scope Changes check ✅ Passed All changes are scoped to compactModel feature: config schema, compact service logic, UI settings, and tests. No unrelated modifications detected.
No Hidden Policy Change ✅ Passed PR introduces only transparent, documented changes: adds compactModel config option with backward-compatible default (unset=existing behavior), new telemetry event follows established patterns with...

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/services/compact/compact.ts (1)

462-471: ⚠️ Potential issue | 🟡 Minor

Cache-sharing gate is correct, but test coverage for model-change scenarios is missing.

The logic correctly disables prompt-cache sharing when compactModel differs from mainLoopModel. The gate at lines 462–471 uses strict inequality (!==), so it will catch empty strings and prevent cache sharing.

However, if compactModel is set to an empty string "", the model selection at line 1413 uses compactModel ?? context.options.mainLoopModel — which would pass "" to the API (since ?? treats empty strings as non-nullish). This is low-likelihood (requires explicit claude config set compactModel ""), but the gate mitigates the cache-sharing risk; the API call risk remains.

Missing: tests covering modelChangesForCompaction when compactModel differs from mainLoopModel. The existing provider-gate tests cover Anthropic vs non-Anthropic, but not model-change scenarios.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/services/compact/compact.ts` around lines 462 - 471, Add test coverage
for the modelChangesForCompaction scenario to verify that prompt-cache sharing
is correctly disabled when compactModel differs from mainLoopModel. Create tests
that set compactModel to a different value than context.options.mainLoopModel
and assert that modelChangesForCompaction evaluates to true, which in turn
causes promptCacheSharingEnabled to be false. Reference the existing
provider-gate tests for structure and add similar test cases for model-change
scenarios to ensure the cache-sharing gate behaves correctly across different
model configurations.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/services/compact/compact.ts`:
- Around line 462-471: Add test coverage for the modelChangesForCompaction
scenario to verify that prompt-cache sharing is correctly disabled when
compactModel differs from mainLoopModel. Create tests that set compactModel to a
different value than context.options.mainLoopModel and assert that
modelChangesForCompaction evaluates to true, which in turn causes
promptCacheSharingEnabled to be false. Reference the existing provider-gate
tests for structure and add similar test cases for model-change scenarios to
ensure the cache-sharing gate behaves correctly across different model
configurations.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d72b7e1e-7465-4c52-94cb-5dcaf8e69307

📥 Commits

Reviewing files that changed from the base of the PR and between de726c4 and 56d2490.

📒 Files selected for processing (2)
  • src/services/compact/compact.ts
  • src/utils/config.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: typecheck
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js,jsx,py}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{ts,tsx,js,jsx,py}: Follow the existing code style in the touched files
Keep comments useful and concise

Files:

  • src/utils/config.ts
  • src/services/compact/compact.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Typecheck TypeScript code before submitting (use bun run typecheck)

Files:

  • src/utils/config.ts
  • src/services/compact/compact.ts
**/*

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/utils/config.ts
  • src/services/compact/compact.ts
**

⚙️ CodeRabbit configuration file

**: # Contributing to OpenClaude

Thanks for contributing.

OpenClaude is a fast-moving open-source coding-agent CLI with support for multiple providers, local backends, MCP, and a terminal-first workflow. The best contributions here are focused, well-tested, and easy to review.

Before You Start

  • Search existing issues and discussions before opening a new thread.
  • Check open pull requests for work that overlaps with your contribution. If a PR already exists that addresses the same change, open an issue or discussion first to align on direction — duplicate PRs may be closed without review.
  • Use issues for confirmed bugs and actionable feature work.
  • Use discussions for setup help, ideas, and general community conversation.
  • For larger changes, open an issue first so the scope is clear before implementation.
  • For security reports, follow SECURITY.md.

Pull Requests

Every PR needs a reason. Your PR description must include:

  • what changed and why
  • the user or developer impact
  • the exact checks you ran
  • a linked issue when one exists, using Fixes #123, `Closes `#123, or another clear link
  • screenshots when the PR touches UI, terminal presentation, or the VS Code extension
  • which provider path was tested when the PR changes provider behavior

The PR author is responsible for ensuring their PR is merge-ready. PRs with merge conflicts will not be reviewed or approved until the conflicts are resolved.

Issues are the recommended starting point for anything non-trivial — opening one first helps avoid wasted effort if the change is out of scope or already being worked on. Small fixes, doc corrections, and obvious improvements can stand on their own without a linked issue, as long as the PR description explains the intent.

What Gets Closed Without Review

PRs may be closed without review...

Files:

  • src/utils/config.ts
  • src/services/compact/compact.ts
🔇 Additional comments (5)
src/utils/config.ts (2)

673-676: LGTM!


781-781: LGTM!

src/services/compact/compact.ts (3)

44-44: LGTM!


1193-1205: Duplicate logic matches the main path.

The compactModel read and modelChangesForCompaction computation are duplicated from compactConversation(). Given that streamCompactSummary() is called independently (including from partialCompactConversation), and the logic is only 3 lines, this duplication is acceptable — extracting it would add more overhead than value.


1413-1420: Model override and max-tokens derivation are correct.

The streaming fallback correctly uses compactModel ?? mainLoopModel for both the model parameter and the getMaxOutputTokensForModel call, ensuring the output token limit matches the chosen model's constraints.

Same empty-string edge case as noted in the cache-sharing block above (low likelihood).

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 14, 2026

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found an issue that needs to be addressed before this is ready.

Findings

  • [P2] Expose and validate compactModel through the config surface
    src/utils/config.ts:676
    The PR wires compactModel into GlobalConfig and the compaction runtime, but the linked issue asks users to configure it with claude config set compactModel ... and explicitly lists the supported setting/model-validation work as part of the implementation. In this patch, compactModel only appears in config.ts and compact.ts; the /config settings list still jumps from autoCompactEnabled to maxMessagesCompactionThreshold, and there is no supported-setting/model validation entry for this key. That leaves the feature effectively unavailable through the advertised user-facing config path, while manual config edits can still pass invalid values such as an empty string into the compaction API call. Please add the missing config UI/command surface and validate or normalize the model value before using it for compaction.

  • [P2] Complete CodeRabbit's request for compactModel coverage
    src/services/compact/compact.ts:462
    CodeRabbit's review item asks for coverage of the modelChangesForCompaction path, and the current patch still has no test that sets compactModel to a model different from mainLoopModel and verifies that the forked-agent cache-sharing path is skipped while the streaming fallback uses the override model. The existing compact tests only cover provider compatibility, so a future edit could easily re-enable cache sharing for a mismatched model or forget to pass the override into queryModelWithStreaming without any regression failing. Please complete that review request with focused coverage for the different-model case.

… test coverage

Addresses review feedback on Twigpine#1629:
- Surface compactModel as a managedEnum setting in the /config screen,
  following the teammateDefaultModel pattern (submenu + ModelPicker).
- Add a compact.test.ts case covering the compactModel !== mainLoopModel
  path: cache-sharing is skipped and the streaming compaction fallback
  routes model/maxOutputTokensOverride to compactModel.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/Settings/Config.tsx`:
- Around line 1616-1634: Add a check before performing the config update
operations to ensure the compact model is actually changing. Before the line
that sets isDirty.current to true, compare the incoming model_2 value with the
current compactModel value from getGlobalConfig(). If they are already equal
(accounting for the null/undefined case where an unset compactModel and model_2
=== null are equivalent), skip the entire block that includes isDirty.current =
true, saveGlobalConfig, setGlobalConfig, and setChanges. This prevents marking
the dialog as dirty and recording unnecessary changes when the user selects an
option that doesn't actually change the current state.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 112e8154-7f90-42c0-a2b7-d41c41ffba3b

📥 Commits

Reviewing files that changed from the base of the PR and between 56d2490 and d741990.

📒 Files selected for processing (2)
  • src/components/Settings/Config.tsx
  • src/services/compact/compact.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx,js,jsx,py}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.{ts,tsx,js,jsx,py}: Follow the existing code style in the touched files
Keep comments useful and concise

Files:

  • src/services/compact/compact.test.ts
  • src/components/Settings/Config.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Typecheck TypeScript code before submitting (use bun run typecheck)

Files:

  • src/services/compact/compact.test.ts
  • src/components/Settings/Config.tsx
**/*

⚙️ CodeRabbit configuration file

**/*: Apply the OpenClaude maintainer review rubric from AGENTS.md. Review the current diff, not stale discussion context. Separate real blockers from suggestions. Do not request changes for vague style churn. Treat approval as merge-ready from CodeRabbit's side, pending required human review and GitHub Checks. If checks are failing or unavailable, say so clearly instead of implying the PR is fully ready.

Files:

  • src/services/compact/compact.test.ts
  • src/components/Settings/Config.tsx
{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}

⚙️ CodeRabbit configuration file

{src/**/*.test.ts,src/**/*.test.tsx,tests/**,scripts/**/*.test.ts,vscode-extension/**/*.test.js}: Review tests for meaningful coverage of the changed behavior, isolation of global/env/config state, async cleanup, fake timers, provider profile leaks, and Windows-compatible assumptions. Block when risky runtime changes lack focused regression coverage or tests assert implementation details while missing the user-visible behavior.

Files:

  • src/services/compact/compact.test.ts
**

⚙️ CodeRabbit configuration file

**: # Contributing to OpenClaude

Thanks for contributing.

OpenClaude is a fast-moving open-source coding-agent CLI with support for multiple providers, local backends, MCP, and a terminal-first workflow. The best contributions here are focused, well-tested, and easy to review.

Before You Start

  • Search existing issues and discussions before opening a new thread.
  • Check open pull requests for work that overlaps with your contribution. If a PR already exists that addresses the same change, open an issue or discussion first to align on direction — duplicate PRs may be closed without review.
  • Use issues for confirmed bugs and actionable feature work.
  • Use discussions for setup help, ideas, and general community conversation.
  • For larger changes, open an issue first so the scope is clear before implementation.
  • For security reports, follow SECURITY.md.

Pull Requests

Every PR needs a reason. Your PR description must include:

  • what changed and why
  • the user or developer impact
  • the exact checks you ran
  • a linked issue when one exists, using Fixes #123, `Closes `#123, or another clear link
  • screenshots when the PR touches UI, terminal presentation, or the VS Code extension
  • which provider path was tested when the PR changes provider behavior

The PR author is responsible for ensuring their PR is merge-ready. PRs with merge conflicts will not be reviewed or approved until the conflicts are resolved.

Issues are the recommended starting point for anything non-trivial — opening one first helps avoid wasted effort if the change is out of scope or already being worked on. Small fixes, doc corrections, and obvious improvements can stand on their own without a linked issue, as long as the PR description explains the intent.

What Gets Closed Without Review

PRs may be closed without review...

Files:

  • src/services/compact/compact.test.ts
  • src/components/Settings/Config.tsx
🔇 Additional comments (1)
src/services/compact/compact.test.ts (1)

203-208: LGTM!

Also applies to: 327-342, 386-388, 679-727

Comment thread src/components/Settings/Config.tsx

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update. I rechecked the current head and found issues that still need to be addressed.

Findings

  • [P2] Check tool-search support against the compact model
    src/services/compact/compact.ts:1365
    The streaming compaction path now sends queryModelWithStreaming() with model: compactModel ?? context.options.mainLoopModel, but the tool-search capability check just above it still calls isToolSearchEnabled() with context.options.mainLoopModel. That means a user can configure a compact model whose tool-search/tool-call surface differs from the main model, yet the compaction request will include tools chosen for the wrong model. In the bad direction this can attach unsupported tool-search tooling to the compact model request; in the other direction it can unnecessarily drop tool-search support even though the compact model supports it. Please run the tool-search eligibility check against the actual model used for compaction, and add a focused regression test for compactModel !== mainLoopModel.

  • [P3] Complete CodeRabbit's request to skip no-op compact model selections
    src/components/Settings/Config.tsx:1616
    CodeRabbit's current review asks for the CompactModel picker to skip the update path when the selected value is already the current value, including the unset/null case. The current handler still closes the submenu and then unconditionally marks the settings dirty, calls saveGlobalConfig, records setChanges, and emits tengu_compact_model_changed. Re-selecting the current compact model therefore produces a false pending settings change and a misleading analytics event. Please mirror the no-op guard used by the teammate default model path before setting isDirty.current.

Addresses round-2 review feedback on Twigpine#1629:
- compact.ts: pass compactModel ?? mainLoopModel to isToolSearchEnabled so
  the tool-search capability check matches the model actually used for
  streaming compaction (not always mainLoopModel when a compact model is set)
- Config.tsx: mirror the teammateDefaultModel no-op guard — return early
  when compactModel is unset and the picker confirms null (no-op selection)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@adityachaudhary99
adityachaudhary99 requested a review from jatmn June 15, 2026 15:45

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update. I rechecked the current head and found one issue that still needs to be addressed.

Findings

  • [P3] Complete CodeRabbit's request to skip no-op compact model selections
    src/components/Settings/Config.tsx:1616
    CodeRabbit's review item asked the CompactModel picker to skip the update path when the selected value is already the current value, including the unset/default case. The current guard only handles compactModel === undefined && model_2 === null; if a user opens the picker while compactModel is already set to a model and confirms that same model, the handler still marks the dialog dirty, calls saveGlobalConfig, records a pending change, and emits tengu_compact_model_changed. Please complete that review request by comparing the normalized current value (globalConfig.compactModel ?? null) to model_2 before setting isDirty.current.

Compare globalConfig.compactModel ?? null against the picker's
selection so re-confirming the current value (including explicit
"Default"/null when a model was previously set) is treated as a
no-op instead of marking settings dirty.
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 15, 2026

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update. I rechecked the current head and found one issue that still needs to be addressed.

Findings

  • [P2] Resolve compactModel aliases before compaction
    src/services/compact/compact.ts:1413
    The new CompactModel picker reuses ModelPicker, whose first-party options return alias values like sonnet, opus, and sonnet[1m]; the handler stores that value directly in globalConfig.compactModel. The compaction path then uses that raw value for isToolSearchEnabled, getMaxOutputTokensForModel, and queryModelWithStreaming, and the API normalizer only strips [1m] rather than expanding aliases. So a normal user selection such as Sonnet can make the next compaction send model: "sonnet" instead of the resolved model ID, and the current regression test misses this because it uses a full model ID. Please normalize the stored compact model with the same parseUserSpecifiedModel path used by the main model before comparing or sending it, and add coverage for an alias value from the picker/config path.

ModelPicker stores alias strings (e.g. 'sonnet') directly in
globalConfig.compactModel. Compact reads that value and must call
parseUserSpecifiedModel() to expand it to the canonical model ID
before comparing against mainLoopModel or sending to the API.

Two read-sites in compactConversation and streamCompactSummary are
both fixed. Test updated so the 'skips cache-sharing' case uses the
resolved model ID (legacy claude-opus-4-1 remaps to current default)
and a new test verifies alias expansion end-to-end.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@jatmn jatmn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update. I rechecked the current head and do not see any remaining actionable issues from my side.

@kevincodex1 LGTM

@kevincodex1 kevincodex1 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@kevincodex1
kevincodex1 merged commit 0c45e16 into Twigpine:main Jun 16, 2026
4 checks passed
hotmanxp added a commit to hotmanxp/openclaude that referenced this pull request Jun 16, 2026
Cherry-picked from upstream 0c45e16. Adds:
- compactModel? field on GlobalConfig (defaults to mainLoopModel)
- CompactModel submenu in /config with ModelPicker
- resolveCompactModel helper respecting model API config gates
- parseUserSpecifiedModel integration for mainLoopModel resolution

OC-specific changes:
- config.ts: kept OC's logoColor/maxMessagesCompactionThreshold alongside UP's compactModel
- compact.test.ts: skipped GitHub Native Anthropic mode test (legacy provider per AGENTS.md)

Includes 2 new tests for compactModel override behavior.
hotmanxp added a commit to hotmanxp/openclaude that referenced this pull request Jun 16, 2026
Goal: bring `bun run typecheck` to 0 errors on main-opencc. Five files
touched, no behavior changes:

- config.ts: cherry-pick da7bc4a (Twigpine#1629) referenced
  MaxMessagesCompactionThreshold without importing the type. Add the
  type, threshold constant tuple, and normalize helper from PR Twigpine#1605.
- Config.tsx: drop dead `&& pendingScope` clause at line 1666;
  showSubmenu === 'ExternalIncludes' guard already gates the dialog.
- initReplBridge.ts: cast msg.message.content at line 293 — UserMessage
  stores response shape (ContentBlock[]) but getContentText expects
  request shape (ContentBlockParam[]); cast via Parameters<>[0].
- compact.test.ts: helpers must include top-level `content` per Message
  interface; rewrite mock to handle optional `msg.message?.content`.
- sessionStorage.test.ts: 5 tests reference upstream-only goalStates
  (loadTranscriptFile) and `goal` arg (restoreSessionMetadata) — OC
  uses appState.goalSentinel instead. Convert to test.skip + no-op
  placeholder per AGENTS.md skip-legacy-test pattern.

Build + impacted test suites verified green.
@adityachaudhary99
adityachaudhary99 deleted the feat/compact-model-config-1445 branch August 21, 2026 16:57
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.

feat: add compactModel config option to use a different model for compaction

3 participants