fix(catalog): restore thinking shape and context window for unidentified gateway rows - #1041
Merged
vastsa merged 3 commits intoSep 25, 2026
Merged
Conversation
Since 41d15d5 a custom Anthropic Messages gateway (vendorKey custom, unknown base URL) no longer resolves a models.dev record for a Claude id that several publishers list, because the lookup refuses to pick one of them without a provider identity. The row then falls back to the generic model shape with no reasoning options, so the adaptive-thinking derivation from vastsa#949 cannot fire and Opus 5.5 turns fail again with "requires adaptive thinking" (400). Which thinking shape a Claude id accepts is a property of the model, stated by Anthropic's own record, not of the deployment. When the lookup misses on an Anthropic Messages row, take only reasoning_options and the derived thinkingLevelMap from Anthropic's record for exactly the same id. Limits and modalities stay generic, so the ambiguity rule from 41d15d5 still holds; aliases, renamed ids, other wire APIs and non-Claude ids served over the Anthropic protocol are unchanged. catalogModelConfigFor centralizes the repeated "catalog record or generic shape" choice for the session and subagent launch paths.
A binding seeded from models.dev stores its window with contextWindowSource "catalog" so a later catalog correction can replace it. Since 41d15d5 a custom gateway row (for example an Anthropic or DeepSeek id several publishers list) no longer resolves a record, and the lookup falls back to the generic model shape. resolveBindingContextWindow treated that generic 128k as a published correction and replaced the saved 1M snapshot, so automatic compaction started at ~86k tokens (about 9% of the window Settings still shows). A generic baseline is the fallback for a missing record, not a published limit. Ignore it as a correction so the stored catalog snapshot stays in force; resolved models.dev records keep replacing catalog-sourced windows exactly as before.
Contributor
Author
|
真实环境补充验证(提交 2:上下文窗口)
期间出现一次 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
问题
v0.15.7 之后,自定义中转服务(
vendorKey: custom、base URL 不在 models.dev 中,例如 sub2api)出现两个回归:claude-opus-5-5 requires adaptive thinking; omit thinking or use thinking.type=adaptive and output_config.effort(fix(agent-runtime): send adaptive thinking to effort-only Claude models #949 修过的问题复发)。根因
41d15d5b3(fix(catalog): resolve gateway model metadata from other publishers)增加了"无供应商身份 + 多家发布同一 ID → 不借用"的规则。自定义中转没有身份,claude-opus-5-5在快照中有 17 家发布方、deepseek-v4-flash也有多家,因此findModel返回undefined,回退到genericModelConfig(128k、无reasoning_options)。这条规则本身合理,但下游有两处把"查不到"当成了"已发布":reasoning_options推导forceAdaptiveThinking;通用形状没有reasoning_options,于是退回thinking.type=enabled+budget_tokens。resolveBindingContextWindow对contextWindowSource: "catalog"的绑定以"已发布值"为准,而通用形状的 128k 被当成已发布修正,覆盖了保存的 1M 快照。窗口 128k、输出预留 32k → hardLimit 96k → 自动压缩阈值 86,400,与会话记录吻合。改动(两个独立提交)
1.
fix(catalog): keep Anthropic thinking shape for unidentified gatewaysModelsDevCatalog.anthropicThinkingFor(modelId):只查 Anthropic 官方记录中完全相同的 ID,返回其reasoning_options与派生的thinkingLevelMap。catalogModelConfigFor(catalog, {vendorKey, baseUrl, apiStyle, modelId}):集中原先分散在各处的"目录记录或通用形状"逻辑;查不到且协议为anthropic_messages时,在通用形状上只补这两个字段。session-launch.ts三处、sidecar.ts一处)改用该函数;session-launch不再需要的modelsDevModelFor依赖一并移除。边界:
41d15d5b3的歧义规则保持不变。off: null,不会发送 Opus 5.5 拒绝的thinking: {type:"disabled"}。2.
fix(shared): keep catalog context snapshots when the lookup missesresolveBindingContextWindow在基线source === "generic"时不把其窗口视为已发布值,保存的catalog快照继续生效;真正解析到的 models.dev 记录仍会替换catalog来源的窗口,user来源规则不变。该函数也被host-runtime的 headless 启动路径使用,一并受益。Spec:
11-provider-model-system(中英)、12-provider-config-schema(中英)、13-model-catalog-and-selection§9.1 已更新。Refs #990(自定义 Anthropic 服务无法发送 adaptive 思考;本 PR 覆盖与官方 ID 完全一致的 Claude 模型,不包含手动开关)。
测试
apps/desktop/test/models-dev-catalog.test.mjs新增 3 条:自定义 Anthropic 网关 + 精确 Claude ID 获得 Anthropic 思考选项且限制保持通用;其他协议 / 非 Claude ID / 改名 ID 不受影响;已解析记录优先。packages/shared/src/model-catalog.test.ts新增 2 条:通用回退不覆盖catalog快照(修复前失败);已发布记录仍会替换catalog来源窗口。thinking-ui.test.mjs的源码断言从modelConfigFromModelsDev改为catalogModelConfigFor(后者命中时返回前者结果,意图不变);两个 launch 测试移除已删除依赖的 stub。验证
models-dev-catalog41/41;shared1030/1030node --test:与未改动基线逐条对比无新增失败(本机既有失败为 macOS 签名/公证、进程组、Windows 路径等;两条 inflight-checkpoint / MCP 计时用例偶发,单跑通过)host-runtimevitest:唯一失败launch-resolver的scratchDir断言为 Windows 路径分隔符问题(期望/data/scratch/s1,实际\data\scratch\s1),与本改动无关tsc --noEmit:desktop、agent-runtime、host-runtime 通过;biome lint、docs/check-locales(81 对)、docs/check-docs通过check-architecture:失败项为 main 上已有的apps/desktop/src/features/mid-autumn-egg/scene.ts(990 LOC 未入 allowlist),非本 PR 引入sub(custom / anthropic_messages)+claude-opus-5-5:thinking: {type:"adaptive"},reasoning: max→output_config: {effort:"max"}catalog1M → 窗口 1,000,000,自动压缩 675,000(修复前 128,000 / 86,400);Opuscatalog1M → 1,000,000 / 784,800(修复前 128,000 / 86,400)真实环境:
剩余风险:
catalogModelConfigFor在主会话路径使用vendorBinding?.baseUrl ?? provider.baseUrl查目录(原先为provider.baseUrl),仅在厂商账号绑定缺少modelConfig时才会走到;当前bindingFromOption总会提供modelConfig,实际不触发。🤖 Generated with Claude Code