Skip to content

fix(models): align GetDefaultModel's defaultOn test with AvailableModels - #18

Open
245678000000 wants to merge 1 commit into
CometixSpace:mainfrom
245678000000:fix/default-model-defaulton-semantics
Open

fix(models): align GetDefaultModel's defaultOn test with AvailableModels#18
245678000000 wants to merge 1 commit into
CometixSpace:mainfrom
245678000000:fix/default-model-defaulton-semantics

Conversation

@245678000000

@245678000000 245678000000 commented Aug 27, 2026

Copy link
Copy Markdown

Summary

The two places that read ProviderModel.defaultOn disagreed on what a missing field means:

File Expression defaultOn: undefined
handlers/models/byokModelBuilder.ts model.defaultOn ?? false off
services/core/AiService.ts (GetDefaultModel) x.model.defaultOn !== false on

So a model with no defaultOn — a hand-written providers.json, or a config predating the sidebar writing the flag — is reported to the client as off in the picker, yet GetDefaultModel would push it as the default model for Composer and Cmd+K. DEFAULT_PROVIDERS seeds no models, so every model comes from user config and can hit this.

Change

A single isModelDefaultOn() predicate next to the ProviderModel type, with all four reads routed through it. It keeps the builder's meaning (only an explicit true counts as on) because that is the one that actually shapes the AvailableModels response the picker renders.

Consequence worth calling out: when nothing is enabled, GetDefaultModel now returns {} instead of picking the first model. That is the documented "don't push, client keeps its previous selection" path already in the handler's contract — but if you'd rather have the opposite fix (undefined meaning on everywhere, changing the wire response), say so and I'll flip it.

GetDefaultModel's body is lifted into a named handleGetDefaultModel, mirroring handleAvailableModels in the same file, so the behaviour is reachable from tests. It is exported for that reason.

Test plan

New Cursor++/src/server/tests/defaultModelSelection.test.ts — the predicate, the empty-candidate case, first-enabled/first-enabled-thinking selection, and an invariant that the pushed default is never a model AvailableModels reports as off. Three of the four fail on the old predicate (verified by reverting just the filter).

  • pnpm --dir "Cursor++" run check-types
  • pnpm --dir "Cursor++" run lint
  • pnpm --dir "Cursor++" run test:server — 39 files / 371 tests passed (baseline on main is 38 / 367)

Those counts are from a machine with Cursor installed and a populated ~/.ccursor. On a clean checkout 5 of the 38 files fail for host-dependency reasons that have nothing to do with this change — 4 need @vscode/sqlite3 out of an installed Cursor, and protocol.test.ts:232 reads the real ~/.ccursor/knowledge-base.json. Detail in #20.

The two sites that read ProviderModel.defaultOn disagreed on what a
missing field means:

  byokModelBuilder.ts   defaultOn: model.defaultOn ?? false      -> off
  AiService.ts          filter(x => x.model.defaultOn !== false) -> on

So a model with no defaultOn (a hand-written providers.json, or a config
predating the sidebar writing the flag) is reported to the client as off
in the picker, yet GetDefaultModel would happily push it as the default
model for Composer and Cmd+K.

Introduce a single predicate isModelDefaultOn() next to the ProviderModel
type and route all four reads through it. It keeps the builder's meaning
(only an explicit true counts as on), which is the one that actually
shapes the AvailableModels response; GetDefaultModel now returns {} when
nothing is enabled, and per the existing contract the client keeps its
previous selection.

GetDefaultModel's body is lifted into a named handleGetDefaultModel,
mirroring handleAvailableModels in the same file, so the behaviour is
reachable from tests.

Adds defaultModelSelection.test.ts. Three of its four cases fail on the
old predicate.
Rogers-F added a commit to Rogers-F/CCursor that referenced this pull request Aug 29, 2026
- getAutoCompactThreshold 改新公式: 窗口 − min(40K, 15%×窗口)
  (签名兼容保留 maxOutputTokens 形参但不再参与计算); 逐档值
  32K→27,200 / 64K→54,400 / 96K→81,600 / 128K→108,800 /
  258.4K→219,640 / 1M→960,000 — 32K/64K 死带消除; 净增长门槛 15K 与
  熔断判定不动
- 错误驱动压缩重试: isContextLengthLimitError 白名单分类
  (context_length_exceeded / maximum context length / prompt is too
  long / input token count exceeds 等 9 模式, 普通故障不误判) →
  performInlineAutoSummarize(budgetOverride=基准预算/2^retry) aggressive
  压缩 → 重发本轮请求 (round--), ≤CONTEXT_LENGTH_RETRY_MAX=3 轮硬封顶;
  基准预算由首次压缩的 plan.diagnostics.budgetTokens 回填
  (未压缩过时按 targetFloor=25%×窗口估计)
- 观测补全 ([AUTOCOMPACT] 结构化 log, 无 metrics 依赖): 压缩间隔样本
  (事故签名 4-5 分钟/次的直接检出器)、升级链/违约事件 (阶段 3 已含)、
  keepTail 构成含占位命中 (阶段 3 已含)、首次消费损失恒 0 计数
  (阶段 3 已含)、互斥争用计数 (阶段 3 已含)
- 测试: CometixSpace#15 错误分类白名单+aggressive 预算减半单调性 / CometixSpace#18 六档逐值
  断言 (含 32K/64K 死带消除); autoSummarize 存量阈值断言更新为新公式
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.

1 participant