Repository navigation
Conversation
The Composer picker already reported each model's context window but not its output ceiling, so a user comparing models there saw half the shape Settings shows on the very same row. The published record already carries both limits (ModelInfo.maxTokens / limit.output); the row simply was not reading it. Each row now renders the pair through the one shared compact formatter, in the same order and the same typography as the settings row, so "200K · 8K" means the same thing in both places. A limit the service never published renders as an em dash — the row never invents a number — and a record that publishes neither keeps the row free of a limits pair altogether. Scope stays deliberately narrow: the picker reports what models.dev states, and a per-model override typed into Advanced keeps its existing home in Settings and at runtime, exactly as the context window already behaves. Tests cover the helper (both published-value shapes plus an unpublished one) and the row contract, and both fail against the previous implementation. fixes vastsa#1028
The Composer model picker named each row only by text, so a list scrolling past its heading stopped saying which vendor a model belonged to. The reporter of vastsa#1028 hand-drew icons and found them "ugly and inconsistent" — the expected result of inventing per-row artwork by hand. Picking a mark by display name would be unsound: a row's name is user editable, several rows resolve to one catalog vendor, and a custom name would borrow a vendor's artwork. Fetching marks from models.dev at runtime would be just as unsound: an extra origin in the CSP, a different list offline, and an outbound request naming the providers a user configured. So the mark is chosen by the catalog key that already places the row's metadata — resolved once in Main, through the alias mapping that exists today, with no second source of truth in the renderer — and the artwork ships with the release. A curated set of monochrome marks is vendored with an UPSTREAM.md recording source, date, licence, and refresh procedure. They render through a CSS mask, so a run of vendors keeps one visual weight and follows the theme text color instead of filling the list with saturated logos. A key with no vendored mark, including every row the catalog cannot place, falls back to the shared generic mark: no row is left without an identity, and a missing artwork is a cosmetic fallback rather than a broken list. Tests cover the table/asset/enforcement set staying in step, the mark staying a monochrome maskable path, the vendored files carrying no script or remote reference, the enrichment wiring, and the row/heading markup. The two new rendering assertions fail against the previous implementation. fixes vastsa#1028
origin/main advanced past this branch's base while the pull request was under review. Integrate it with a merge rather than a rebase, because the branch is already shared through the open PR and rewriting its history would force a push onto it. Six files conflicted, and none of them needed a judgement call about which change wins — both sides were right: - `provider-ipc.ts` — origin/main restructured the catalog dependency into a multi-line union and added `anthropicThinkingFor`; keep that shape and add `providerKeyForRow` beside it, since both surfaces are used. - `provider-catalog.ts` — origin/main replaced the enrichment guard with `catalogModelConfig.source !== "generic"`. Keep the new guard and keep the `catalogProviderKey` spread; they publish different fields. - `ComposerModelList.tsx` — origin/main turned the reasoning/vision badges into icon marks with an accessible label, and read the configured alias for the row label. Keep both, and keep the output limit beside the context window, so a row now reads: mark, id, badges, `context · output`. - `composer-menus.css` — origin/main deleted the thinking-list truncation rule because nothing references it any more. Respect that deletion and keep the two new limit rules. - Both decisions logs appended a section at the end. Keep both entries. One real collision surfaced here: origin/main had already spent **D625** on the model-settings redesign, and this change had claimed the same id for the provider brand marks. Renumber ours to D628 — the next id free across the repository — in both the English log and its Chinese mirror, so the mirror stays a one-to-one translation of the source of truth. Validation: desktop typecheck and a full JS build pass. The desktop suite reports 52 failures, which is the same set the untouched `origin/main` reports in this environment — measured in a throwaway worktree at `origin/main`, not assumed — so the merge introduces no regression. Seven of those failures are new only relative to this branch's previous base, because the bundled models.dev snapshot tests that origin/main added do not load a snapshot here; they fail identically without this change.
models.dev publishes Xiaomi's mimo models under a `xiaomi` key with ids like `mimo-v2.6-pro` — no `xiaomi/` route anywhere in the id. Reading the owner off the id alone therefore named nothing, and every mimo row kept the generic mark even though the catalog states the owner outright. So add a second owner signal: when a publisher's own key is a known vendor, that is the vendor describing its own model, which is the same claim a route in the id makes. `xiaomi` joins `MODEL_VENDOR_PREFIXES` so the publisher qualifies. This is bounded in the direction that matters: a reseller never qualifies, because its key (`opencode-go`, `nano-gpt`, `requesty`) is not in the vendor set, so a gateway whose row merely republishes a model cannot claim its mark. A route still wins, because the id states its owner more directly than the host that listed it. The effect is not limited to Xiaomi. `muse-spark-1.3-contributor` was generic for the same reason and now resolves to `meta`, which is who publishes it — the rule covers the class rather than one vendor. Vendor `xiaomi.svg` from models.dev and map the three `xiaomi-token-plan-*` billing-region keys to the same artwork, since they publish the same models. Tests run against the shipped snapshot rather than a fixture, because a fixture would only prove the resolver agrees with itself: every mimo spelling through the vendor route, the bare id, and the resellers' variants; a reseller not becoming the owner of an id it republishes; and a spelling no record owns still resolving to nothing rather than being guessed. fixes vastsa#1028
lenmei233
force-pushed
the
feat/composer-model-output-limit-icons
branch
from
September 26, 2026 08:23
c03076f to
efbd72e
Compare
…utput-limit-icons
Contributor
Author
|
@vastsa 经过多次完善,我认为已经可以merge了 |
This branch has not been deployed
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.
改动说明
Issue #1028 提了三件事:显示模型上下文与输出长度、获取模型和图标,并吐槽自制图标"好难看、不统一"。核对主线后:上下文长度上游已经做了;输出长度是真实缺口;图标完全缺失。本 PR 补齐后两项。
一、Composer 模型行显示输出上限
行内数据一直都在(
ModelInfo.maxTokens/limit.output),只是选择器没读。现在每行与设置行读法一致地显示「上下文窗口 · 输出上限」一对数值,共用同一个紧凑格式化函数;服务未发布的那一项显示破折号,不编造数字。刻意保持窄范围:选择器只报告模型的已发布值,用户在「高级」里按模型填写的覆盖值仍留在设置页与运行时,与上下文窗口现有行为一致。二、模型行由厂商标识
选择器此前只用文字标识每一行,列表滚过标题后就看不出某行属于哪个厂商。两轮迭代后定型的做法:
ModelInfo.catalogVendorKey),而不是整个 provider 组的 key;组标题没有行可读,才用 provider 级 key。openai/gpt-6-astra指名openai)读出,扫描范围是目录为该 ID 自带的候选索引(与findModel同一套),再经既有的提供商别名表映射。它指名的是权重归属者,而不是本次查找恰好命中的记录由谁发布——否则中转网关自己的记录会让 MiniMax 行显示网关图标。纯元数据:不改任何能力、上限或线模型 ID,findModel本身未动。它指名的是权重归属者,而不是本次查找恰好命中的记录由谁发布——否则中转网关自己的记录会让 MiniMax 行显示网关图标。纯元数据:不改任何能力、上限或线模型 ID,
findModel本身未动。mimo-v2.6-pro因此归到xiaomi(xiaomi据此加入MODEL_VENDOR_PREFIXES)。这条规则对中转网关是封闭的:网关的 key(opencode-go、nano-gpt、requesty)不在厂商集合里,所以只是转载某模型的网关无法冒领其图标;厂商路由始终优先于发布者 key。这也顺带修好了muse-spark-1.3-contributor(原显示通用图标,实际由meta自己发布)。两种信号都指认不出的 ID 仍走回退。图标随发布打包(16 个厂商,
UPSTREAM.md记录来源、抓取日期、MIT 许可与刷新方式),并由scripts/build-provider-marks.mjs编译为内联currentColor组件。它们是路径而非图片:运行时不拉取、没有会失败的<img>、也不占 CSP 表面;继承主题文字颜色使各厂商保持同一视觉重量,而不是堆一排高饱和彩色 logo。目录无法指认厂商的行(含未知自由格式 ID)统一回退到共享通用图标——任何一行都不会缺少身份标识,缺失美术资源只是外观退化。图标是装饰性的(
aria-hidden),未新增任何用户可见字符串,十个 locale 不变。途中被否掉的方案(已记录进 ADR)
第一版把 SVG 当资产 URL 导入、用 CSS
mask-image上色。它只在 Vite 把资产输出为真实文件时生效:4 KB 以下的资产会被内联成data:URL,而 mask 无法从中取样绘制,元素就只剩自己的背景色——表现为纯灰方块。本次打包的多个图标都在该阈值以下,所以故障是局部的、看起来像某些厂商的单独 bug。改为内联 path 后阈值、<img>、mask 表面一并消失。实现要点
ProviderPublic.catalogProviderKey、ModelInfo.catalogVendorKey。无 IPC 契约变更(仅多两个属性)、无数据库迁移、无持久化格式变更、无 Plugin SDK 变更。不发送该字段的旧生产者正常工作并走回退。src/lib/provider-marks.tsx已提交(构建无需先跑生成器),build:deps仍会重新生成,并有测试在「重新生成结果与已提交文件不一致」时失败——避免改了 SVG 却发出旧美术资源。provider-brand-marks记录决策、备选方案与被否的 mask 方案;同步中英两份规格、UX 组件规范与决策日志(本 PR 决策号为 D628,主线此前已占用 D625)。测试
ComposerModelList放进 React SSR 渲染,确认品牌图标出现在组标题与行首、限额成对、未发布为—、未知供应商回退通用图标。本地实机验证(Windows)
除了静态检查,本 PR 是在跑起来的真实客户端里确认的:在独立 worktree 用
PI_DESKTOP_DEV=1启动(数据目录~/.pi-desktop-dev,与真实 profile 隔离),Rust host 握手与 sidecar 均正常启动。据此定位并修掉了两个只有实机才能看到的问题——自定义网关上全部回退、以及 mask 导致的局部灰块。效果预览
已验证
JS 全量构建、desktop typecheck、biome lint、
check:pr-base、check:agent-policy均通过。shared 1110 项全绿。desktop 测试 2958 项中 2899 通过;52 项失败与未经本 PR 改动的origin/main@05225d9d6完全一致(在临时 worktree 实测比对,非推断),合并不引入回归。未验证
test:e2e:transcript未能跑通,但与本次改动无关:该套件需要 Electron 渲染进程,本机跑不通;已在origin/main上另建独立 worktree 跑同一套,失败消息一字不差,故确认为环境限制。e2e-image-chat(需明确授权);未跑verify:ui:*(未获授权)。合并期间的冲突处理
origin/main在评审期间前进了,做过一次非破坏性合并(分支已共享,不做 rebase 强推)。六个文件冲突均为"两侧都对",分别保留双方;其中主线已占用 D625,故本 PR 决策号改为 D628(全仓空闲),中英文两份决策日志同步。fixes #1028