@tzyc/dsh-model-visibility 1.10.2 → 1.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,10 +3,12 @@ export const DICT = {
3
3
  'nav': '模型显示',
4
4
  'page.title': '模型显示',
5
5
  'page.description':
6
- '关闭的模型不会出现在聊天输入框的模型下拉列表中;这里的改动立即生效,之后仍可随时重新打开。每个模型标注真实能力:适配器声明优先,其次读中转站的模型列表,再用内置目录补全;生图、生视频等生成类模型单独标记。',
7
- 'page.summary': '已显示 {visible} / {total} 个模型',
8
- 'page.hiddenSummary': '已关闭 {count} 个',
9
- 'page.kindSummary': '{count} 个生图/生视频模型',
6
+ '关闭的模型不会出现在聊天输入框的模型下拉列表中;这里的改动立即生效,之后仍可随时重新打开。每个模型标注真实能力:适配器声明优先,其次读中转站模型列表,最后用校验结果或模型名补全。',
7
+ 'page.about': '说明',
8
+ 'page.aboutTitle': '展开标签含义、来源与颜色说明',
9
+ 'page.summary': '已显示 {visible} / {total}',
10
+ 'page.hiddenSummary': '已关闭 {count}',
11
+ 'page.kindSummary': '生图/生视频 {count}',
10
12
  'page.loading': '正在加载模型列表…',
11
13
  'page.empty': '暂无可用模型。',
12
14
  'page.filterEmpty': '当前筛选下没有模型。',
@@ -14,31 +16,33 @@ export const DICT = {
14
16
  'page.saveFailed': '保存失败,请重试。',
15
17
  'page.refresh': '刷新',
16
18
  'page.refreshing': '刷新中…',
19
+ 'page.refreshTitle': '重新读取适配器与中转站的能力信息(沿用缓存,10 分钟内的探测不会重发请求)',
17
20
  'page.reload': '重新获取能力',
18
21
  'page.reloading': '正在获取…',
19
22
  'page.reloadTitle':
20
23
  '清空本插件的能力缓存和正在进行的读取,重新询问适配器与所有中转站;不会改动任何模型开关。适配器没有公布的思考强度仍不会凭空出现。',
21
24
  'page.reloadUnavailable': 'Host 半不支持强制重新获取;重启 DSH 后可用。',
22
- 'page.collapseGroups': '折叠全部分组',
23
- 'page.expandGroups': '展开全部分组',
25
+ 'page.collapseGroups': '折叠全部',
26
+ 'page.expandGroups': '展开全部',
24
27
  'page.collapseGroupsTitle': '只保留分组标题,方便跳到其他分组',
25
28
  'page.expandGroupsTitle': '展开所有被折叠的分组',
26
29
  'page.showAll': '全部显示',
27
30
  'page.legend':
28
- '标签说明:推理 = 可调推理等级;上下文 = 输入窗口;多模态 = 可输入图像。实线标签来自适配器、中转站或厂商文档,虚线标签来自内置目录或模型名推断。生图 / 生视频 / 嵌入等模型只标类型,不显示思考强度与文本标签。',
31
+ '标签:推理 = 可调推理等级;上下文 = 输入窗口;多模态 = 可输入图像。实线来自适配器、中转站或厂商文档,虚线来自联网校验或模型名推断。生图 / 生视频 / 嵌入等只标类型,不显示思考强度与文本标签。',
29
32
  'page.metaFallback':
30
33
  '模型能力信息暂不可用:上下文与模态显示为未知,推理档位仍来自官方目录。',
31
34
  'page.hostStale':
32
35
  'Host 半仍是旧版本:颜色与开关已更新,但「放行图像」和官方校正要等 DSH 重启(或 profile 重组)后才会生效。',
33
- 'page.providerFailures': '部分提供方暂时读不到模型:{names}',
34
- 'page.probeSummary': '中转站探测:{ok} 个已读取模型列表,{caps} 个公布了能力字段',
35
- 'page.probeSummaryNone': '中转站探测:暂无可读取的路由配置',
36
- 'page.catalogNote': '内置目录:pi-ai {version} 快照({date}),共 {models} 个模型',
37
- 'page.learnedNote': '学习快照:联网校验({date}),缓存 {models} 个模型的可验证事实',
38
- 'usage.title': 'token 用量',
36
+ 'page.providerFailures': '部分提供方读不到模型:{names}',
37
+ 'page.probeFailures': '中转站读取失败:{names}',
38
+ 'page.probeSummary': '探测:{ok} 个中转站可读',
39
+ 'page.probeSummaryTitle': '中转站探测结果;悬停分组上的标记可看具体诊断',
40
+ 'page.probeSummaryNone': '探测:未配置可探测的路由',
41
+ 'page.learnedNote': '学习快照 {models} 条({date})',
42
+ 'usage.title': 'token',
39
43
  'usage.computing': '统计中…',
40
44
  'usage.none': '—',
41
- 'usage.range': '输入 {input} · 输出 {output}(合计 {total})',
45
+ 'usage.detail': '输入 {input} · 输出 {output} · 缓存读 {cacheRead} · 缓存写 {cacheWrite}',
42
46
  'usage.today': '今天',
43
47
  'usage.todayTitle': '本地自然日(今天 0 点起)',
44
48
  'usage.week': '本周',
@@ -47,47 +51,62 @@ export const DICT = {
47
51
  'usage.monthTitle': '本月 1 日 0 点起',
48
52
  'usage.total': '总计',
49
53
  'usage.totalTitle': '全部历史(更早的按会话创建日粗算)',
50
- 'usage.exportUsage': '导出用量 CSV',
54
+ 'usage.exportUsage': '用量 CSV',
51
55
  'usage.exportUsageTitle': '下载按天分桶、含每模型 token 分解的 CSV',
52
- 'usage.exportModels': '导出模型清单 CSV',
56
+ 'usage.exportModels': '模型 CSV',
53
57
  'usage.exportModelsTitle': '下载全部提供商模型的可见性与能力表',
54
58
  'usage.hostStale': '宿主半尚未提供用量统计,重启 DSH 即可启用。',
55
- 'checker.title': '联网校验模型能力',
59
+ 'checker.title': '联网校验',
56
60
  'checker.description':
57
- '选定一个模型作为校验员:先把两个公开目录(models.dev / OpenRouter)拉下来做基准,再把其余模型分批交给它核对上下文窗口、输入模态、思考档位与类型;结果回填本页并(在开关打开时)写入对应提供商配置,同时存进本地快照 learned.json,之后同名模型直接复用缓存。校验请求会消耗所选模型的 API 额度,其 token 消耗会计入上方用量统计。',
61
+ '选定一个校验员模型:先拉 models.dev / OpenRouter / Hugging Face 三个公开目录做基准,再把其余模型分批交给它核对。公开目录已经知道的能力会直接采用,校验员答不上时也不例外。校验请求会消耗所选模型的额度,其 token 计入上方统计。提示:思考型模型会先花掉输出预算,若批次普遍失败,换一个非思考模型或降低其思考档位。',
58
62
  'checker.provider': '校验员提供商',
59
63
  'checker.model': '校验员模型',
60
64
  'checker.start': '开始校验',
61
65
  'checker.startTitle': '在宿主侧后台跑一轮全模型校验',
62
66
  'checker.cancel': '取消',
63
67
  'checker.cancelTitle': '中止正在进行的校验',
64
- 'checker.writeBack': '校验通过即写入提供商配置',
68
+ 'checker.writeBack': '同时写入提供商配置',
65
69
  'checker.writeBackTitle':
66
- '开启:判定到的 input / contextWindow / 推理档位直接写进各提供商该模型条目(learned.json 只留写不进去的字段);关闭:只更新本页与快照,需要时再用「编辑能力」手动写入。',
70
+ '开启:判定到的 input / contextWindow / 推理档位直接写进各提供商该模型条目(learned.json 只留写不进去的字段);关闭:只更新本页与快照。',
67
71
  'checker.idle': '未运行',
68
- 'checker.running': '进行中 {phase} · {done}/{total} · 已耗 {tokens}',
69
- 'checker.finished': '已完成 {done}/{total} · 校验耗 token {tokens}',
72
+ 'checker.running': '进行中{phase} · {done}/{total} · 已耗 {tokens}',
73
+ 'checker.finished': '已完成 {done}/{total} · 耗 {tokens}',
70
74
  'checker.progress': '{done}/{total} 已核对 · 校验本身消耗 {tokens} token',
71
- 'checker.errors': '{count} 个批次失败(悬停看详情)',
72
- 'checker.pickNeeded': '请先选择校验员提供商与模型。',
73
- 'checker.failed': '校验任务未能启动。',
75
+ 'checker.errorBadge': '{count} 个批次失败',
76
+ 'checker.errorTitle': '失败批次',
77
+ 'checker.errorMore': '另有 {count} 条未显示',
78
+ 'checker.concurrency': '并发线程',
79
+ 'checker.concurrencyTitle': '同时发出的校验请求数。中转站限流时调低,网络快时调高(上限 8)。',
80
+ 'checker.concurrencyValue': '{count} 路',
81
+ 'checker.threads': '并发 {count} 路',
82
+ 'checker.sourcesTitle': '公开目录',
83
+ 'checker.source.ok': '已读取',
84
+ 'checker.source.empty': '无匹配',
85
+ 'checker.source.http': 'HTTP 错误',
86
+ 'checker.source.failed': '请求失败',
87
+ 'checker.source.bad-json': '非 JSON',
88
+ 'checker.source.too-large': '响应过大',
89
+ 'checker.source.pending': '等待中',
90
+ 'checker.sourceModels': '{count} 条',
91
+ 'checker.publicOnly': '其中 {count} 个模型的能力来自公开目录(校验员未作答)。',
74
92
  'checker.hostStale': '宿主半不支持联网校验,请重启 DSH 后使用。',
75
93
  'checker.phase.public': '(读取公开目录)',
76
94
  'checker.phase.checker': '(读取公开目录)',
77
95
  'checker.phase.verifying': '(分批校验)',
78
96
  'source.snapshot': '已校验',
79
97
  'page.applyInput': '让输入框按能力标注放行图像',
98
+ 'page.applyInputShort': '多模态中转站模型自动补 image;关闭则只按 Provider 的 input 声明',
80
99
  'page.applyInputHint':
81
100
  '开启后,被标注为「多模态」的中转站对话模型会在发送请求时自动补上图像输入能力;关闭则完全按 Provider 配置里的 input 声明。只影响中转站(pi-ai)路由,不改任何配置文件;若某个上游实际拒绝图像,关闭此开关即可。',
82
101
  'page.kindLegend':
83
- '颜色区分模型类型:生图 蓝 · 生视频 绿 · 嵌入 橙 · 音频 紫 · 重排 红 · 审核 玫红 · 翻译 灰。「官方校正」表示内置目录与厂商文档不一致时以文档为准。',
84
- 'page.filterLabel': '筛选',
85
- 'page.searchPlaceholder': '搜索模型名称或 ID',
86
- 'page.capabilityLabel': '能力',
102
+ '类型配色:生图 蓝 · 生视频 绿 · 嵌入 橙 · 音频 紫 · 重排 红 · 审核 玫红 · 翻译 灰。「官方校正」表示目录与厂商文档不一致时以文档为准。',
103
+ 'page.searchPlaceholder': '搜索名称或 ID',
87
104
  'page.capability.multimodal': '多模态',
105
+ 'page.capability.multimodalTitle': '只看可输入图像的模型',
88
106
  'page.capability.reasoning': '支持推理',
107
+ 'page.capability.reasoningTitle': '只看公布了推理能力的模型',
89
108
  'page.contextLabel': '上下文至少',
90
- 'page.context.any': '不限',
109
+ 'page.context.any': '上下文不限',
91
110
  'page.context.128k': '128K+',
92
111
  'page.context.256k': '256K+',
93
112
  'page.context.512k': '512K+',
@@ -99,15 +118,15 @@ export const DICT = {
99
118
  'page.filter.other': '其它',
100
119
  'group.showAll': '全组显示',
101
120
  'group.hideAll': '全组隐藏',
102
- 'group.showFiltered': '显示筛选结果',
103
- 'group.hideFiltered': '隐藏筛选结果',
121
+ 'group.showFiltered': '显示结果',
122
+ 'group.hideFiltered': '隐藏结果',
104
123
  'group.collapseNamed': '折叠 {name} 分组',
105
124
  'group.expandNamed': '展开 {name} 分组',
106
- 'group.capabilities': '{chat} 对话 · {image} 生图 · {video} 生视频 · {other} 其它',
107
- 'group.probeOk': '中转站 {models} 个模型 · {caps} 个带能力字段',
108
- 'group.probeNoCaps': '中转站 {models} 个模型 · 未公布能力字段',
109
- 'group.probeFailed': '中转站读取失败',
110
- 'group.probeSkipped': '未探测中转站',
125
+ 'group.probeOk': '{models} 个模型 · {caps} 带能力',
126
+ 'group.probeNoCaps': '{models} 个模型 · 无能力字段',
127
+ 'group.probePartial': '价格接口 {models} 个',
128
+ 'group.probeFailed': '读取失败',
129
+ 'group.probeSkipped': '未探测',
111
130
  'tag.reasoning': '支持推理',
112
131
  'tag.noReasoning': '不支持推理',
113
132
  'tag.reasoningUnknown': '推理未知',
@@ -130,7 +149,6 @@ export const DICT = {
130
149
  'tag.kindVideoTitle': '视频生成模型(输出视频);类型来源:{source}',
131
150
  'tag.correction': '官方校正',
132
151
  'tag.correctionTitle': '{note}\n来源:{source}',
133
- 'tag.resolution': '分辨率',
134
152
  'tag.resolutionTitle': '模型名标注了 {value} 输出档位',
135
153
  'tag.imageInput': '可改图',
136
154
  'tag.imageInputTitle': '支持图像输入(图生图 / 参考图)',
@@ -213,10 +231,12 @@ export const DICT = {
213
231
  'nav': 'Model visibility',
214
232
  'page.title': 'Model visibility',
215
233
  'page.description':
216
- 'Models turned off here disappear from the chat composer model list. Changes apply immediately and can be turned back on at any time. Every model shows its real capabilities: adapter declarations first, then the relay model list, then a built-in catalog; image, video and other generation models are labelled separately.',
217
- 'page.summary': 'Showing {visible} of {total} models',
234
+ 'Models turned off here disappear from the chat composer model list. Changes apply immediately and can be turned back on at any time. Every model shows its real capabilities: adapter declarations first, then the relay model list, then verification results or the model name.',
235
+ 'page.about': 'About',
236
+ 'page.aboutTitle': 'Show what the tags, sources and colours mean',
237
+ 'page.summary': 'Showing {visible} of {total}',
218
238
  'page.hiddenSummary': '{count} hidden',
219
- 'page.kindSummary': '{count} image/video models',
239
+ 'page.kindSummary': '{count} image/video',
220
240
  'page.loading': 'Loading model list…',
221
241
  'page.empty': 'No models available.',
222
242
  'page.filterEmpty': 'No models match this filter.',
@@ -224,80 +244,99 @@ export const DICT = {
224
244
  'page.saveFailed': 'Could not save this change. Try again.',
225
245
  'page.refresh': 'Refresh',
226
246
  'page.refreshing': 'Refreshing…',
247
+ 'page.refreshTitle': 'Read adapter and relay capabilities again (honours caches; a probe younger than 10 minutes is not repeated)',
227
248
  'page.reload': 'Re-fetch capabilities',
228
249
  'page.reloading': 'Re-fetching…',
229
250
  'page.reloadTitle':
230
251
  'Drops this plugin’s capability caches and any in-flight read, then asks the adapter and every relay again. Model switches are untouched; effort levels the adapter does not publish still cannot appear.',
231
252
  'page.reloadUnavailable': 'The Host half does not support a hard re-fetch; restart DSH to enable it.',
232
- 'page.collapseGroups': 'Collapse all groups',
233
- 'page.expandGroups': 'Expand all groups',
253
+ 'page.collapseGroups': 'Collapse all',
254
+ 'page.expandGroups': 'Expand all',
234
255
  'page.collapseGroupsTitle': 'Keep only group headers so other groups are easy to reach',
235
256
  'page.expandGroupsTitle': 'Expand every collapsed group',
236
257
  'page.showAll': 'Show all',
237
258
  'page.legend':
238
- 'Tags: Reasoning = adjustable levels; Context = input window; Multimodal = accepts images. Solid tags come from the adapter, the relay or vendor documentation; dashed tags come from the built-in catalog or the model name. Image, video, embedding and other generation models show only their kind, never effort or text tags.',
259
+ 'Tags: Reasoning = adjustable levels; Context = input window; Multimodal = accepts images. Solid tags come from the adapter, the relay or vendor documentation; dashed tags come from online verification or the model name. Image, video, embedding and other models show only their kind.',
239
260
  'page.metaFallback':
240
261
  'Model capability details are unavailable right now: context and modalities show as unknown, while effort levels still come from the shipped catalog.',
241
262
  'page.hostStale':
242
263
  'The Host half is still the previous version: the colours and switch are live, but image admission and vendor corrections take effect after DSH restarts (or the profile recomposes).',
243
264
  'page.providerFailures': 'Some providers could not be read: {names}',
244
- 'page.probeSummary': 'Relay probe: {ok} model lists read, {caps} published capability fields',
245
- 'page.probeSummaryNone': 'Relay probe: no readable route configuration',
246
- 'page.catalogNote': 'Built-in catalog: pi-ai {version} snapshot ({date}), {models} models',
247
- 'page.learnedNote': 'Learned snapshot: online verification ({date}), {models} verified models',
248
- 'usage.title': 'Token usage',
265
+ 'page.probeFailures': 'Relay read failed: {names}',
266
+ 'page.probeSummary': 'Probe: {ok} relays readable',
267
+ 'page.probeSummaryTitle': 'Relay probe result; hover a group badge for its diagnostics',
268
+ 'page.probeSummaryNone': 'Probe: no route configured to probe',
269
+ 'page.learnedNote': 'Learned {models} facts ({date})',
270
+ 'usage.title': 'tokens',
249
271
  'usage.computing': 'scanning…',
250
272
  'usage.none': '—',
251
- 'usage.range': 'in {input} · out {output} ({total} total)',
273
+ 'usage.detail': 'input {input} · output {output} · cache read {cacheRead} · cache write {cacheWrite}',
252
274
  'usage.today': 'Today',
275
+ 'usage.week': 'Week',
276
+ 'usage.month': 'Month',
277
+ 'usage.total': 'Total',
253
278
  'usage.todayTitle': 'Local calendar day',
254
- 'usage.week': 'This week',
255
279
  'usage.weekTitle': 'Since Monday 00:00 local',
256
- 'usage.month': 'This month',
257
280
  'usage.monthTitle': 'Since the 1st local',
258
- 'usage.total': 'Total',
259
281
  'usage.totalTitle': 'All history (older months attributed by session start day)',
260
- 'usage.exportUsage': 'Export usage CSV',
282
+ 'usage.exportUsage': 'Usage CSV',
261
283
  'usage.exportUsageTitle': 'Download a day-bucketed CSV with per-model breakdown',
262
- 'usage.exportModels': 'Export model list CSV',
284
+ 'usage.exportModels': 'Models CSV',
263
285
  'usage.exportModelsTitle': 'Download visibility and capability table of every provider model',
264
286
  'usage.hostStale': 'The Host half does not provide usage stats yet; restart DSH to enable it.',
265
- 'checker.title': 'Verify model capabilities online',
287
+ 'checker.title': 'Online verification',
266
288
  'checker.description':
267
- 'Pick one model as the checker: two public catalogs (models.dev / OpenRouter) are fetched first, then the remaining models are verified in batches — context window, input modalities, effort ladder and kind. Confirmed facts fill this page and, with the switch on, are written into the provider entries; they are also stored in the local learned.json snapshot so a same-named model on another route reuses the cache. Verification spends the checker route quota and its tokens count in the usage strip above.',
289
+ 'Pick one model as the checker: three public catalogs (models.dev / OpenRouter / Hugging Face) are fetched first, then the remaining models are verified in batches. Whatever the catalogs already know is applied directly, even when the checker has no answer. A sweep spends the checker route quota and its tokens count in the strip above. Note: a thinking model spends the output budget before it answers, so if batches keep failing pick a non-thinking checker or lower its effort.',
268
290
  'checker.provider': 'Checker provider',
269
291
  'checker.model': 'Checker model',
270
- 'checker.start': 'Verify all',
292
+ 'checker.start': 'Start',
271
293
  'checker.startTitle': 'Run a background verification sweep in the Host',
272
294
  'checker.cancel': 'Cancel',
273
295
  'checker.cancelTitle': 'Abort the running sweep',
274
- 'checker.writeBack': 'Write confirmed facts into provider settings',
296
+ 'checker.writeBack': 'Also write into provider settings',
275
297
  'checker.writeBackTitle':
276
- 'On: the judged input / contextWindow / efforts are written into each provider entry (learned.json keeps only what cannot be mapped). Off: only this page and the snapshot update; use Edit capabilities to write manually.',
298
+ 'On: the judged input / contextWindow / efforts are written into each provider entry (learned.json keeps only what cannot be mapped). Off: only this page and the snapshot update.',
277
299
  'checker.idle': 'not run yet',
278
- 'checker.running': 'running {phase} · {done}/{total} · {tokens} spent',
279
- 'checker.finished': 'finished {done}/{total} · checker spent {tokens} tokens',
300
+ 'checker.running': 'running{phase} · {done}/{total} · {tokens} spent',
301
+ 'checker.finished': 'finished {done}/{total} · {tokens} spent',
280
302
  'checker.progress': '{done}/{total} verified · checker spent {tokens} tokens',
281
- 'checker.errors': '{count} failed batches (hover for details)',
282
- 'checker.pickNeeded': 'Pick a checker provider and model first.',
283
- 'checker.failed': 'The verify sweep could not start.',
303
+ 'checker.errorBadge': '{count} failed batches',
304
+ 'checker.errorTitle': 'Failed batches',
305
+ 'checker.errorMore': '{count} more not shown',
306
+ 'checker.concurrency': 'Threads',
307
+ 'checker.concurrencyTitle':
308
+ 'How many checker requests may be in flight at once. Lower it if the relay rate-limits you, raise it on a fast link (max 8).',
309
+ 'checker.concurrencyValue': '{count}',
310
+ 'checker.threads': '{count} in parallel',
311
+ 'checker.sourcesTitle': 'Public catalogs',
312
+ 'checker.source.ok': 'read',
313
+ 'checker.source.empty': 'no match',
314
+ 'checker.source.http': 'HTTP error',
315
+ 'checker.source.failed': 'request failed',
316
+ 'checker.source.bad-json': 'not JSON',
317
+ 'checker.source.too-large': 'response too large',
318
+ 'checker.source.pending': 'pending',
319
+ 'checker.sourceModels': '{count}',
320
+ 'checker.publicOnly': '{count} models were resolved from a public catalog alone (the checker had no answer).',
284
321
  'checker.hostStale': 'The Host half does not support online verification yet; restart DSH.',
285
- 'checker.phase.public': '(fetching public catalogs)',
286
- 'checker.phase.checker': '(fetching public catalogs)',
287
- 'checker.phase.verifying': '(verifying in batches)',
322
+ 'checker.phase.public': ' (fetching public catalogs)',
323
+ 'checker.phase.checker': ' (fetching public catalogs)',
324
+ 'checker.phase.verifying': ' (verifying in batches)',
288
325
  'source.snapshot': 'verified',
289
326
  'page.applyInput': 'Let the composer admit images shown as supported',
327
+ 'page.applyInputShort':
328
+ 'Adds image input to multimodal relay models; off means the Provider input declaration only',
290
329
  'page.applyInputHint':
291
330
  'When on, relay chat models labelled Multimodal advertise image input to the request path; when off, only the Provider input declaration counts. Relay (pi-ai) routes only — no configuration file is modified. Turn it off if a particular upstream still rejects images.',
292
331
  'page.kindLegend':
293
- 'Colours separate model kinds: image blue · video green · embedding orange · audio purple · rerank red · moderation rose · translation grey. “Official correction” means the vendor documentation overrides a wrong catalog row.',
294
- 'page.filterLabel': 'Filter',
295
- 'page.searchPlaceholder': 'Search model name or ID',
296
- 'page.capabilityLabel': 'Capabilities',
332
+ 'Kind colours: image blue · video green · embedding orange · audio purple · rerank red · moderation rose · translation grey. “Official correction” means vendor documentation overrides a wrong catalog row.',
333
+ 'page.searchPlaceholder': 'Search name or ID',
297
334
  'page.capability.multimodal': 'Multimodal',
335
+ 'page.capability.multimodalTitle': 'Only models that accept image input',
298
336
  'page.capability.reasoning': 'Reasoning',
337
+ 'page.capability.reasoningTitle': 'Only models that publish reasoning support',
299
338
  'page.contextLabel': 'Context at least',
300
- 'page.context.any': 'Any',
339
+ 'page.context.any': 'Any context',
301
340
  'page.context.128k': '128K+',
302
341
  'page.context.256k': '256K+',
303
342
  'page.context.512k': '512K+',
@@ -309,15 +348,15 @@ export const DICT = {
309
348
  'page.filter.other': 'Other',
310
349
  'group.showAll': 'Show all',
311
350
  'group.hideAll': 'Hide all',
312
- 'group.showFiltered': 'Show filtered',
313
- 'group.hideFiltered': 'Hide filtered',
351
+ 'group.showFiltered': 'Show results',
352
+ 'group.hideFiltered': 'Hide results',
314
353
  'group.collapseNamed': 'Collapse the {name} group',
315
354
  'group.expandNamed': 'Expand the {name} group',
316
- 'group.capabilities': '{chat} chat · {image} image · {video} video · {other} other',
317
- 'group.probeOk': 'relay: {models} models · {caps} with capability fields',
318
- 'group.probeNoCaps': 'relay: {models} models · no capability fields',
319
- 'group.probeFailed': 'relay read failed',
320
- 'group.probeSkipped': 'relay not probed',
355
+ 'group.probeOk': '{models} models · {caps} with caps',
356
+ 'group.probeNoCaps': '{models} models · no cap fields',
357
+ 'group.probePartial': 'pricing {models} models',
358
+ 'group.probeFailed': 'read failed',
359
+ 'group.probeSkipped': 'not probed',
321
360
  'tag.reasoning': 'Reasoning',
322
361
  'tag.noReasoning': 'No reasoning',
323
362
  'tag.reasoningUnknown': 'Reasoning unknown',
@@ -340,7 +379,6 @@ export const DICT = {
340
379
  'tag.kindVideoTitle': 'Video generation model (outputs video); kind source: {source}',
341
380
  'tag.correction': 'Official correction',
342
381
  'tag.correctionTitle': '{note}\nSource: {source}',
343
- 'tag.resolution': 'Resolution',
344
382
  'tag.resolutionTitle': 'The model name advertises a {value} output tier',
345
383
  'tag.imageInput': 'Image edit',
346
384
  'tag.imageInputTitle': 'Accepts image input (image-to-image / reference images)',
@@ -93,9 +93,16 @@ export function sourceOf(model, field) {
93
93
  return sources && typeof sources[field] === 'string' ? sources[field] : 'unknown'
94
94
  }
95
95
 
96
- /** Catalog and name heuristics are completed values, not declarations. */
96
+ /**
97
+ * Sources whose values are completed or inferred rather than declared.
98
+ *
99
+ * `snapshot` is the learned store: facts a checker model or a public catalog
100
+ * reported. Only the adapter, the settings document, the relay's own listing
101
+ * and a vendor correction count as declarations, so a verified row must stay
102
+ * dashed — otherwise an LLM guess would look as trustworthy as a declaration.
103
+ */
97
104
  export function isInferredSource(source) {
98
- return source === 'catalog' || source === 'inferred'
105
+ return source === 'snapshot' || source === 'inferred'
99
106
  }
100
107
 
101
108
  /** Kind with a safe fallback for records from an older Host. */
@@ -5,6 +5,8 @@
5
5
  * @module client-src/pure
6
6
  */
7
7
 
8
+ import { bucketOf, kindOf } from './format.mjs'
9
+
8
10
  /** Number of one bucket's token sum, guarding partial buckets. */
9
11
  export function bucketTotalOf(buckets) {
10
12
  if (!Array.isArray(buckets)) return 0
@@ -79,11 +81,9 @@ export function computeFilteredGroups(groups, { filter = 'all', query = '', mult
79
81
  }
80
82
 
81
83
  function bucket(model) {
82
- const kind = model && typeof model.kind === 'string' && model.kind !== '' ? model.kind : 'chat'
83
- if (kind === 'image') return 'image'
84
- if (kind === 'video') return 'video'
85
- if (kind === 'chat') return 'chat'
86
- return 'other'
84
+ // One implementation lives in `format.mjs` as `bucketOf`; duplicating the
85
+ // four branches here meant the filter and the tag colours could drift apart.
86
+ return bucketOf(kindOf(model))
87
87
  }
88
88
 
89
89
  /** Counts per kind bucket for the whole list. */
@@ -104,7 +104,11 @@ export function checkerRoutesOf(groups) {
104
104
  return routes
105
105
  }
106
106
 
107
- /** Compact label + tooltip for one provider probe diagnostic. */
107
+ /**
108
+ * Compact label + tooltip for one provider probe diagnostic.
109
+ * @returns `{ label, title, failed? }` or null; `failed` marks a route the page
110
+ * should warn about instead of quietly annotating.
111
+ */
108
112
  export function probeOf(state, group, t) {
109
113
  const list = Array.isArray(state.providers) ? state.providers : []
110
114
  const diagnostic = list.find((item) => item && item.id === group.id)
@@ -112,6 +116,8 @@ export function probeOf(state, group, t) {
112
116
  const details = [
113
117
  diagnostic.host ? 'host: ' + diagnostic.host : null,
114
118
  diagnostic.status ? 'status: ' + diagnostic.status : null,
119
+ diagnostic.models ? 'models: ' + diagnostic.models : null,
120
+ diagnostic.capabilities ? 'capabilities: ' + diagnostic.capabilities : null,
115
121
  diagnostic.message ? 'message: ' + diagnostic.message : null,
116
122
  diagnostic.pricing && diagnostic.pricing !== 'skipped' ? 'pricing: ' + diagnostic.pricing : null,
117
123
  ]
@@ -129,8 +135,19 @@ export function probeOf(state, group, t) {
129
135
  title: details,
130
136
  }
131
137
  }
138
+ // The listing failed but the pricing endpoint still enumerated the route.
139
+ if (diagnostic.status === 'partial') {
140
+ return {
141
+ label: t('group.probePartial', { models: diagnostic.models ?? 0 }),
142
+ title: details,
143
+ }
144
+ }
132
145
  if (diagnostic.status === 'failed' || diagnostic.status === 'unauthorized') {
133
- return { label: t('group.probeFailed'), title: details }
146
+ return {
147
+ label: t('group.probeFailed'),
148
+ title: details,
149
+ failed: true,
150
+ }
134
151
  }
135
152
  return { label: t('group.probeSkipped'), title: details }
136
153
  }