dsh-llm-verifier 0.6.3 → 0.6.5
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.
- package/README.md +7 -2
- package/lib/client.js +124 -96
- package/lib/client.js.map +1 -1
- package/lib/index.js +334 -10
- package/lib/index.js.map +1 -1
- package/lib/types/client-fields.d.ts +4 -0
- package/lib/types/client-fields.d.ts.map +1 -1
- package/lib/types/client-fields.js +21 -4
- package/lib/types/client-fields.js.map +1 -1
- package/lib/types/client-i18n.d.ts +24 -0
- package/lib/types/client-i18n.d.ts.map +1 -1
- package/lib/types/client-i18n.js +110 -94
- package/lib/types/client-i18n.js.map +1 -1
- package/lib/types/config.d.ts +12 -0
- package/lib/types/config.d.ts.map +1 -1
- package/lib/types/config.js +13 -1
- package/lib/types/config.js.map +1 -1
- package/lib/types/engine.d.ts +3 -0
- package/lib/types/engine.d.ts.map +1 -1
- package/lib/types/engine.js +7 -1
- package/lib/types/engine.js.map +1 -1
- package/lib/types/index.d.ts +1 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +45 -6
- package/lib/types/index.js.map +1 -1
- package/lib/types/pricing.d.ts +132 -0
- package/lib/types/pricing.d.ts.map +1 -0
- package/lib/types/pricing.js +279 -0
- package/lib/types/pricing.js.map +1 -0
- package/package.json +1 -1
- package/scripts/sync-installed-profiles.mjs +226 -21
- package/src/client-fields.test.ts +2 -0
- package/src/client-fields.ts +27 -4
- package/src/client-i18n.ts +110 -94
- package/src/config.ts +25 -1
- package/src/engine.ts +8 -2
- package/src/index.ts +45 -6
- package/src/pricing.test.ts +174 -0
- package/src/pricing.ts +324 -0
package/README.md
CHANGED
|
@@ -294,7 +294,11 @@ flowchart LR
|
|
|
294
294
|
| **缓存条目上限** | 成功评分持久化缓存的最大容量条目数 |
|
|
295
295
|
| **重试基础延迟 (ms)** | 重试时指数退避的基数,默认 500 |
|
|
296
296
|
| **缓存目录 (Cache directory)** | 评分缓存 / 能力记忆 / 统计文件在话题目录下的相对子目录,默认 `verifier`;留空保存时保留原值 |
|
|
297
|
-
|
|
|
297
|
+
| **输入 / 输出价格** | 手填的 USD/百万 token 单价。**留 0 即交给自动定价**;一旦填了任意一个,整组就以手填为准 |
|
|
298
|
+
| **缓存读取价格** | 缓存命中输入 token 的单价;留 0 时退回按输入价计算(旧口径,会把缓存密集的调用算贵)。真实的 cache-read 单价常是输入价的 1/50 |
|
|
299
|
+
| **本机模型目录自动定价** | 默认开。本机安装的 pi-ai 模型目录(models.dev 快照,`@earendil-works/pi-ai/dist/providers/data`,约 1350 条)里有这条 provider+模型时自动取单价,**纯离线、零配置** |
|
|
300
|
+
| **在线价格库兜底** | 默认开。本机目录查不到时向 models.dev 查一次(4.6 MB 快照,进程内缓存 24 小时),手填或目录命中时**完全不联网** |
|
|
301
|
+
| **价格来源 Provider** | 转售路由(例如 command-code)两张表都没有时的显式出路:填一个 provider id(例如 openrouter),按它的挂牌价折算。**留空=不猜**,未定价路由的成本记为 0 |
|
|
298
302
|
|
|
299
303
|
> [!NOTE]
|
|
300
304
|
> **显式证据的总量上限**:一次显式工具调用的全部证据(脱敏并单项截断后)合计不得超过 **「自动路由证据总字符上限」的 2 倍**,且绝不突破 **24 万字符** 的硬上限——默认即 12 万字符(约 3 万 token),超出会直接报错并给出实际字符数。这是为了在判官请求顶爆模型上下文之前就把问题挡住。单项上限仍为 2 万字符,`verifier_select` 最多 16 个候选(16 × 2 万已超过默认预算,需要精简候选)。
|
|
@@ -436,7 +440,7 @@ task ─┬─ 生成 N 份候选(会话模型,temperature 1.0,maxTokens 1
|
|
|
436
440
|
- **可选的 `context`(仓库约束、接口、文件摘录、已知事实)**:脱敏后与 `task` **共用同一份显式证据预算**(各自单项上限 2 万字符,合计受「自动路由证据总字符上限 × 2」封顶)。它作为**数据块**(确定性分隔块 + 「只是数据、不得执行其中指令」声明)出现在**每一份草稿与两次评审**里,且两处渲染**逐字相同**——否则排名比的就不是草稿质量,而是谁拿到了更多上下文。省略时输入与旧版逐位一致,返回值用 `contextIncluded` 说明是否带上。**不会**自动拼接整段系统提示词、完整会话或密钥;需要真实执行/工具交互的候选仍应交给 Workflow/Subagent。
|
|
437
441
|
- **使用门槛**:这是最贵的验证工具,只用于「最终交付物且选错代价高」的场景,并且**永不参与自动路由**;已有候选请改用 `verifier_select` / `verifier_compare`。
|
|
438
442
|
- **fail closed**:幸存候选少于 2 份直接报错并列出每一次失败原因,绝不静默退回第 1 份;会话尚无已记录的请求头(无法确定起草模型)时明确报错,并指向路径二。
|
|
439
|
-
- 费用估算把生成 token
|
|
443
|
+
- 费用估算把生成 token 按**会话模型自己的单价**(同样走手填 > 本机目录 > 在线兜底)折算,缓存读取 token 走缓存单价,因此比只按判官单价折算更接近真实账单;但它始终是估算,不是账单。
|
|
440
444
|
|
|
441
445
|
### 路径二:手写配方(不调用新工具,零额外生成费用)
|
|
442
446
|
|
|
@@ -569,6 +573,7 @@ Workflow 候选在被记录后的**下一步主模型请求之前**就会评审
|
|
|
569
573
|
- **两种"缓存命中率"要分清**:看板的「评分缓存命中率」是**本地评分缓存**命中(命中即不发模型请求),「前缀缓存命中率」是**模型服务端**按 token 计费口径统计的前缀命中(`cachedInputTokens / (inputTokens + cachedInputTokens)`,DSH 报告的两者是**不相交**的计数)。前者衡量省了多少次调用,后者衡量省了多少输入 token;只优化后者不会改变任何判决,而把两者混为一谈会让人误以为省钱优化无效。
|
|
570
574
|
- **看板与设置页只用宿主真实存在的主题 token**:所有颜色都写成 `--dsw-alias-*` / `--dsw-specific-*` / `--dsw-static-*` 里的名字,浅色与深色由宿主 token 表解析,不读主题标记、不手写两套色。原因见 `.agents/notes/implemented/bug-fix/2026-09-14-client-theme-tokens-and-activity-chip-geometry.md`:CSS 对取不到值的 `var()` **静默丢弃声明**,所以写错 token 名既不会被构建、类型检查也不会被单测发现,历史上就因此让看板在浅色主题下画出一片深色卡片。`src/client.test.ts` 里的 `client design tokens` 用例现在会双向校验这份名单(用了未登记的名字、或登记了没用的名字,都会失败)。
|
|
571
575
|
- **能力记忆**:当某个 Provider/Model 明确拒绝 `logprobs` 参数后,插件会记住该能力探测结果,避免后续每次调用重复报错。探测结果按话题持久化到 verifier 目录的 `capabilities-v1.json`(24 小时 TTL 后自动重新探测),随话题一并删除;跨进程与会话恢复不再重复探测,首次降级并发窗口内的相同请求也会合并在途调用、不重复计费。
|
|
576
|
+
- **自动定价的三层来源**(`src/pricing.ts`):手填单价 > 本机 pi-ai 模型目录 > models.dev(可选)。宿主**不向插件暴露任何价格**——`@deepseek-ai/dsh-llm` 的 usage 与 `resolveModel` 没有价格字段,`llm-pi-ai` 还明确把 pi-ai 的 cost 元数据归零("no consumer reports spend")——所以价格只能由插件自己找。匹配**只认精确的 provider + model**:同一个 model id 在 models.dev 上有 21 家 provider 挂牌、价差 6.5 倍(0.10/0.40 ↔ 0.65/1.45),跨 provider 取价等于往成本列写一个编造的数字,插件因此**绝不猜**;转售路由要用 `priceProviderOverride` 明确指定跟随谁的挂牌价,否则老老实实记为未定价(0)。两层目录都是「读不到就退到下一层」,任何一种失败都不会影响判定。判官自检会回报当前判官实际生效的单价与来源。
|
|
572
577
|
|
|
573
578
|
## 隐私与数据安全边界
|
|
574
579
|
|
package/lib/client.js
CHANGED
|
@@ -16,17 +16,17 @@ window.__ModuleLoader__.load({
|
|
|
16
16
|
"settings.nsUnregistered": "未注册 Verifier 设置命名空间,请重启 DSH 宿主。",
|
|
17
17
|
"section.tools": "工具",
|
|
18
18
|
"field.enabled.title": "启用 Verifier 工具",
|
|
19
|
-
"field.enabled.helpOn": "允许 Agent
|
|
20
|
-
"field.enabled.helpOff": "停用后,所有
|
|
19
|
+
"field.enabled.helpOn": "允许 Agent 调用 Verifier 评审工具并向裁判模型发起请求。",
|
|
20
|
+
"field.enabled.helpOff": "停用后,所有 Verifier 工具均不可用并立即报错。",
|
|
21
21
|
"field.enabled.warnDisabled": "verifier_compare、verifier_select、verifier_track、verifier_best_of_n 和 verifier_current_session 当前不可用。",
|
|
22
22
|
"section.autoVerify": "自动验收",
|
|
23
23
|
"field.autoVerifyMode.title": "调用策略",
|
|
24
|
-
"field.autoVerifyMode.help": "
|
|
24
|
+
"field.autoVerifyMode.help": "手动:仅供主动调用;智能(推荐):发现明确证据时自动复核与验收;严格:关键操作后强制全面复核与验收。",
|
|
25
25
|
"field.autoVerifyMode.manual": "手动",
|
|
26
26
|
"field.autoVerifyMode.smart": "智能(推荐)",
|
|
27
27
|
"field.autoVerifyMode.strict": "严格",
|
|
28
28
|
"field.criteriaPreset.title": "验收判据",
|
|
29
|
-
"field.criteriaPreset.help": "
|
|
29
|
+
"field.criteriaPreset.help": "自动复核与最终验收使用的评分标准预设。不同预设针对不同的工作任务场景。",
|
|
30
30
|
"field.criteriaPreset.coding": "编码(默认)",
|
|
31
31
|
"field.criteriaPreset.debug": "调试排错",
|
|
32
32
|
"field.criteriaPreset.research": "研究问答",
|
|
@@ -38,63 +38,63 @@ window.__ModuleLoader__.load({
|
|
|
38
38
|
"field.criteriaPreset.sampleA": "(示例轨迹 A)运行 pytest -k login,输出 1 failed … 修改 auth.py … 再次运行,输出 1 passed。",
|
|
39
39
|
"field.criteriaPreset.sampleB": "(示例轨迹 B)已经改好了,应该没问题。",
|
|
40
40
|
"field.criteriaFile.title": "判据文件",
|
|
41
|
-
"field.criteriaFile.help": "Markdown
|
|
41
|
+
"field.criteriaFile.help": "自定义 Markdown 判据文件路径。若解析失败会自动回退为默认「编码」判据;判据条数较多时建议适当调高模型调用预算。",
|
|
42
42
|
"field.autoRouteSemantic.title": "混合语义路由",
|
|
43
|
-
"field.autoRouteSemantic.help": "
|
|
43
|
+
"field.autoRouteSemantic.help": "缺少显式标记时,由裁判模型智能识别上下文,自动发起方案优选或进度跟踪。",
|
|
44
44
|
"field.autoRouteMinConfidence.title": "语义路由置信度",
|
|
45
|
-
"field.autoRouteMinConfidence.help": "
|
|
45
|
+
"field.autoRouteMinConfidence.help": "触发自动路由所需的最低语义置信度(0–1,建议保持 0.9)。低于该值不触发。",
|
|
46
46
|
"field.autoRouteMaxCandidates.title": "最多候选数",
|
|
47
|
-
"field.autoRouteMaxCandidates.help": "
|
|
47
|
+
"field.autoRouteMaxCandidates.help": "多方案优选(select)单次最多对比的候选方案数(3–16)。",
|
|
48
48
|
"field.autoRouteMaxPerTask.title": "每任务最多路由",
|
|
49
|
-
"field.autoRouteMaxPerTask.help": "
|
|
49
|
+
"field.autoRouteMaxPerTask.help": "单个任务中自动对比与进度跟踪的最大尝试次数(独立计数,不消耗最终验收额度)。",
|
|
50
50
|
"field.autoRouteMaxPerSession.title": "每会话最多路由",
|
|
51
|
-
"field.autoRouteMaxPerSession.help": "
|
|
51
|
+
"field.autoRouteMaxPerSession.help": "整个会话中自动路由的最大尝试总次数。",
|
|
52
52
|
"field.autoTrackCompletionThreshold.title": "进度完成阈值",
|
|
53
|
-
"field.autoTrackCompletionThreshold.help": "
|
|
53
|
+
"field.autoTrackCompletionThreshold.help": "进度检查点达标阈值(0–1)。最新进度低于此值时,将提示 Agent 尚未完成并继续执行。",
|
|
54
54
|
"field.autoRouteMaxItemChars.title": "单项证据字符上限",
|
|
55
|
-
"field.autoRouteMaxItemChars.help": "
|
|
55
|
+
"field.autoRouteMaxItemChars.help": "单次路由中单个候选方案或执行步骤脱敏后的最大字符数。",
|
|
56
56
|
"field.autoRouteMaxInputChars.title": "路由证据总字符上限",
|
|
57
|
-
"field.autoRouteMaxInputChars.help": "
|
|
57
|
+
"field.autoRouteMaxInputChars.help": "单次路由对比中所有候选证据的脱敏字符总上限。",
|
|
58
58
|
"field.autoMaxModelCallsPerTask.title": "每任务模型调用预算",
|
|
59
|
-
"field.autoMaxModelCallsPerTask.help": "
|
|
59
|
+
"field.autoMaxModelCallsPerTask.help": "单任务内所有自动评审阶段(路由、对比、最终验收)共享的模型调用上限。",
|
|
60
60
|
"field.autoMaxModelCallsPerSession.title": "每会话模型调用预算",
|
|
61
|
-
"field.autoMaxModelCallsPerSession.help": "
|
|
61
|
+
"field.autoMaxModelCallsPerSession.help": "整个会话内所有自动评审累计允许的最大模型调用总次数。",
|
|
62
62
|
"field.autoVerifyThreshold.title": "通过阈值",
|
|
63
|
-
"field.autoVerifyThreshold.help": "
|
|
63
|
+
"field.autoVerifyThreshold.help": "任务通过最终验收所需的最低得分(0–1)。得分未达标时会要求 Agent 继续修复。",
|
|
64
64
|
"field.autoVerifyRepeats.title": "路由评估轮次",
|
|
65
|
-
"field.autoVerifyRepeats.help": "
|
|
65
|
+
"field.autoVerifyRepeats.help": "自动方案对比每项判据的评分轮数(默认 1,增加可提高稳定性)。",
|
|
66
66
|
"field.autoTrackRepeats.title": "进度跟踪轮次",
|
|
67
|
-
"field.autoTrackRepeats.help": "
|
|
67
|
+
"field.autoTrackRepeats.help": "进度跟踪的评分采样轮数(默认 3)。多次采样取平均可有效抑制单次随机误差。",
|
|
68
68
|
"field.autoVerifyFinalRepeats.title": "最终验收轮次",
|
|
69
|
-
"field.autoVerifyFinalRepeats.help": "
|
|
69
|
+
"field.autoVerifyFinalRepeats.help": "最终验收每项判据的评分轮数(默认 2)。偶数轮会自动交换 A/B 位置以消除位置偏好。",
|
|
70
70
|
"field.autoVerifyMinToolCalls.title": "智能模式最少工具调用",
|
|
71
|
-
"field.autoVerifyMinToolCalls.help": "
|
|
71
|
+
"field.autoVerifyMinToolCalls.help": "触发智能验收所需的最少非 Verifier 工具调用数(需包含实际操作与成功结果)。",
|
|
72
72
|
"field.autoVerifyMaxChars.title": "最大证据字符",
|
|
73
|
-
"field.autoVerifyMaxChars.help": "
|
|
73
|
+
"field.autoVerifyMaxChars.help": "最终验收时截取并发送给裁判的最近会话轨迹字符上限。",
|
|
74
74
|
"field.autoVerifyMaxPerTask.title": "每任务最多验收",
|
|
75
|
-
"field.autoVerifyMaxPerTask.help": "
|
|
75
|
+
"field.autoVerifyMaxPerTask.help": "单任务最终验收的最大尝试次数(独立计数,防止低分修复陷入死循环)。",
|
|
76
76
|
"field.autoVerifyMaxPerSession.title": "每会话最多验收",
|
|
77
|
-
"field.autoVerifyMaxPerSession.help": "
|
|
78
|
-
"field.autoVerify.warnNotice": "
|
|
77
|
+
"field.autoVerifyMaxPerSession.help": "整个会话中最终验收的最大尝试总次数。",
|
|
78
|
+
"field.autoVerify.warnNotice": "自动评审按「多项优选 → 两项对比 → 进度跟踪 → 最终验收」顺序进行。脱敏后的任务信息、执行轨迹与工具输出将发送给裁判模型;进度或评分不足时将提示继续完善,验收未通过将要求修复后重新验证。",
|
|
79
79
|
"field.autoMaxModelCallsPerTask.warnBudget": "当前单任务预算为 {current} 次模型调用,低于 {judges} 位裁判完整锦标赛所需的最差情况({required} 次)。建议调大该预算以避免自动路由过早耗尽。",
|
|
80
80
|
"field.autoMaxModelCallsPerSession.warnBudget": "当前会话预算为 {current} 次模型调用,低于 {judges} 位裁判推荐的最差情况({required} 次)。建议调大该预算以避免会话验证过早耗尽。",
|
|
81
81
|
"section.model": "裁判模型",
|
|
82
82
|
"field.provider.title": "供应商",
|
|
83
|
-
"field.provider.help": "
|
|
83
|
+
"field.provider.help": "裁判模型的供应商(须已在 DSH「模型」中配置)。",
|
|
84
84
|
"field.model.title": "模型",
|
|
85
|
-
"field.model.help": "
|
|
85
|
+
"field.model.help": "担任独立裁判的具体模型。",
|
|
86
86
|
"field.reasoningEffort.title": "推理强度",
|
|
87
|
-
"field.reasoningEffort.help": "
|
|
87
|
+
"field.reasoningEffort.help": "推理模型的思考强度等级(low / medium / high),留空使用默认值。",
|
|
88
88
|
"field.reasoningEffort.default": "模型默认",
|
|
89
89
|
"field.maxTokens.title": "最大输出 Token",
|
|
90
|
-
"field.maxTokens.help": "
|
|
90
|
+
"field.maxTokens.help": "裁判模型单次评审回复的最大 Token 上限。",
|
|
91
91
|
"field.temperature.title": "裁判采样温度",
|
|
92
|
-
"field.temperature.help": "
|
|
92
|
+
"field.temperature.help": "裁判调用的采样温度(0–2)。较低值(如 0.2)可提高评分的一致性与稳定性。",
|
|
93
93
|
"field.label.title": "裁判标签",
|
|
94
|
-
"field.label.help": "
|
|
94
|
+
"field.label.help": "在看板和统计明细中显示的自定义裁判别名,留空时使用模型名称。",
|
|
95
95
|
"field.label.placeholder": "默认使用模型名称",
|
|
96
96
|
"field.extraJudges.title": "附加裁判",
|
|
97
|
-
"field.extraJudges.help": "
|
|
97
|
+
"field.extraJudges.help": "最多添加 4 个不同模型组成多裁判评审团,采用中位数综合打分以消除单一模型偏好。",
|
|
98
98
|
"field.extraJudges.add": "添加裁判",
|
|
99
99
|
"field.extraJudges.remove": "删除",
|
|
100
100
|
"field.extraJudges.labelTitle": "标签",
|
|
@@ -108,22 +108,30 @@ window.__ModuleLoader__.load({
|
|
|
108
108
|
"field.extraJudges.conflictDuplicate": "附加裁判 #{index} 与附加裁判 #{other} 重复({id}),请选择不同模型。",
|
|
109
109
|
"section.execution": "执行",
|
|
110
110
|
"field.maxConcurrency.title": "最大并发",
|
|
111
|
-
"field.maxConcurrency.help": "所有
|
|
111
|
+
"field.maxConcurrency.help": "所有 Verifier 评审请求共享的最大并发数。",
|
|
112
112
|
"field.maxRetries.title": "最多重试",
|
|
113
|
-
"field.maxRetries.help": "
|
|
113
|
+
"field.maxRetries.help": "遇到限流、超时或临时网络错误时的重试次数。",
|
|
114
114
|
"field.retryBaseDelayMs.title": "重试基础延迟",
|
|
115
|
-
"field.retryBaseDelayMs.help": "
|
|
115
|
+
"field.retryBaseDelayMs.help": "触发网络重试时的基础退避等待时间(毫秒)。",
|
|
116
116
|
"field.timeoutMs.title": "请求超时",
|
|
117
|
-
"field.timeoutMs.help": "
|
|
117
|
+
"field.timeoutMs.help": "单次裁判模型调用的超时时间(毫秒)。",
|
|
118
118
|
"field.cacheDir.title": "缓存相对目录",
|
|
119
|
-
"field.cacheDir.help": "
|
|
119
|
+
"field.cacheDir.help": "评分结果持久化缓存的相对存放路径(相对于话题目录)。",
|
|
120
120
|
"field.cacheMaxEntries.title": "缓存条目上限",
|
|
121
|
-
"field.cacheMaxEntries.help": "
|
|
121
|
+
"field.cacheMaxEntries.help": "本地持久化评分缓存保留的最大条目数,超限时自动淘汰旧记录。",
|
|
122
122
|
"section.cost": "费用估算",
|
|
123
123
|
"field.estimatedInputUsdPerMillion.title": "输入价格",
|
|
124
|
-
"field.estimatedInputUsdPerMillion.help": "每百万输入 Token
|
|
124
|
+
"field.estimatedInputUsdPerMillion.help": "每百万输入 Token 的美元单价(手动指定,用于看板费用估算)。",
|
|
125
125
|
"field.estimatedOutputUsdPerMillion.title": "输出价格",
|
|
126
|
-
"field.estimatedOutputUsdPerMillion.help": "每百万输出 Token
|
|
126
|
+
"field.estimatedOutputUsdPerMillion.help": "每百万输出 Token 的美元单价(手动指定,用于看板费用估算)。",
|
|
127
|
+
"field.estimatedCachedInputUsdPerMillion.title": "缓存读取价格",
|
|
128
|
+
"field.estimatedCachedInputUsdPerMillion.help": "每百万命中缓存的输入 Token 美元单价。设为 0 则按普通输入价格计算。",
|
|
129
|
+
"field.autoPriceFromCatalog.title": "从本机模型目录自动定价",
|
|
130
|
+
"field.autoPriceFromCatalog.help": "优先从本机模型目录自动匹配对应模型的 Token 单价;手动填写的价格优先生效。",
|
|
131
|
+
"field.autoPriceOnline.title": "在线价格库兜底",
|
|
132
|
+
"field.autoPriceOnline.help": "本机未收录时,通过 models.dev 在线价格库精确匹配单价并缓存 24 小时。",
|
|
133
|
+
"field.priceProviderOverride.title": "价格来源 Provider",
|
|
134
|
+
"field.priceProviderOverride.help": "第三方转售或聚合模型未收录时,可填写参考供应商 ID(如 openrouter)折算单价,留空记为 0。",
|
|
127
135
|
"settings.catalogFailures": "部分模型目录读取失败",
|
|
128
136
|
"settings.saved": "设置已保存。",
|
|
129
137
|
"settings.reload": "重新载入",
|
|
@@ -259,21 +267,21 @@ window.__ModuleLoader__.load({
|
|
|
259
267
|
"guide.verifier.title": "Verifier 统计",
|
|
260
268
|
"guide.verifier.desc": "大模型复核工具调用、耗时与成本统计",
|
|
261
269
|
"field.autoVerifyTeamTasks.title": "自动验收 Team 任务",
|
|
262
|
-
"field.autoVerifyTeamTasks.help": "
|
|
270
|
+
"field.autoVerifyTeamTasks.help": "多 Agent 团队任务状态变更或标记完成时,自动触发进度跟踪与任务验收。",
|
|
263
271
|
"field.autoVerifyPlanMode.title": "计划模式自动预审",
|
|
264
|
-
"field.autoVerifyPlanMode.help": "
|
|
272
|
+
"field.autoVerifyPlanMode.help": "Agent 退出计划模式提交计划前,自动由裁判模型预审其可行性与潜在风险。",
|
|
265
273
|
"field.autoProcessSelection.title": "过程选优(受控)",
|
|
266
|
-
"field.autoProcessSelection.help": "
|
|
274
|
+
"field.autoProcessSelection.help": "任务连续两次验证运行失败时,自动额外生成一份备选回复并由裁判挑选更优方案,辅助打破死循环。",
|
|
267
275
|
"field.autoProcessFailureContext.title": "备选带上失败证据",
|
|
268
276
|
"field.autoProcessCandidates.title": "过程选优候选数",
|
|
269
|
-
"field.autoProcessCandidates.help": "
|
|
277
|
+
"field.autoProcessCandidates.help": "过程选优生成的候选总数(含原回复,默认 2)。设为 3 或 4 时将采用多轮对决,消耗更多调用。",
|
|
270
278
|
"field.autoProcessAlternativeModel.title": "备选用另一个模型",
|
|
271
|
-
"field.autoProcessAlternativeModel.help": "
|
|
272
|
-
"field.autoProcessFailureContext.help": "
|
|
279
|
+
"field.autoProcessAlternativeModel.help": "用于生成备选方案的指定模型(格式 provider/model)。留空则使用当前会话模型重新采样。",
|
|
280
|
+
"field.autoProcessFailureContext.help": "生成备选方案时附带前两次失败的报错日志,促使模型尝试不同的解决路径。",
|
|
273
281
|
"field.captureDecisions.title": "保存决策快照",
|
|
274
|
-
"field.captureDecisions.help": "
|
|
282
|
+
"field.captureDecisions.help": "将裁判调用的提示词与原始回复脱敏后保存在本话题下,用于看板中追溯评审理由。",
|
|
275
283
|
"field.autoVerifySubagents.title": "同时验收子 Agent",
|
|
276
|
-
"field.autoVerifySubagents.help": "
|
|
284
|
+
"field.autoVerifySubagents.help": "是否对派生的子 Agent 会话同样执行自动复核与验收。开启后会消耗更多裁判额度。",
|
|
277
285
|
"section.routing": "自动路由",
|
|
278
286
|
"section.budgets": "预算与限额",
|
|
279
287
|
"section.storage": "存储与观测",
|
|
@@ -325,17 +333,17 @@ window.__ModuleLoader__.load({
|
|
|
325
333
|
"settings.nsUnregistered": "Verifier settings namespace is not registered. Restart the DSH host.",
|
|
326
334
|
"section.tools": "Tools",
|
|
327
335
|
"field.enabled.title": "Enable Verifier Tools",
|
|
328
|
-
"field.enabled.helpOn": "Allows the Agent to call
|
|
329
|
-
"field.enabled.helpOff": "When disabled, all
|
|
336
|
+
"field.enabled.helpOn": "Allows the Agent to call Verifier tools and send review requests to the judge model.",
|
|
337
|
+
"field.enabled.helpOff": "When disabled, all Verifier tools will be unavailable and return an error.",
|
|
330
338
|
"field.enabled.warnDisabled": "verifier_compare, verifier_select, verifier_track, verifier_best_of_n, and verifier_current_session are currently unavailable.",
|
|
331
339
|
"section.autoVerify": "Automatic Verification",
|
|
332
340
|
"field.autoVerifyMode.title": "Invocation Policy",
|
|
333
|
-
"field.autoVerifyMode.help": "Manual
|
|
341
|
+
"field.autoVerifyMode.help": "Manual: explicit calls only; Smart (recommended): automatically reviews and gates when sufficient evidence is present; Strict: enforces full review and acceptance after any consequential action.",
|
|
334
342
|
"field.autoVerifyMode.manual": "Manual",
|
|
335
343
|
"field.autoVerifyMode.smart": "Smart (Recommended)",
|
|
336
344
|
"field.autoVerifyMode.strict": "Strict",
|
|
337
345
|
"field.criteriaPreset.title": "Acceptance Rubric",
|
|
338
|
-
"field.criteriaPreset.help": "
|
|
346
|
+
"field.criteriaPreset.help": "Evaluation rubric preset for automatic review and final acceptance. Different presets tailor to different tasks.",
|
|
339
347
|
"field.criteriaPreset.coding": "Coding (default)",
|
|
340
348
|
"field.criteriaPreset.debug": "Debugging",
|
|
341
349
|
"field.criteriaPreset.research": "Research Q&A",
|
|
@@ -347,63 +355,63 @@ window.__ModuleLoader__.load({
|
|
|
347
355
|
"field.criteriaPreset.sampleA": "(sample trajectory A) Ran pytest -k login: 1 failed … changed auth.py … ran it again: 1 passed.",
|
|
348
356
|
"field.criteriaPreset.sampleB": "(sample trajectory B) Already fixed it, should be fine.",
|
|
349
357
|
"field.criteriaFile.title": "Criteria File",
|
|
350
|
-
"field.criteriaFile.help": "Path to a
|
|
358
|
+
"field.criteriaFile.help": "Path to a custom Markdown rubric file. Automatically falls back to the default \"coding\" rubric on failure. Increase model call budget if defining more than 3 criteria.",
|
|
351
359
|
"field.autoRouteSemantic.title": "Hybrid Semantic Routing",
|
|
352
|
-
"field.autoRouteSemantic.help": "When
|
|
360
|
+
"field.autoRouteSemantic.help": "When explicit clues are absent, the judge model analyzes context to identify targets for candidate comparison or progress tracking.",
|
|
353
361
|
"field.autoRouteMinConfidence.title": "Semantic Route Confidence",
|
|
354
|
-
"field.autoRouteMinConfidence.help": "Minimum confidence required for semantic
|
|
362
|
+
"field.autoRouteMinConfidence.help": "Minimum confidence (0–1, 0.9 recommended) required for semantic routing before triggering reviews.",
|
|
355
363
|
"field.autoRouteMaxCandidates.title": "Max Candidates",
|
|
356
|
-
"field.autoRouteMaxCandidates.help": "Maximum number of
|
|
364
|
+
"field.autoRouteMaxCandidates.help": "Maximum number of candidate options evaluated in a single candidate selection (3–16).",
|
|
357
365
|
"field.autoRouteMaxPerTask.title": "Max Routes per Task",
|
|
358
|
-
"field.autoRouteMaxPerTask.help": "
|
|
366
|
+
"field.autoRouteMaxPerTask.help": "Maximum automatic comparison and progress tracking attempts per task (counted separately from final acceptance).",
|
|
359
367
|
"field.autoRouteMaxPerSession.title": "Max Routes per Session",
|
|
360
|
-
"field.autoRouteMaxPerSession.help": "
|
|
368
|
+
"field.autoRouteMaxPerSession.help": "Maximum automatic routing attempts allowed across the entire session.",
|
|
361
369
|
"field.autoTrackCompletionThreshold.title": "Progress Completion Threshold",
|
|
362
|
-
"field.autoTrackCompletionThreshold.help": "
|
|
370
|
+
"field.autoTrackCompletionThreshold.help": "Progress checkpoint threshold (0–1). When the latest progress is below this value, the Agent is prompted to continue.",
|
|
363
371
|
"field.autoRouteMaxItemChars.title": "Max Chars per Route Item",
|
|
364
|
-
"field.autoRouteMaxItemChars.help": "Maximum sanitized
|
|
372
|
+
"field.autoRouteMaxItemChars.help": "Maximum sanitized characters allowed for a single candidate or step in a route review.",
|
|
365
373
|
"field.autoRouteMaxInputChars.title": "Total Route Input Chars Cap",
|
|
366
|
-
"field.autoRouteMaxInputChars.help": "Total character budget across all candidates
|
|
374
|
+
"field.autoRouteMaxInputChars.help": "Total sanitized character budget across all candidates and steps in a single route review.",
|
|
367
375
|
"field.autoMaxModelCallsPerTask.title": "Model Call Budget per Task",
|
|
368
|
-
"field.autoMaxModelCallsPerTask.help": "
|
|
376
|
+
"field.autoMaxModelCallsPerTask.help": "Maximum model calls shared across all automatic review stages (routing, comparison, final acceptance) per task.",
|
|
369
377
|
"field.autoMaxModelCallsPerSession.title": "Model Call Budget per Session",
|
|
370
|
-
"field.autoMaxModelCallsPerSession.help": "
|
|
378
|
+
"field.autoMaxModelCallsPerSession.help": "Maximum cumulative model calls allowed for all automatic reviews across the entire session.",
|
|
371
379
|
"field.autoVerifyRepeats.title": "Routing Repeats",
|
|
372
|
-
"field.autoVerifyRepeats.help": "Scoring repeats per criterion for
|
|
380
|
+
"field.autoVerifyRepeats.help": "Scoring repeats per criterion for candidate comparison (default 1, higher values increase stability).",
|
|
373
381
|
"field.autoTrackRepeats.title": "Progress Repeats",
|
|
374
|
-
"field.autoTrackRepeats.help": "
|
|
382
|
+
"field.autoTrackRepeats.help": "Number of scoring rounds for progress tracking (default 3). Averaging multiple rounds reduces sampling noise.",
|
|
375
383
|
"field.autoVerifyFinalRepeats.title": "Final Acceptance Repeats",
|
|
376
|
-
"field.autoVerifyFinalRepeats.help": "Scoring
|
|
384
|
+
"field.autoVerifyFinalRepeats.help": "Scoring rounds per criterion for final acceptance (default 2). Even rounds swap A/B positions to cancel position bias.",
|
|
377
385
|
"field.autoVerifyThreshold.title": "Pass Threshold",
|
|
378
|
-
"field.autoVerifyThreshold.help": "
|
|
386
|
+
"field.autoVerifyThreshold.help": "Minimum score (0–1) required to pass final acceptance. Agent will be prompted to remediate if below this score.",
|
|
379
387
|
"field.autoVerifyMinToolCalls.title": "Min Tool Calls (Smart Mode)",
|
|
380
|
-
"field.autoVerifyMinToolCalls.help": "
|
|
388
|
+
"field.autoVerifyMinToolCalls.help": "Minimum non-Verifier tool calls required to trigger smart acceptance (must include consequential actions and success).",
|
|
381
389
|
"field.autoVerifyMaxChars.title": "Max Evidence Characters",
|
|
382
|
-
"field.autoVerifyMaxChars.help": "Maximum recent session
|
|
390
|
+
"field.autoVerifyMaxChars.help": "Maximum recent session trajectory characters retained and sent to the judge for final acceptance.",
|
|
383
391
|
"field.autoVerifyMaxPerTask.title": "Max Verifications per Task",
|
|
384
|
-
"field.autoVerifyMaxPerTask.help": "
|
|
392
|
+
"field.autoVerifyMaxPerTask.help": "Maximum final acceptance attempts per task (counted separately to prevent infinite remediation loops).",
|
|
385
393
|
"field.autoVerifyMaxPerSession.title": "Max Verifications per Session",
|
|
386
|
-
"field.autoVerifyMaxPerSession.help": "
|
|
387
|
-
"field.autoVerify.warnNotice": "Automatic
|
|
394
|
+
"field.autoVerifyMaxPerSession.help": "Maximum final acceptance attempts allowed across the entire session.",
|
|
395
|
+
"field.autoVerify.warnNotice": "Automatic review follows the sequence: candidate selection → comparison → progress tracking → final acceptance. Sanitized task info, trajectories, and tool outputs are sent to the judge; insufficient progress prompts continuation, and failed acceptance requires remediation.",
|
|
388
396
|
"field.autoMaxModelCallsPerTask.warnBudget": "Current task budget ({current} calls) is below the worst-case requirement ({required} calls) for {judges} judge(s) in a full tournament. Consider increasing it to avoid premature budget exhaustion.",
|
|
389
397
|
"field.autoMaxModelCallsPerSession.warnBudget": "Current session budget ({current} calls) is below the worst-case requirement ({required} calls) for {judges} judge(s). Consider increasing it to avoid premature budget exhaustion.",
|
|
390
398
|
"section.model": "Judge Model",
|
|
391
399
|
"field.provider.title": "Provider",
|
|
392
|
-
"field.provider.help": "
|
|
400
|
+
"field.provider.help": "Model provider of the judge (must be configured in DSH \"Models\").",
|
|
393
401
|
"field.model.title": "Model",
|
|
394
|
-
"field.model.help": "Specific model
|
|
402
|
+
"field.model.help": "Specific model to serve as the independent judge.",
|
|
395
403
|
"field.reasoningEffort.title": "Reasoning Effort",
|
|
396
|
-
"field.reasoningEffort.help": "Leave empty to use
|
|
404
|
+
"field.reasoningEffort.help": "Reasoning effort level (low / medium / high). Leave empty to use model default.",
|
|
397
405
|
"field.reasoningEffort.default": "Model Default",
|
|
398
406
|
"field.maxTokens.title": "Max Output Tokens",
|
|
399
|
-
"field.maxTokens.help": "Maximum tokens allowed in a single judge
|
|
407
|
+
"field.maxTokens.help": "Maximum output tokens allowed in a single judge completion.",
|
|
400
408
|
"field.temperature.title": "Judge Sampling Temperature",
|
|
401
|
-
"field.temperature.help": "Sampling temperature for judge
|
|
409
|
+
"field.temperature.help": "Sampling temperature for judge calls (0–2). Lower values (e.g. 0.2) improve verdict consistency and stability.",
|
|
402
410
|
"field.label.title": "Judge Label",
|
|
403
|
-
"field.label.help": "
|
|
411
|
+
"field.label.help": "Custom display name for the judge in dashboards and records. Defaults to the model name.",
|
|
404
412
|
"field.label.placeholder": "Defaults to model name",
|
|
405
413
|
"field.extraJudges.title": "Extra Judges",
|
|
406
|
-
"field.extraJudges.help": "Add up to 4 extra judge models for ensemble
|
|
414
|
+
"field.extraJudges.help": "Add up to 4 extra judge models for an ensemble review, using median scores to mitigate individual bias.",
|
|
407
415
|
"field.extraJudges.add": "Add Judge",
|
|
408
416
|
"field.extraJudges.remove": "Remove",
|
|
409
417
|
"field.extraJudges.labelTitle": "Label",
|
|
@@ -417,22 +425,30 @@ window.__ModuleLoader__.load({
|
|
|
417
425
|
"field.extraJudges.conflictDuplicate": "Extra judge #{index} duplicates extra judge #{other} ({id}). Please select a different model.",
|
|
418
426
|
"section.execution": "Execution",
|
|
419
427
|
"field.maxConcurrency.title": "Max Concurrency",
|
|
420
|
-
"field.maxConcurrency.help": "Maximum concurrent requests shared across all
|
|
428
|
+
"field.maxConcurrency.help": "Maximum concurrent requests shared across all Verifier reviews.",
|
|
421
429
|
"field.maxRetries.title": "Max Retries",
|
|
422
|
-
"field.maxRetries.help": "
|
|
430
|
+
"field.maxRetries.help": "Maximum retry attempts on rate limits, timeouts, or transient network errors.",
|
|
423
431
|
"field.retryBaseDelayMs.title": "Retry Base Delay",
|
|
424
|
-
"field.retryBaseDelayMs.help": "Base wait time before retrying
|
|
432
|
+
"field.retryBaseDelayMs.help": "Base backoff wait time (ms) before retrying network errors.",
|
|
425
433
|
"field.timeoutMs.title": "Request Timeout",
|
|
426
|
-
"field.timeoutMs.help": "Timeout for a single model request
|
|
434
|
+
"field.timeoutMs.help": "Timeout duration (ms) for a single judge model request.",
|
|
427
435
|
"field.cacheDir.title": "Cache Relative Directory",
|
|
428
|
-
"field.cacheDir.help": "Relative directory for persistent score cache (relative to topic directory).
|
|
436
|
+
"field.cacheDir.help": "Relative directory path for persistent score cache (relative to topic directory).",
|
|
429
437
|
"field.cacheMaxEntries.title": "Max Cache Entries",
|
|
430
|
-
"field.cacheMaxEntries.help": "Maximum entries retained in the local persistent score cache.",
|
|
438
|
+
"field.cacheMaxEntries.help": "Maximum entries retained in the local persistent score cache before pruning oldest records.",
|
|
431
439
|
"section.cost": "Cost Estimation",
|
|
432
440
|
"field.estimatedInputUsdPerMillion.title": "Input Price",
|
|
433
|
-
"field.estimatedInputUsdPerMillion.help": "USD price per million input tokens
|
|
441
|
+
"field.estimatedInputUsdPerMillion.help": "USD price per million input tokens (manually specified for dashboard cost estimation).",
|
|
434
442
|
"field.estimatedOutputUsdPerMillion.title": "Output Price",
|
|
435
|
-
"field.estimatedOutputUsdPerMillion.help": "USD price per million output tokens
|
|
443
|
+
"field.estimatedOutputUsdPerMillion.help": "USD price per million output tokens (manually specified for dashboard cost estimation).",
|
|
444
|
+
"field.estimatedCachedInputUsdPerMillion.title": "Cached Input Price",
|
|
445
|
+
"field.estimatedCachedInputUsdPerMillion.help": "USD price per million cached prompt tokens. Set to 0 to calculate using standard input price.",
|
|
446
|
+
"field.autoPriceFromCatalog.title": "Auto Price From Catalog",
|
|
447
|
+
"field.autoPriceFromCatalog.help": "Automatically retrieves token prices from the local pi-ai model catalog. Manually entered prices take priority.",
|
|
448
|
+
"field.autoPriceOnline.title": "Online Price Lookup",
|
|
449
|
+
"field.autoPriceOnline.help": "When missing locally, queries the online models.dev database for exact price matching (cached for 24 hours).",
|
|
450
|
+
"field.priceProviderOverride.title": "Price Source Provider",
|
|
451
|
+
"field.priceProviderOverride.help": "For unlisted reseller or aggregator routes, specify a reference provider ID (e.g. openrouter) to convert pricing.",
|
|
436
452
|
"settings.catalogFailures": "Some model catalogs failed to load",
|
|
437
453
|
"settings.saved": "Settings saved.",
|
|
438
454
|
"settings.reload": "Reload",
|
|
@@ -568,21 +584,21 @@ window.__ModuleLoader__.load({
|
|
|
568
584
|
"guide.verifier.title": "Verifier Stats",
|
|
569
585
|
"guide.verifier.desc": "LLM verifier tool calls, duration and cost statistics",
|
|
570
586
|
"field.autoVerifyTeamTasks.title": "Verify Team Tasks",
|
|
571
|
-
"field.autoVerifyTeamTasks.help": "Automatically
|
|
587
|
+
"field.autoVerifyTeamTasks.help": "Automatically routes progress tracking and acceptance when Agent Teams tasks change status or complete.",
|
|
572
588
|
"field.autoVerifyPlanMode.title": "Plan Mode Pre-verification",
|
|
573
|
-
"field.autoVerifyPlanMode.help": "Automatically pre-
|
|
589
|
+
"field.autoVerifyPlanMode.help": "Automatically pre-verifies plan feasibility and risks before exit_plan_mode submits the plan for user review.",
|
|
574
590
|
"field.autoProcessSelection.title": "Process Selection (Controlled)",
|
|
575
|
-
"field.autoProcessSelection.help": "
|
|
591
|
+
"field.autoProcessSelection.help": "When a task fails two consecutive verification runs, generates an alternative reply and lets the judge choose the better path to break loops.",
|
|
576
592
|
"field.autoProcessFailureContext.title": "Give the alternative the failure evidence",
|
|
577
593
|
"field.autoProcessCandidates.title": "Process-selection candidates",
|
|
578
|
-
"field.autoProcessCandidates.help": "
|
|
594
|
+
"field.autoProcessCandidates.help": "Total candidates generated for process selection (including original, default 2). 3 or 4 runs a tournament and uses more calls.",
|
|
579
595
|
"field.autoProcessAlternativeModel.title": "Generate the alternative with another model",
|
|
580
|
-
"field.autoProcessAlternativeModel.help": "
|
|
581
|
-
"field.autoProcessFailureContext.help": "
|
|
596
|
+
"field.autoProcessAlternativeModel.help": "Alternative model (provider/model) used to generate the candidate reply. Leave empty to resample using the session model.",
|
|
597
|
+
"field.autoProcessFailureContext.help": "Attaches error logs from the two failed runs to the alternative request to encourage a different troubleshooting approach.",
|
|
582
598
|
"field.captureDecisions.title": "Keep decision snapshots",
|
|
583
|
-
"field.captureDecisions.help": "
|
|
599
|
+
"field.captureDecisions.help": "Saves sanitized prompts and raw outputs of judge calls in the topic directory for dashboard tracing.",
|
|
584
600
|
"field.autoVerifySubagents.title": "Verify Subagent Sessions",
|
|
585
|
-
"field.autoVerifySubagents.help": "
|
|
601
|
+
"field.autoVerifySubagents.help": "Whether to also run automatic routing and acceptance on delegated child sessions. Consumes additional judge budget.",
|
|
586
602
|
"section.routing": "Automatic Routing",
|
|
587
603
|
"section.budgets": "Budgets & Limits",
|
|
588
604
|
"section.storage": "Storage & Observability",
|
|
@@ -1311,6 +1327,10 @@ window.__ModuleLoader__.load({
|
|
|
1311
1327
|
cacheMaxEntries: 1e4,
|
|
1312
1328
|
estimatedInputUsdPerMillion: 0,
|
|
1313
1329
|
estimatedOutputUsdPerMillion: 0,
|
|
1330
|
+
estimatedCachedInputUsdPerMillion: 0,
|
|
1331
|
+
autoPriceFromCatalog: true,
|
|
1332
|
+
autoPriceOnline: true,
|
|
1333
|
+
priceProviderOverride: "",
|
|
1314
1334
|
autoVerifySubagents: false,
|
|
1315
1335
|
extraJudges: []
|
|
1316
1336
|
};
|
|
@@ -1536,8 +1556,12 @@ window.__ModuleLoader__.load({
|
|
|
1536
1556
|
integer: true,
|
|
1537
1557
|
unitKey: "settings.unit.ms"
|
|
1538
1558
|
}),
|
|
1559
|
+
toggle("autoPriceFromCatalog", "cost"),
|
|
1560
|
+
toggle("autoPriceOnline", "cost"),
|
|
1561
|
+
text("priceProviderOverride", "cost", true),
|
|
1539
1562
|
number("estimatedInputUsdPerMillion", "cost", { min: 0 }),
|
|
1540
|
-
number("estimatedOutputUsdPerMillion", "cost", { min: 0 })
|
|
1563
|
+
number("estimatedOutputUsdPerMillion", "cost", { min: 0 }),
|
|
1564
|
+
number("estimatedCachedInputUsdPerMillion", "cost", { min: 0 })
|
|
1541
1565
|
];
|
|
1542
1566
|
function fieldsOfSection(section) {
|
|
1543
1567
|
return FIELDS.filter((field) => field.section === section);
|
|
@@ -1619,6 +1643,10 @@ window.__ModuleLoader__.load({
|
|
|
1619
1643
|
cacheMaxEntries: numberOr("cacheMaxEntries"),
|
|
1620
1644
|
estimatedInputUsdPerMillion: numberOr("estimatedInputUsdPerMillion"),
|
|
1621
1645
|
estimatedOutputUsdPerMillion: numberOr("estimatedOutputUsdPerMillion"),
|
|
1646
|
+
estimatedCachedInputUsdPerMillion: numberOr("estimatedCachedInputUsdPerMillion"),
|
|
1647
|
+
autoPriceFromCatalog: v.autoPriceFromCatalog !== false,
|
|
1648
|
+
autoPriceOnline: v.autoPriceOnline !== false,
|
|
1649
|
+
priceProviderOverride: typeof v.priceProviderOverride === "string" ? v.priceProviderOverride.trim() : "",
|
|
1622
1650
|
autoVerifySubagents: v.autoVerifySubagents === true,
|
|
1623
1651
|
extraJudges: normalizeExtraJudges(v.extraJudges)
|
|
1624
1652
|
};
|
|
@@ -1725,7 +1753,7 @@ window.__ModuleLoader__.load({
|
|
|
1725
1753
|
});
|
|
1726
1754
|
continue;
|
|
1727
1755
|
}
|
|
1728
|
-
if (field.kind === "text" && field.key !== "criteriaFile" && field.key !== "label" && field.key !== "autoProcessAlternativeModel") {
|
|
1756
|
+
if (field.kind === "text" && field.key !== "criteriaFile" && field.key !== "label" && field.key !== "autoProcessAlternativeModel" && field.key !== "priceProviderOverride") {
|
|
1729
1757
|
const value = typeof raw === "string" ? raw.trim() : "";
|
|
1730
1758
|
if (!value) {
|
|
1731
1759
|
issues.push({
|