dsh-llm-verifier 0.3.0 → 0.4.0

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.
Files changed (97) hide show
  1. package/README.md +133 -9
  2. package/lib/auto-B5V49e-A.js +1517 -0
  3. package/lib/auto-B5V49e-A.js.map +1 -0
  4. package/lib/{caller-DJd_FlrQ.js → caller-DR_C7ueP.js} +154 -20
  5. package/lib/caller-DR_C7ueP.js.map +1 -0
  6. package/lib/caller.js +2 -2
  7. package/lib/client.js +804 -29
  8. package/lib/client.js.map +1 -1
  9. package/lib/core.js +226 -3
  10. package/lib/core.js.map +1 -1
  11. package/lib/index.js +1014 -1337
  12. package/lib/index.js.map +1 -1
  13. package/lib/replay.js +157 -0
  14. package/lib/replay.js.map +1 -0
  15. package/lib/types/auto.js +1 -1
  16. package/lib/types/auto.js.map +1 -1
  17. package/lib/types/caller.d.ts +65 -0
  18. package/lib/types/caller.d.ts.map +1 -1
  19. package/lib/types/caller.js +113 -5
  20. package/lib/types/caller.js.map +1 -1
  21. package/lib/types/client-i18n.d.ts +163 -6
  22. package/lib/types/client-i18n.d.ts.map +1 -1
  23. package/lib/types/client-i18n.js +137 -26
  24. package/lib/types/client-i18n.js.map +1 -1
  25. package/lib/types/client.d.ts +30 -0
  26. package/lib/types/client.d.ts.map +1 -1
  27. package/lib/types/client.js +94 -9
  28. package/lib/types/client.js.map +1 -1
  29. package/lib/types/config.d.ts +33 -0
  30. package/lib/types/config.d.ts.map +1 -1
  31. package/lib/types/config.js +17 -2
  32. package/lib/types/config.js.map +1 -1
  33. package/lib/types/core.d.ts +84 -0
  34. package/lib/types/core.d.ts.map +1 -1
  35. package/lib/types/core.js +222 -2
  36. package/lib/types/core.js.map +1 -1
  37. package/lib/types/criteria.d.ts +33 -0
  38. package/lib/types/criteria.d.ts.map +1 -0
  39. package/lib/types/criteria.js +67 -0
  40. package/lib/types/criteria.js.map +1 -0
  41. package/lib/types/decisions.d.ts +84 -0
  42. package/lib/types/decisions.d.ts.map +1 -0
  43. package/lib/types/decisions.js +209 -0
  44. package/lib/types/decisions.js.map +1 -0
  45. package/lib/types/engine.d.ts +54 -1
  46. package/lib/types/engine.d.ts.map +1 -1
  47. package/lib/types/engine.js +175 -12
  48. package/lib/types/engine.js.map +1 -1
  49. package/lib/types/index.d.ts +1 -0
  50. package/lib/types/index.d.ts.map +1 -1
  51. package/lib/types/index.js +392 -38
  52. package/lib/types/index.js.map +1 -1
  53. package/lib/types/replay.d.ts +88 -0
  54. package/lib/types/replay.d.ts.map +1 -0
  55. package/lib/types/replay.js +136 -0
  56. package/lib/types/replay.js.map +1 -0
  57. package/lib/types/router.d.ts +29 -5
  58. package/lib/types/router.d.ts.map +1 -1
  59. package/lib/types/router.js +283 -46
  60. package/lib/types/router.js.map +1 -1
  61. package/lib/types/statistics.d.ts +10 -1
  62. package/lib/types/statistics.d.ts.map +1 -1
  63. package/lib/types/statistics.js +35 -7
  64. package/lib/types/statistics.js.map +1 -1
  65. package/lib/types/top-logprobs.d.ts +36 -0
  66. package/lib/types/top-logprobs.d.ts.map +1 -1
  67. package/lib/types/top-logprobs.js +41 -14
  68. package/lib/types/top-logprobs.js.map +1 -1
  69. package/package.json +6 -1
  70. package/scripts/eval-replay.mjs +118 -0
  71. package/src/auto.ts +1 -1
  72. package/src/caller.test.ts +62 -1
  73. package/src/caller.ts +124 -4
  74. package/src/client-i18n.ts +137 -25
  75. package/src/client.test.ts +21 -0
  76. package/src/client.tsx +145 -7
  77. package/src/config.test.ts +32 -0
  78. package/src/config.ts +49 -2
  79. package/src/core.test.ts +95 -0
  80. package/src/core.ts +217 -2
  81. package/src/criteria.test.ts +60 -0
  82. package/src/criteria.ts +76 -0
  83. package/src/decisions.test.ts +150 -0
  84. package/src/decisions.ts +244 -0
  85. package/src/engine.test.ts +131 -0
  86. package/src/engine.ts +167 -10
  87. package/src/index.test.ts +278 -8
  88. package/src/index.ts +373 -37
  89. package/src/replay.test.ts +82 -0
  90. package/src/replay.ts +155 -0
  91. package/src/router.test.ts +240 -1
  92. package/src/router.ts +298 -48
  93. package/src/statistics.test.ts +49 -1
  94. package/src/statistics.ts +44 -7
  95. package/src/top-logprobs.test.ts +28 -0
  96. package/src/top-logprobs.ts +56 -8
  97. package/lib/caller-DJd_FlrQ.js.map +0 -1
@@ -1,7 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { Button, IconDataOutline16, IconRefreshOutline16, Input } from '@deepseek-ai/dsh-client-ui-primitives';
3
- import { useEffect, useMemo, useRef, useState } from 'react';
4
- import { zh, en, dictionaries, toolLabels, tFormat, useLanguage, detectLanguage, compact, money, duration, dateTime, resolveCacheDirOnSave, sameSettingValue, sectionForSave, WORST_CASE_ROUTE_CALLS_PER_JUDGE, WORST_CASE_FINAL_CALLS_PER_JUDGE, WORST_CASE_TASK_PER_JUDGE, WORST_CASE_SESSION_PER_JUDGE, computeJudgeCount, computeWorstCaseBudget, evaluateBudgetWarning, isVerdictFailed, formatPercentage, formatVerdictDetails, } from "./client-i18n.js";
3
+ import { Fragment, useEffect, useMemo, useRef, useState } from 'react';
4
+ import { zh, en, dictionaries, toolLabels, tFormat, useLanguage, detectLanguage, compact, money, duration, dateTime, resolveCacheDirOnSave, sameSettingValue, sectionForSave, WORST_CASE_ROUTE_CALLS_PER_JUDGE, WORST_CASE_FINAL_CALLS_PER_JUDGE, WORST_CASE_TASK_PER_JUDGE, WORST_CASE_SESSION_PER_JUDGE, WORST_CASE_CRITERIA_PER_COMPARISON, computeJudgeCount, computeWorstCaseBudget, evaluateBudgetWarning, isVerdictFailed, formatPercentage, formatVerdictDetails, } from "./client-i18n.js";
5
+ import { CRITERIA_PRESETS, DEFAULT_GROUND_TRUTH_NOTE, buildPairwisePrompt } from "./core.js";
5
6
  import { MAX_EXTRA_JUDGES, normalizeExtraJudges, judgeIdentity, judgeConflict, addExtraJudge, removeExtraJudge, serializeExtraJudges, } from "./client-judges.js";
6
7
  export { zh, en, dictionaries, toolLabels, tFormat, useLanguage, detectLanguage, compact, money, duration, dateTime, resolveCacheDirOnSave, sameSettingValue, sectionForSave, WORST_CASE_ROUTE_CALLS_PER_JUDGE, WORST_CASE_FINAL_CALLS_PER_JUDGE, WORST_CASE_TASK_PER_JUDGE, WORST_CASE_SESSION_PER_JUDGE, computeJudgeCount, computeWorstCaseBudget, evaluateBudgetWarning, isVerdictFailed, formatPercentage, formatVerdictDetails, };
7
8
  const NS = 'llm-verifier';
@@ -16,9 +17,9 @@ const toggleStyle = (enabled) => ({ position: 'relative', justifySelf: 'end', wi
16
17
  const toggleThumbStyle = (enabled) => ({ position: 'absolute', top: 3, left: enabled ? 21 : 3, width: 16, height: 16, borderRadius: '50%', background: 'var(--dsw-static-neutral-00, #fff)', boxShadow: '0 1px 3px rgba(0,0,0,.28)', transition: 'left .15s ease' });
17
18
  const dashboardCard = { border: '1px solid var(--dsw-alias-border-l2, rgba(255,255,255,.13))', background: 'color-mix(in srgb, var(--dsw-alias-bg-module, #171925) 88%, transparent)', borderRadius: 16, boxShadow: '0 12px 36px rgba(0,0,0,.12)' };
18
19
  const muted = { color: 'var(--dsw-text-secondary)', fontSize: 12 };
19
- const toolColors = { verifier_route_classify: '#d97706', verifier_compare: '#4f8cff', verifier_select: '#8b6df6', verifier_track: '#2fc5c9', verifier_current_session: '#f5a524' };
20
+ const toolColors = { verifier_route_classify: '#d97706', verifier_compare: '#4f8cff', verifier_select: '#8b6df6', verifier_track: '#2fc5c9', verifier_best_of_n: '#e2569b', verifier_current_session: '#f5a524' };
20
21
  function record(value) { return typeof value === 'object' && value !== null && !Array.isArray(value) ? value : {}; }
21
- function values(view) { const v = record(view.value); const mode = v.autoVerifyMode === 'manual' || v.autoVerifyMode === 'strict' ? v.autoVerifyMode : 'smart'; return { enabled: v.enabled !== false, autoVerifyMode: mode, autoVerifyThreshold: Number(v.autoVerifyThreshold ?? .65), autoVerifyRepeats: Number(v.autoVerifyRepeats ?? 1), autoVerifyFinalRepeats: Number(v.autoVerifyFinalRepeats ?? 2), autoVerifyMinToolCalls: Number(v.autoVerifyMinToolCalls ?? 3), autoVerifyMaxChars: Number(v.autoVerifyMaxChars ?? 80000), autoVerifyMaxPerTask: Number(v.autoVerifyMaxPerTask ?? 2), autoVerifyMaxPerSession: Number(v.autoVerifyMaxPerSession ?? 8), autoRouteSemantic: v.autoRouteSemantic !== false, autoRouteMinConfidence: Number(v.autoRouteMinConfidence ?? .9), autoRouteMaxCandidates: Number(v.autoRouteMaxCandidates ?? 8), autoRouteMaxPerTask: Number(v.autoRouteMaxPerTask ?? 2), autoRouteMaxPerSession: Number(v.autoRouteMaxPerSession ?? 8), autoTrackCompletionThreshold: Number(v.autoTrackCompletionThreshold ?? .8), autoRouteMaxItemChars: Number(v.autoRouteMaxItemChars ?? 20000), autoRouteMaxInputChars: Number(v.autoRouteMaxInputChars ?? 60000), autoMaxModelCallsPerTask: Number(v.autoMaxModelCallsPerTask ?? 96), autoMaxModelCallsPerSession: Number(v.autoMaxModelCallsPerSession ?? 240), autoVerifyTeamTasks: v.autoVerifyTeamTasks !== false, autoVerifyPlanMode: v.autoVerifyPlanMode !== false, provider: String(v.provider ?? ''), model: String(v.model ?? ''), ...(typeof v.reasoningEffort === 'string' ? { reasoningEffort: v.reasoningEffort } : {}), maxTokens: Number(v.maxTokens ?? 32768), temperature: Number(v.temperature ?? 0.2), ...(typeof v.label === 'string' && v.label.trim() ? { label: v.label.trim() } : {}), maxConcurrency: Number(v.maxConcurrency ?? 8), maxRetries: Number(v.maxRetries ?? 3), retryBaseDelayMs: Number(v.retryBaseDelayMs ?? 500), timeoutMs: Number(v.timeoutMs ?? 300000), cacheDir: typeof v.cacheDir === 'string' && v.cacheDir.trim() ? v.cacheDir.trim() : 'verifier', cacheMaxEntries: Number(v.cacheMaxEntries ?? 10000), estimatedInputUsdPerMillion: Number(v.estimatedInputUsdPerMillion ?? 0), estimatedOutputUsdPerMillion: Number(v.estimatedOutputUsdPerMillion ?? 0), autoVerifySubagents: v.autoVerifySubagents === true, extraJudges: normalizeExtraJudges(v.extraJudges) }; }
22
+ function values(view) { const v = record(view.value); const mode = v.autoVerifyMode === 'manual' || v.autoVerifyMode === 'strict' ? v.autoVerifyMode : 'smart'; return { enabled: v.enabled !== false, captureDecisions: v.captureDecisions !== false, autoVerifyMode: mode, autoVerifyThreshold: Number(v.autoVerifyThreshold ?? .65), autoVerifyRepeats: Number(v.autoVerifyRepeats ?? 1), autoTrackRepeats: Number(v.autoTrackRepeats ?? 3), autoVerifyFinalRepeats: Number(v.autoVerifyFinalRepeats ?? 2), autoVerifyMinToolCalls: Number(v.autoVerifyMinToolCalls ?? 3), autoVerifyMaxChars: Number(v.autoVerifyMaxChars ?? 80000), autoVerifyMaxPerTask: Number(v.autoVerifyMaxPerTask ?? 2), autoVerifyMaxPerSession: Number(v.autoVerifyMaxPerSession ?? 8), autoRouteSemantic: v.autoRouteSemantic !== false, autoRouteMinConfidence: Number(v.autoRouteMinConfidence ?? .9), autoRouteMaxCandidates: Number(v.autoRouteMaxCandidates ?? 8), autoRouteMaxPerTask: Number(v.autoRouteMaxPerTask ?? 2), autoRouteMaxPerSession: Number(v.autoRouteMaxPerSession ?? 8), autoTrackCompletionThreshold: Number(v.autoTrackCompletionThreshold ?? .684), autoRouteMaxItemChars: Number(v.autoRouteMaxItemChars ?? 20000), autoRouteMaxInputChars: Number(v.autoRouteMaxInputChars ?? 60000), autoMaxModelCallsPerTask: Number(v.autoMaxModelCallsPerTask ?? 96), autoMaxModelCallsPerSession: Number(v.autoMaxModelCallsPerSession ?? 240), autoVerifyTeamTasks: v.autoVerifyTeamTasks !== false, autoVerifyPlanMode: v.autoVerifyPlanMode !== false, criteriaPreset: (v.criteriaPreset === 'debug' || v.criteriaPreset === 'research' || v.criteriaPreset === 'ops' || v.criteriaPreset === 'writing' || v.criteriaPreset === 'custom') ? v.criteriaPreset : 'coding', criteriaFile: typeof v.criteriaFile === 'string' ? v.criteriaFile.trim() : '', provider: String(v.provider ?? ''), model: String(v.model ?? ''), ...(typeof v.reasoningEffort === 'string' ? { reasoningEffort: v.reasoningEffort } : {}), maxTokens: Number(v.maxTokens ?? 32768), temperature: Number(v.temperature ?? 0.2), ...(typeof v.label === 'string' && v.label.trim() ? { label: v.label.trim() } : {}), maxConcurrency: Number(v.maxConcurrency ?? 8), maxRetries: Number(v.maxRetries ?? 3), retryBaseDelayMs: Number(v.retryBaseDelayMs ?? 500), timeoutMs: Number(v.timeoutMs ?? 300000), cacheDir: typeof v.cacheDir === 'string' && v.cacheDir.trim() ? v.cacheDir.trim() : 'verifier', cacheMaxEntries: Number(v.cacheMaxEntries ?? 10000), estimatedInputUsdPerMillion: Number(v.estimatedInputUsdPerMillion ?? 0), estimatedOutputUsdPerMillion: Number(v.estimatedOutputUsdPerMillion ?? 0), autoVerifySubagents: v.autoVerifySubagents === true, extraJudges: normalizeExtraJudges(v.extraJudges) }; }
22
23
  function message(error) { return error instanceof Error ? error.message : String(error); }
23
24
  /** The endpoint answered but rejected the request: a transport fallback would only repeat it. */
24
25
  class EndpointError extends Error {
@@ -128,8 +129,12 @@ export function VerifierSettings({ remote }) {
128
129
  const budgetWarning = useMemo(() => {
129
130
  if (!draft)
130
131
  return null;
131
- return evaluateBudgetWarning(draft.autoVerifyMode, draft.extraJudges.length, draft.autoMaxModelCallsPerTask, draft.autoMaxModelCallsPerSession);
132
- }, [draft?.autoVerifyMode, draft?.extraJudges.length, draft?.autoMaxModelCallsPerTask, draft?.autoMaxModelCallsPerSession]);
132
+ // The engine reserves budget from the REAL criteria count. A built-in preset's count is known
133
+ // here; a custom file's is not (it lives on the server), so the estimate falls back to the
134
+ // three-criteria default and the file field's help says as much.
135
+ const criteria = draft.criteriaPreset === 'custom' ? WORST_CASE_CRITERIA_PER_COMPARISON : CRITERIA_PRESETS[draft.criteriaPreset].length;
136
+ return evaluateBudgetWarning(draft.autoVerifyMode, draft.extraJudges.length, draft.autoMaxModelCallsPerTask, draft.autoMaxModelCallsPerSession, criteria);
137
+ }, [draft?.autoVerifyMode, draft?.criteriaPreset, draft?.extraJudges.length, draft?.autoMaxModelCallsPerTask, draft?.autoMaxModelCallsPerSession]);
133
138
  // The saved section holds only real overrides: a draft field equal to the
134
139
  // composition base is dropped so a later plugin default still reaches this
135
140
  // install (see sectionForSave).
@@ -177,7 +182,8 @@ export function VerifierSettings({ remote }) {
177
182
  patch(key, parsed); }, onBlur: () => setEditing(current => { if (!(key in current))
178
183
  return current; const next = { ...current }; delete next[key]; return next; }) });
179
184
  const textField = (key, placeholder) => _jsx(Input, { style: { width: '100%', height: 36, borderRadius: 8 }, type: "text", disabled: busy, placeholder: placeholder, "aria-label": t[('field.' + key + '.title')] ?? String(key), value: String(draft[key] ?? ''), onChange: e => patch(key, e.target.value) });
180
- return _jsxs("div", { style: shell, children: [_jsx("h2", { style: settingsHeading, children: t['settings.title'] }), _jsx("p", { style: settingsIntro, children: t['settings.intro'] }), _jsxs("section", { style: group, children: [_jsx(GroupTitle, { children: t['section.tools'] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.enabled.title'], help: draft.enabled ? t['field.enabled.helpOn'] : t['field.enabled.helpOff'] }), _jsx("button", { type: "button", role: "switch", "aria-checked": draft.enabled, "aria-label": t['field.enabled.title'], onClick: () => patch('enabled', !draft.enabled), style: toggleStyle(draft.enabled), children: _jsx("span", { style: toggleThumbStyle(draft.enabled) }) })] }), !draft.enabled && _jsx("p", { style: { margin: '8px 0 0', fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-state-warn-label)' }, children: t['field.enabled.warnDisabled'] })] }), _jsxs("section", { style: group, children: [_jsx(GroupTitle, { children: t['section.autoVerify'] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoVerifyMode.title'], help: t['field.autoVerifyMode.help'] }), _jsxs("select", { style: selectStyle, disabled: busy, "aria-label": t['field.autoVerifyMode.title'], value: draft.autoVerifyMode, onChange: e => patch('autoVerifyMode', e.target.value), children: [_jsx("option", { value: "manual", children: t['field.autoVerifyMode.manual'] }), _jsx("option", { value: "smart", children: t['field.autoVerifyMode.smart'] }), _jsx("option", { value: "strict", children: t['field.autoVerifyMode.strict'] })] })] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoRouteSemantic.title'], help: t['field.autoRouteSemantic.help'] }), _jsx("button", { type: "button", role: "switch", "aria-checked": draft.autoRouteSemantic, "aria-label": t['field.autoRouteSemantic.title'], onClick: () => patch('autoRouteSemantic', !draft.autoRouteSemantic), style: toggleStyle(draft.autoRouteSemantic), children: _jsx("span", { style: toggleThumbStyle(draft.autoRouteSemantic) }) })] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoVerifyTeamTasks.title'], help: t['field.autoVerifyTeamTasks.help'] }), _jsx("button", { type: "button", role: "switch", "aria-checked": draft.autoVerifyTeamTasks, "aria-label": t['field.autoVerifyTeamTasks.title'], onClick: () => patch('autoVerifyTeamTasks', !(draft.autoVerifyTeamTasks)), style: toggleStyle(draft.autoVerifyTeamTasks), children: _jsx("span", { style: toggleThumbStyle(draft.autoVerifyTeamTasks) }) })] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoVerifySubagents.title'], help: t['field.autoVerifySubagents.help'] }), _jsx("button", { type: "button", role: "switch", "aria-checked": draft.autoVerifySubagents, "aria-label": t['field.autoVerifySubagents.title'], onClick: () => patch('autoVerifySubagents', !draft.autoVerifySubagents), style: toggleStyle(draft.autoVerifySubagents), children: _jsx("span", { style: toggleThumbStyle(draft.autoVerifySubagents) }) })] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoVerifyPlanMode.title'], help: t['field.autoVerifyPlanMode.help'] }), _jsx("button", { type: "button", role: "switch", "aria-checked": draft.autoVerifyPlanMode, "aria-label": t['field.autoVerifyPlanMode.title'], onClick: () => patch('autoVerifyPlanMode', !(draft.autoVerifyPlanMode)), style: toggleStyle(draft.autoVerifyPlanMode), children: _jsx("span", { style: toggleThumbStyle(draft.autoVerifyPlanMode) }) })] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoRouteMinConfidence.title'], help: t['field.autoRouteMinConfidence.help'] }), numeric('autoRouteMinConfidence', 0)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoRouteMaxCandidates.title'], help: t['field.autoRouteMaxCandidates.help'] }), numeric('autoRouteMaxCandidates', 3)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoRouteMaxPerTask.title'], help: t['field.autoRouteMaxPerTask.help'] }), numeric('autoRouteMaxPerTask', 1)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoRouteMaxPerSession.title'], help: t['field.autoRouteMaxPerSession.help'] }), numeric('autoRouteMaxPerSession', 1)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoTrackCompletionThreshold.title'], help: t['field.autoTrackCompletionThreshold.help'] }), numeric('autoTrackCompletionThreshold', 0)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoRouteMaxItemChars.title'], help: t['field.autoRouteMaxItemChars.help'] }), numeric('autoRouteMaxItemChars', 100)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoRouteMaxInputChars.title'], help: t['field.autoRouteMaxInputChars.help'] }), numeric('autoRouteMaxInputChars', 1000)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoMaxModelCallsPerTask.title'], help: t['field.autoMaxModelCallsPerTask.help'] }), numeric('autoMaxModelCallsPerTask', 1)] }), budgetWarning?.warnTask && _jsx("p", { style: { margin: '-4px 0 10px', fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-state-warn-label)' }, children: tFormat(t['field.autoMaxModelCallsPerTask.warnBudget'], { current: draft.autoMaxModelCallsPerTask, required: budgetWarning.worstCaseTask, judges: budgetWarning.judgeCount }) }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoMaxModelCallsPerSession.title'], help: t['field.autoMaxModelCallsPerSession.help'] }), numeric('autoMaxModelCallsPerSession', 1)] }), budgetWarning?.warnSession && _jsx("p", { style: { margin: '-4px 0 10px', fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-state-warn-label)' }, children: tFormat(t['field.autoMaxModelCallsPerSession.warnBudget'], { current: draft.autoMaxModelCallsPerSession, required: budgetWarning.worstCaseSession, judges: budgetWarning.judgeCount }) }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoVerifyThreshold.title'], help: t['field.autoVerifyThreshold.help'] }), numeric('autoVerifyThreshold', 0)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoVerifyRepeats.title'], help: t['field.autoVerifyRepeats.help'] }), numeric('autoVerifyRepeats', 1)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoVerifyFinalRepeats.title'], help: t['field.autoVerifyFinalRepeats.help'] }), numeric('autoVerifyFinalRepeats', 1)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoVerifyMinToolCalls.title'], help: t['field.autoVerifyMinToolCalls.help'] }), numeric('autoVerifyMinToolCalls', 1)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoVerifyMaxChars.title'], help: t['field.autoVerifyMaxChars.help'] }), numeric('autoVerifyMaxChars', 1000)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoVerifyMaxPerTask.title'], help: t['field.autoVerifyMaxPerTask.help'] }), numeric('autoVerifyMaxPerTask', 1)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoVerifyMaxPerSession.title'], help: t['field.autoVerifyMaxPerSession.help'] }), numeric('autoVerifyMaxPerSession', 1)] }), draft.autoVerifyMode !== 'manual' && _jsx("p", { style: { margin: '8px 0 0', fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-state-warn-label)' }, children: t['field.autoVerify.warnNotice'] })] }), _jsxs("section", { style: group, children: [_jsx(GroupTitle, { children: t['section.model'] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.provider.title'], help: t['field.provider.help'] }), _jsx("select", { style: selectStyle, disabled: busy, "aria-label": t['field.provider.title'], value: draft.provider, onChange: e => { const provider = e.target.value; const first = loaded.groups.find(g => g.id === provider)?.models[0]; setDraft({ ...draft, provider, ...(first ? { model: first.id, reasoningEffort: first.reasoning?.defaultEffort } : {}) }); }, children: loaded.groups.map(g => _jsxs("option", { value: g.id, children: [g.name, " \u00B7 ", g.id] }, g.id)) })] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.model.title'], help: t['field.model.help'] }), _jsx("select", { style: selectStyle, disabled: busy, "aria-label": t['field.model.title'], value: draft.model, onChange: e => { const model = e.target.value; const found = models.find(m => m.id === model); setDraft({ ...draft, model, ...(found?.reasoning?.defaultEffort ? { reasoningEffort: found.reasoning.defaultEffort } : { reasoningEffort: undefined }) }); }, children: models.map(m => _jsxs("option", { value: m.id, children: [m.name, " \u00B7 ", m.id] }, m.id)) })] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.reasoningEffort.title'], help: t['field.reasoningEffort.help'] }), _jsxs("select", { style: selectStyle, disabled: busy, "aria-label": t['field.reasoningEffort.title'], value: draft.reasoningEffort ?? '', onChange: e => patch('reasoningEffort', e.target.value || undefined), children: [_jsx("option", { value: "", children: t['field.reasoningEffort.default'] }), efforts.map(e => _jsx("option", { value: e.id, children: e.name }, e.id))] })] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.maxTokens.title'], help: t['field.maxTokens.help'] }), numeric('maxTokens', 1)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.temperature.title'], help: t['field.temperature.help'] }), numeric('temperature', 0)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.label.title'], help: t['field.label.help'] }), _jsx(Input, { style: { width: '100%', height: 36, borderRadius: 8 }, type: "text", disabled: busy, placeholder: draft.model || t['field.label.placeholder'], "aria-label": t['field.label.title'], value: draft.label ?? '', onChange: e => patch('label', e.target.value || undefined) })] }), _jsxs("div", { style: { ...row, gridTemplateColumns: 'minmax(180px, 1fr) auto', minHeight: 48 }, children: [_jsx(Label, { title: t['field.extraJudges.title'], help: t['field.extraJudges.help'] }), _jsx(Button, { variant: "outline", disabled: busy || draft.extraJudges.length >= MAX_EXTRA_JUDGES, onClick: addJudge, children: t['field.extraJudges.add'] })] }), draft.extraJudges.length > 0 && _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 8, padding: '10px 0', borderBottom: '1px solid var(--dsw-alias-border-l2)' }, children: [_jsxs("div", { style: { display: 'grid', gridTemplateColumns: 'minmax(110px, 1.2fr) minmax(120px, 1.3fr) minmax(95px, 1fr) minmax(95px, 1fr) auto', gap: 8, fontSize: 12, color: 'var(--dsw-alias-label-tertiary)', paddingBottom: 2 }, children: [_jsx("div", { children: t['field.provider.title'] }), _jsx("div", { children: t['field.model.title'] }), _jsx("div", { children: t['field.reasoningEffort.title'] }), _jsx("div", { children: t['field.extraJudges.labelTitle'] }), _jsx("div", {})] }), draft.extraJudges.map((judge, idx) => {
185
+ return _jsxs("div", { style: shell, children: [_jsx("h2", { style: settingsHeading, children: t['settings.title'] }), _jsx("p", { style: settingsIntro, children: t['settings.intro'] }), _jsxs("section", { style: group, children: [_jsx(GroupTitle, { children: t['section.tools'] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.enabled.title'], help: draft.enabled ? t['field.enabled.helpOn'] : t['field.enabled.helpOff'] }), _jsx("button", { type: "button", role: "switch", "aria-checked": draft.enabled, "aria-label": t['field.enabled.title'], onClick: () => patch('enabled', !draft.enabled), style: toggleStyle(draft.enabled), children: _jsx("span", { style: toggleThumbStyle(draft.enabled) }) })] }), !draft.enabled && _jsx("p", { style: { margin: '8px 0 0', fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-state-warn-label)' }, children: t['field.enabled.warnDisabled'] })] }), _jsxs("section", { style: group, children: [_jsx(GroupTitle, { children: t['section.autoVerify'] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoVerifyMode.title'], help: t['field.autoVerifyMode.help'] }), _jsxs("select", { style: selectStyle, disabled: busy, "aria-label": t['field.autoVerifyMode.title'], value: draft.autoVerifyMode, onChange: e => patch('autoVerifyMode', e.target.value), children: [_jsx("option", { value: "manual", children: t['field.autoVerifyMode.manual'] }), _jsx("option", { value: "smart", children: t['field.autoVerifyMode.smart'] }), _jsx("option", { value: "strict", children: t['field.autoVerifyMode.strict'] })] })] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.criteriaPreset.title'], help: t['field.criteriaPreset.help'] }), _jsx("select", { style: selectStyle, disabled: busy, "aria-label": t['field.criteriaPreset.title'], value: draft.criteriaPreset, onChange: e => patch('criteriaPreset', e.target.value), children: ['coding', 'debug', 'research', 'ops', 'writing', 'custom'].map(id => _jsx("option", { value: id, children: t[('field.criteriaPreset.' + id)] }, id)) })] }), draft.criteriaPreset === 'custom' && _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.criteriaFile.title'], help: t['field.criteriaFile.help'] }), textField('criteriaFile', 'criteria/my-task.md')] }), draft.criteriaPreset !== 'custom' && (() => { const preset = CRITERIA_PRESETS[draft.criteriaPreset]; const first = preset[0]; if (!first)
186
+ return null; return _jsxs("details", { style: { margin: '2px 0 0 4px', fontSize: 12 }, children: [_jsx("summary", { style: { cursor: 'pointer', color: 'var(--dsw-text-secondary)' }, children: tFormat(t['field.criteriaPreset.previewSummary'], { count: preset.length }) }), _jsx("pre", { style: { whiteSpace: 'pre-wrap', wordBreak: 'break-word', maxHeight: 240, overflow: 'auto', background: 'var(--dsw-surface-sunken)', border: '1px solid var(--dsw-alias-border-l2, rgba(255,255,255,.12))', borderRadius: 8, padding: 10, marginTop: 8 }, children: buildPairwisePrompt(t['field.criteriaPreset.sampleTask'], t['field.criteriaPreset.sampleA'], t['field.criteriaPreset.sampleB'], first, DEFAULT_GROUND_TRUTH_NOTE) })] }); })(), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoRouteSemantic.title'], help: t['field.autoRouteSemantic.help'] }), _jsx("button", { type: "button", role: "switch", "aria-checked": draft.autoRouteSemantic, "aria-label": t['field.autoRouteSemantic.title'], onClick: () => patch('autoRouteSemantic', !draft.autoRouteSemantic), style: toggleStyle(draft.autoRouteSemantic), children: _jsx("span", { style: toggleThumbStyle(draft.autoRouteSemantic) }) })] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoVerifyTeamTasks.title'], help: t['field.autoVerifyTeamTasks.help'] }), _jsx("button", { type: "button", role: "switch", "aria-checked": draft.autoVerifyTeamTasks, "aria-label": t['field.autoVerifyTeamTasks.title'], onClick: () => patch('autoVerifyTeamTasks', !(draft.autoVerifyTeamTasks)), style: toggleStyle(draft.autoVerifyTeamTasks), children: _jsx("span", { style: toggleThumbStyle(draft.autoVerifyTeamTasks) }) })] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.captureDecisions.title'], help: t['field.captureDecisions.help'] }), _jsx("button", { type: "button", role: "switch", "aria-checked": draft.captureDecisions, "aria-label": t['field.captureDecisions.title'], onClick: () => patch('captureDecisions', !draft.captureDecisions), style: toggleStyle(draft.captureDecisions), children: _jsx("span", { style: toggleThumbStyle(draft.captureDecisions) }) })] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoVerifySubagents.title'], help: t['field.autoVerifySubagents.help'] }), _jsx("button", { type: "button", role: "switch", "aria-checked": draft.autoVerifySubagents, "aria-label": t['field.autoVerifySubagents.title'], onClick: () => patch('autoVerifySubagents', !draft.autoVerifySubagents), style: toggleStyle(draft.autoVerifySubagents), children: _jsx("span", { style: toggleThumbStyle(draft.autoVerifySubagents) }) })] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoVerifyPlanMode.title'], help: t['field.autoVerifyPlanMode.help'] }), _jsx("button", { type: "button", role: "switch", "aria-checked": draft.autoVerifyPlanMode, "aria-label": t['field.autoVerifyPlanMode.title'], onClick: () => patch('autoVerifyPlanMode', !(draft.autoVerifyPlanMode)), style: toggleStyle(draft.autoVerifyPlanMode), children: _jsx("span", { style: toggleThumbStyle(draft.autoVerifyPlanMode) }) })] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoRouteMinConfidence.title'], help: t['field.autoRouteMinConfidence.help'] }), numeric('autoRouteMinConfidence', 0)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoRouteMaxCandidates.title'], help: t['field.autoRouteMaxCandidates.help'] }), numeric('autoRouteMaxCandidates', 3)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoRouteMaxPerTask.title'], help: t['field.autoRouteMaxPerTask.help'] }), numeric('autoRouteMaxPerTask', 1)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoRouteMaxPerSession.title'], help: t['field.autoRouteMaxPerSession.help'] }), numeric('autoRouteMaxPerSession', 1)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoTrackCompletionThreshold.title'], help: t['field.autoTrackCompletionThreshold.help'] }), numeric('autoTrackCompletionThreshold', 0)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoRouteMaxItemChars.title'], help: t['field.autoRouteMaxItemChars.help'] }), numeric('autoRouteMaxItemChars', 100)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoRouteMaxInputChars.title'], help: t['field.autoRouteMaxInputChars.help'] }), numeric('autoRouteMaxInputChars', 1000)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoMaxModelCallsPerTask.title'], help: t['field.autoMaxModelCallsPerTask.help'] }), numeric('autoMaxModelCallsPerTask', 1)] }), budgetWarning?.warnTask && _jsx("p", { style: { margin: '-4px 0 10px', fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-state-warn-label)' }, children: tFormat(t['field.autoMaxModelCallsPerTask.warnBudget'], { current: draft.autoMaxModelCallsPerTask, required: budgetWarning.worstCaseTask, judges: budgetWarning.judgeCount }) }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoMaxModelCallsPerSession.title'], help: t['field.autoMaxModelCallsPerSession.help'] }), numeric('autoMaxModelCallsPerSession', 1)] }), budgetWarning?.warnSession && _jsx("p", { style: { margin: '-4px 0 10px', fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-state-warn-label)' }, children: tFormat(t['field.autoMaxModelCallsPerSession.warnBudget'], { current: draft.autoMaxModelCallsPerSession, required: budgetWarning.worstCaseSession, judges: budgetWarning.judgeCount }) }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoVerifyThreshold.title'], help: t['field.autoVerifyThreshold.help'] }), numeric('autoVerifyThreshold', 0)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoVerifyRepeats.title'], help: t['field.autoVerifyRepeats.help'] }), numeric('autoVerifyRepeats', 1)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoTrackRepeats.title'], help: t['field.autoTrackRepeats.help'] }), numeric('autoTrackRepeats', 1)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoVerifyFinalRepeats.title'], help: t['field.autoVerifyFinalRepeats.help'] }), numeric('autoVerifyFinalRepeats', 1)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoVerifyMinToolCalls.title'], help: t['field.autoVerifyMinToolCalls.help'] }), numeric('autoVerifyMinToolCalls', 1)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoVerifyMaxChars.title'], help: t['field.autoVerifyMaxChars.help'] }), numeric('autoVerifyMaxChars', 1000)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoVerifyMaxPerTask.title'], help: t['field.autoVerifyMaxPerTask.help'] }), numeric('autoVerifyMaxPerTask', 1)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.autoVerifyMaxPerSession.title'], help: t['field.autoVerifyMaxPerSession.help'] }), numeric('autoVerifyMaxPerSession', 1)] }), draft.autoVerifyMode !== 'manual' && _jsx("p", { style: { margin: '8px 0 0', fontSize: 12, lineHeight: '18px', color: 'var(--dsw-alias-state-warn-label)' }, children: t['field.autoVerify.warnNotice'] })] }), _jsxs("section", { style: group, children: [_jsx(GroupTitle, { children: t['section.model'] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.provider.title'], help: t['field.provider.help'] }), _jsx("select", { style: selectStyle, disabled: busy, "aria-label": t['field.provider.title'], value: draft.provider, onChange: e => { const provider = e.target.value; const first = loaded.groups.find(g => g.id === provider)?.models[0]; setDraft({ ...draft, provider, ...(first ? { model: first.id, reasoningEffort: first.reasoning?.defaultEffort } : {}) }); }, children: loaded.groups.map(g => _jsxs("option", { value: g.id, children: [g.name, " \u00B7 ", g.id] }, g.id)) })] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.model.title'], help: t['field.model.help'] }), _jsx("select", { style: selectStyle, disabled: busy, "aria-label": t['field.model.title'], value: draft.model, onChange: e => { const model = e.target.value; const found = models.find(m => m.id === model); setDraft({ ...draft, model, ...(found?.reasoning?.defaultEffort ? { reasoningEffort: found.reasoning.defaultEffort } : { reasoningEffort: undefined }) }); }, children: models.map(m => _jsxs("option", { value: m.id, children: [m.name, " \u00B7 ", m.id] }, m.id)) })] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.reasoningEffort.title'], help: t['field.reasoningEffort.help'] }), _jsxs("select", { style: selectStyle, disabled: busy, "aria-label": t['field.reasoningEffort.title'], value: draft.reasoningEffort ?? '', onChange: e => patch('reasoningEffort', e.target.value || undefined), children: [_jsx("option", { value: "", children: t['field.reasoningEffort.default'] }), efforts.map(e => _jsx("option", { value: e.id, children: e.name }, e.id))] })] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.maxTokens.title'], help: t['field.maxTokens.help'] }), numeric('maxTokens', 1)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.temperature.title'], help: t['field.temperature.help'] }), numeric('temperature', 0)] }), _jsxs("div", { style: row, children: [_jsx(Label, { title: t['field.label.title'], help: t['field.label.help'] }), _jsx(Input, { style: { width: '100%', height: 36, borderRadius: 8 }, type: "text", disabled: busy, placeholder: draft.model || t['field.label.placeholder'], "aria-label": t['field.label.title'], value: draft.label ?? '', onChange: e => patch('label', e.target.value || undefined) })] }), _jsxs("div", { style: { ...row, gridTemplateColumns: 'minmax(180px, 1fr) auto', minHeight: 48 }, children: [_jsx(Label, { title: t['field.extraJudges.title'], help: t['field.extraJudges.help'] }), _jsx(Button, { variant: "outline", disabled: busy || draft.extraJudges.length >= MAX_EXTRA_JUDGES, onClick: addJudge, children: t['field.extraJudges.add'] })] }), draft.extraJudges.length > 0 && _jsxs("div", { style: { display: 'flex', flexDirection: 'column', gap: 8, padding: '10px 0', borderBottom: '1px solid var(--dsw-alias-border-l2)' }, children: [_jsxs("div", { style: { display: 'grid', gridTemplateColumns: 'minmax(110px, 1.2fr) minmax(120px, 1.3fr) minmax(95px, 1fr) minmax(95px, 1fr) auto', gap: 8, fontSize: 12, color: 'var(--dsw-alias-label-tertiary)', paddingBottom: 2 }, children: [_jsx("div", { children: t['field.provider.title'] }), _jsx("div", { children: t['field.model.title'] }), _jsx("div", { children: t['field.reasoningEffort.title'] }), _jsx("div", { children: t['field.extraJudges.labelTitle'] }), _jsx("div", {})] }), draft.extraJudges.map((judge, idx) => {
181
187
  const judgeGroup = loaded.groups.find(g => g.id === judge.provider);
182
188
  const judgeModels = judgeGroup?.models ?? [];
183
189
  const judgeModel = judgeModels.find(m => m.id === judge.model);
@@ -232,6 +238,81 @@ export function StatisticsPage({ sessionId, rpc, isGlobal }) {
232
238
  const [loading, setLoading] = useState(true);
233
239
  const [error, setError] = useState(null);
234
240
  const [refresh, setRefresh] = useState(0);
241
+ // Decision snapshots are fetched on demand: they carry whole prompts, and a dashboard
242
+ // that loaded all of them would ship megabytes of text for rows nobody opened.
243
+ const [snapshot, setSnapshot] = useState(null);
244
+ const snapshotRequest = useRef(0);
245
+ const toggleSnapshot = async (id) => {
246
+ if (snapshot?.id === id) {
247
+ setSnapshot(null);
248
+ return;
249
+ }
250
+ const request = ++snapshotRequest.current;
251
+ setSnapshot({ id });
252
+ const payload = { kind: 'decision', id };
253
+ try {
254
+ let record;
255
+ if (rpc && typeof rpc.call === 'function') {
256
+ try {
257
+ const result = await rpc.call('/api', 'llm-verifier/statistics', payload);
258
+ if (result && result.ok === true)
259
+ record = result.value.decision;
260
+ }
261
+ catch (rpcError) {
262
+ console.warn('[llm-verifier] decision rpc.call failed, trying fetch fallback:', rpcError);
263
+ }
264
+ }
265
+ if (record === undefined) {
266
+ const response = await fetch('/api/llm-verifier/statistics', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(payload) });
267
+ const body = await response.json().catch(() => undefined);
268
+ const value = body?.ok === true ? body.value : body?.result?.ok === true ? body.result.value : undefined;
269
+ if (value === undefined || value === null)
270
+ throw new EndpointError(body?.error?.message ?? body?.result?.error?.message ?? t['stats.requestFailed']);
271
+ record = value.decision;
272
+ }
273
+ if (snapshotRequest.current === request)
274
+ setSnapshot({ id, ...(record === undefined ? { error: t['recent.decisionMissing'] } : { record }) });
275
+ }
276
+ catch (cause) {
277
+ if (snapshotRequest.current === request)
278
+ setSnapshot({ id, error: message(cause) });
279
+ }
280
+ };
281
+ // Judge probe: one real, bounded call per configured judge. Not recorded in the statistics —
282
+ // it answers "which channel is this judge on, and is my rubric the one in effect", which the
283
+ // aggregate counters cannot.
284
+ const [probe, setProbe] = useState(null);
285
+ const runProbe = async () => {
286
+ if (probe?.busy)
287
+ return;
288
+ setProbe({ busy: true });
289
+ const payload = { kind: 'probe' };
290
+ try {
291
+ let value;
292
+ if (rpc && typeof rpc.call === 'function') {
293
+ try {
294
+ const result = await rpc.call('/api', 'llm-verifier/statistics', payload);
295
+ if (result && result.ok === true)
296
+ value = result.value;
297
+ }
298
+ catch (rpcError) {
299
+ console.warn('[llm-verifier] probe rpc.call failed, trying fetch fallback:', rpcError);
300
+ }
301
+ }
302
+ if (value === undefined) {
303
+ const response = await fetch('/api/llm-verifier/statistics', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(payload) });
304
+ const body = await response.json().catch(() => undefined);
305
+ const fallback = body?.ok === true ? body.value : body?.result?.ok === true ? body.result.value : undefined;
306
+ if (fallback === undefined || fallback === null)
307
+ throw new EndpointError(body?.error?.message ?? body?.result?.error?.message ?? t['stats.requestFailed']);
308
+ value = fallback;
309
+ }
310
+ setProbe({ busy: false, value });
311
+ }
312
+ catch (cause) {
313
+ setProbe({ busy: false, error: message(cause) });
314
+ }
315
+ };
235
316
  // Data belongs to the range/session that produced it: keeping the previous
236
317
  // range's numbers under an error banner reads as if they were current.
237
318
  const queryKey = days + '|' + sessionOnly + '|' + String(sessionId ?? '');
@@ -321,10 +402,14 @@ export function StatisticsPage({ sessionId, rpc, isGlobal }) {
321
402
  return () => controller.abort();
322
403
  }, [days, sessionOnly, sessionId, refresh, rpc, t, queryKey]);
323
404
  const totals = data?.totals;
324
- return _jsx("main", { style: { height: '100%', overflow: 'auto', boxSizing: 'border-box', padding: '22px clamp(16px, 3vw, 38px) 48px', color: 'var(--dsw-text-primary)', background: 'radial-gradient(circle at 10% 0%, rgba(115,77,255,.09), transparent 32%), radial-gradient(circle at 100% 8%, rgba(47,197,201,.07), transparent 28%)' }, children: _jsxs("div", { style: { maxWidth: 1180, margin: '0 auto', display: 'flex', flexDirection: 'column', gap: 16 }, children: [_jsxs("header", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 16, flexWrap: 'wrap' }, children: [_jsxs("div", { children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 10 }, children: [_jsx("span", { style: { display: 'grid', placeItems: 'center', width: 34, height: 34, borderRadius: 10, background: 'rgba(79,140,255,.14)', color: '#6da0ff' }, children: _jsx(IconDataOutline16, { size: 18 }) }), _jsx("h2", { style: { margin: 0, fontSize: 23 }, children: isGlobal ? t['global.panelTitle'] : t['stats.pageTitle'] })] }), _jsx("p", { style: { margin: '7px 0 0 44px', ...muted }, children: isGlobal ? t['global.panelIntro'] : tFormat(t['stats.updatedAt'], { time: data ? dateTime(data.generatedAt, lang) : '--' }) })] }), _jsxs("div", { style: { display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap' }, children: [_jsx("div", { style: { display: 'flex', padding: 3, borderRadius: 10, background: 'var(--dsw-surface-sunken)', border: '1px solid var(--dsw-alias-border-l2, rgba(255,255,255,.12))' }, children: [7, 30, 90].map(value => _jsx("button", { "aria-pressed": days === value, onClick: () => setDays(value), style: { border: 0, borderRadius: 7, padding: '6px 10px', cursor: 'pointer', color: days === value ? '#fff' : 'var(--dsw-text-secondary)', background: days === value ? '#3f68d8' : 'transparent' }, children: tFormat(t['stats.daysUnit'], { days: value }) }, value)) }), Boolean(sessionId) && _jsx("button", { "aria-pressed": sessionOnly, onClick: () => setSessionOnly(value => !value), style: { border: '1px solid var(--dsw-alias-border-l2, rgba(255,255,255,.15))', borderRadius: 9, padding: '7px 11px', cursor: 'pointer', color: 'var(--dsw-text-primary)', background: sessionOnly ? 'rgba(79,140,255,.18)' : 'var(--dsw-surface-sunken)' }, children: sessionOnly ? t['stats.currentSession'] : t['stats.allSessions'] }), _jsx("button", { title: t['stats.refresh'], onClick: () => setRefresh(value => value + 1), style: { display: 'grid', placeItems: 'center', width: 34, height: 34, borderRadius: 9, border: '1px solid var(--dsw-alias-border-l2, rgba(255,255,255,.15))', color: 'var(--dsw-text-primary)', background: 'var(--dsw-surface-sunken)', cursor: 'pointer' }, children: _jsx(IconRefreshOutline16, { size: 16 }) })] })] }), error && _jsxs("div", { style: { ...dashboardCard, padding: 18, borderColor: 'var(--dsw-danger, #e85858)', color: 'var(--dsw-danger, #e85858)' }, children: [error, _jsx("div", { style: { ...muted, marginTop: 6 }, children: t['stats.hostRestartHint'] })] }), loading && !data ? _jsx("div", { style: { ...dashboardCard, padding: 32, textAlign: 'center', ...muted }, children: t['stats.loading'] }) : _jsxs(_Fragment, { children: [_jsxs("section", { style: { ...dashboardCard, padding: '22px 24px', display: 'grid', gridTemplateColumns: 'minmax(220px,1.4fr) minmax(240px,1fr)', gap: 24, alignItems: 'center' }, children: [_jsxs("div", { children: [_jsx("div", { style: muted, children: tFormat(t['stats.costSummary'], { days }) }), _jsx("div", { style: { fontSize: 38, fontWeight: 780, letterSpacing: '-.03em', margin: '5px 0' }, children: money(totals?.estimatedCostUsd ?? 0) }), _jsx("div", { style: muted, children: tFormat(t['stats.callsSummary'], { invocations: compact(totals?.invocations ?? 0, lang), calls: compact(totals?.calls ?? 0, lang) }) })] }), _jsxs("div", { style: { display: 'grid', gridTemplateColumns: '1fr auto', gap: '9px 16px', fontSize: 13 }, children: [_jsx("span", { style: muted, children: t['stats.successCalls'] }), _jsxs("strong", { children: [compact(totals?.successes ?? 0, lang), " ", _jsxs("small", { style: { color: '#77d49b' }, children: ["\u25B2 ", ((totals?.successRate ?? 0) * 100).toFixed(1), "%"] })] }), _jsx("span", { style: muted, children: t['stats.failedCalls'] }), _jsx("strong", { children: compact(totals?.failures ?? 0, lang) }), _jsx("span", { style: muted, children: t['stats.avgDuration'] }), _jsx("strong", { children: duration(totals?.averageDurationMs ?? 0) })] })] }), _jsxs("section", { style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fit,minmax(180px,1fr))', gap: 12 }, children: [_jsx(Metric, { label: t['metric.cacheHitRate'], value: ((totals?.cacheHitRate ?? 0) * 100).toFixed(1) + '%', note: tFormat(t['metric.cacheHitNote'], { hits: compact(totals?.cacheHits ?? 0, lang), total: compact((totals?.cacheHits ?? 0) + (totals?.cacheMisses ?? 0), lang) }), accent: "#b7dd64" }), _jsx(Metric, { label: t['metric.tokens'], value: compact(totals?.tokens ?? 0, lang), note: tFormat(t['metric.tokensNote'], { input: compact((totals?.inputTokens ?? 0) + (totals?.cachedInputTokens ?? 0), lang), output: compact(totals?.outputTokens ?? 0, lang) }) }), _jsx(Metric, { label: t['metric.avgModelCalls'], value: (totals?.invocations ?? 0) > 0 ? ((totals?.calls ?? 0) / (totals?.invocations ?? 1)).toFixed(1) : '0', note: tFormat(t['metric.avgModelCallsNote'], { attempts: compact(totals?.attempts ?? 0, lang), retries: compact(totals?.retries ?? 0, lang) }) }), _jsx(Metric, { label: t['metric.scoringMode'], value: compact(totals?.topLogprobScores ?? 0, lang), note: tFormat(t['metric.scoringModeNote'], { explicit: compact(totals?.explicitTagScores ?? 0, lang) }) })] }), _jsxs("section", { style: { ...dashboardCard, padding: '18px 20px 16px' }, children: [_jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 4 }, children: [_jsx("strong", { children: t['chart.title'] }), _jsx("span", { style: muted, children: sessionOnly ? t['stats.currentSession'] : t['stats.allSessions'] })] }), _jsx(TrendChart, { daily: data?.daily ?? [], days: days, lang: lang })] }), _jsxs("section", { style: { ...dashboardCard, padding: '18px 18px 8px', overflow: 'hidden' }, children: [_jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', margin: '0 2px 12px' }, children: [_jsx("strong", { children: t['table.title'] }), _jsx("span", { style: muted, children: tFormat(t['table.toolCount'], { count: (data?.tools ?? []).length }) })] }), _jsx("div", { style: { overflowX: 'auto' }, children: _jsxs("table", { style: { width: '100%', borderCollapse: 'collapse', fontSize: 13, minWidth: 760 }, children: [_jsx("thead", { children: _jsx("tr", { style: { textAlign: 'left', color: 'var(--dsw-text-secondary)', background: 'var(--dsw-surface-sunken)' }, children: [t['table.colTool'], t['table.colInvocations'], t['table.colSuccessRate'], t['table.colAvgDuration'], t['table.colModelCalls'], t['table.colTokens'], t['table.colCacheHits'], t['table.colEstimatedCost']].map(value => _jsx("th", { style: { padding: '10px 12px', fontWeight: 500 }, children: value }, value)) }) }), _jsxs("tbody", { children: [(data?.tools ?? []).map(tool => _jsxs("tr", { style: { borderTop: '1px solid var(--dsw-alias-border-l2, rgba(255,255,255,.1))' }, children: [_jsxs("td", { style: { padding: '13px 12px' }, children: [_jsx("span", { style: { display: 'inline-block', width: 8, height: 8, borderRadius: '50%', background: toolColors[tool.toolName] ?? '#8691a8', marginRight: 8 } }), _jsx("strong", { children: labels[tool.toolName] ?? tool.toolName }), _jsx("div", { style: { ...muted, margin: '3px 0 0 16px' }, children: tool.toolName })] }), _jsx("td", { style: { padding: '13px 12px' }, children: compact(tool.invocations, lang) }), _jsxs("td", { style: { padding: '13px 12px', color: tool.successRate >= .9 ? '#77d49b' : tool.successRate >= .7 ? '#e3bd63' : '#ed7777' }, children: [(tool.successRate * 100).toFixed(1), "%"] }), _jsx("td", { style: { padding: '13px 12px' }, children: duration(tool.averageDurationMs) }), _jsx("td", { style: { padding: '13px 12px' }, children: compact(tool.calls, lang) }), _jsx("td", { style: { padding: '13px 12px' }, children: compact(tool.tokens, lang) }), _jsxs("td", { style: { padding: '13px 12px' }, children: [tool.cacheHits, "/", tool.cacheHits + tool.cacheMisses] }), _jsx("td", { style: { padding: '13px 12px' }, children: money(tool.estimatedCostUsd) })] }, tool.toolName)), (data?.tools.length ?? 0) === 0 && _jsx("tr", { children: _jsx("td", { colSpan: 8, style: { padding: 28, textAlign: 'center', ...muted }, children: t['table.empty'] }) })] })] }) })] }), _jsxs("section", { style: { display: 'grid', gridTemplateColumns: 'minmax(0,1fr) minmax(290px,.45fr)', gap: 16, alignItems: 'start' }, children: [_jsxs("div", { style: { ...dashboardCard, padding: '18px 18px 8px', overflow: 'hidden' }, children: [_jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', margin: '0 2px 12px' }, children: [_jsx("strong", { children: t['recent.title'] }), _jsx("span", { style: muted, children: t['recent.maxCount'] })] }), _jsxs("div", { style: { maxHeight: 360, overflow: 'auto' }, children: [(data?.recent ?? []).map(item => {
405
+ return _jsx("main", { style: { height: '100%', overflow: 'auto', boxSizing: 'border-box', padding: '22px clamp(16px, 3vw, 38px) 48px', color: 'var(--dsw-text-primary)', background: 'radial-gradient(circle at 10% 0%, rgba(115,77,255,.09), transparent 32%), radial-gradient(circle at 100% 8%, rgba(47,197,201,.07), transparent 28%)' }, children: _jsxs("div", { style: { maxWidth: 1180, margin: '0 auto', display: 'flex', flexDirection: 'column', gap: 16 }, children: [_jsxs("header", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 16, flexWrap: 'wrap' }, children: [_jsxs("div", { children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 10 }, children: [_jsx("span", { style: { display: 'grid', placeItems: 'center', width: 34, height: 34, borderRadius: 10, background: 'rgba(79,140,255,.14)', color: '#6da0ff' }, children: _jsx(IconDataOutline16, { size: 18 }) }), _jsx("h2", { style: { margin: 0, fontSize: 23 }, children: isGlobal ? t['global.panelTitle'] : t['stats.pageTitle'] })] }), _jsx("p", { style: { margin: '7px 0 0 44px', ...muted }, children: isGlobal ? t['global.panelIntro'] : tFormat(t['stats.updatedAt'], { time: data ? dateTime(data.generatedAt, lang) : '--' }) })] }), _jsxs("div", { style: { display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap' }, children: [_jsx("div", { style: { display: 'flex', padding: 3, borderRadius: 10, background: 'var(--dsw-surface-sunken)', border: '1px solid var(--dsw-alias-border-l2, rgba(255,255,255,.12))' }, children: [7, 30, 90].map(value => _jsx("button", { "aria-pressed": days === value, onClick: () => setDays(value), style: { border: 0, borderRadius: 7, padding: '6px 10px', cursor: 'pointer', color: days === value ? '#fff' : 'var(--dsw-text-secondary)', background: days === value ? '#3f68d8' : 'transparent' }, children: tFormat(t['stats.daysUnit'], { days: value }) }, value)) }), Boolean(sessionId) && _jsx("button", { "aria-pressed": sessionOnly, onClick: () => setSessionOnly(value => !value), style: { border: '1px solid var(--dsw-alias-border-l2, rgba(255,255,255,.15))', borderRadius: 9, padding: '7px 11px', cursor: 'pointer', color: 'var(--dsw-text-primary)', background: sessionOnly ? 'rgba(79,140,255,.18)' : 'var(--dsw-surface-sunken)' }, children: sessionOnly ? t['stats.currentSession'] : t['stats.allSessions'] }), _jsx("button", { type: "button", disabled: probe?.busy === true, onClick: () => void runProbe(), style: { border: '1px solid var(--dsw-alias-border-l2, rgba(255,255,255,.15))', borderRadius: 9, padding: '7px 11px', cursor: 'pointer', color: 'var(--dsw-text-primary)', background: 'var(--dsw-surface-sunken)' }, children: probe?.busy === true ? t['probe.running'] : t['probe.button'] }), _jsx("button", { title: t['stats.refresh'], onClick: () => setRefresh(value => value + 1), style: { display: 'grid', placeItems: 'center', width: 34, height: 34, borderRadius: 9, border: '1px solid var(--dsw-alias-border-l2, rgba(255,255,255,.15))', color: 'var(--dsw-text-primary)', background: 'var(--dsw-surface-sunken)', cursor: 'pointer' }, children: _jsx(IconRefreshOutline16, { size: 16 }) })] })] }), error && _jsxs("div", { style: { ...dashboardCard, padding: 18, borderColor: 'var(--dsw-danger, #e85858)', color: 'var(--dsw-danger, #e85858)' }, children: [error, _jsx("div", { style: { ...muted, marginTop: 6 }, children: t['stats.hostRestartHint'] })] }), probe !== null && _jsxs("section", { style: { ...dashboardCard, padding: '16px 18px' }, children: [_jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center' }, children: [_jsx("strong", { children: t['probe.title'] }), _jsx("span", { style: muted, children: t['probe.note'] })] }), probe.error !== undefined && _jsx("div", { style: { marginTop: 10, fontSize: 12, color: '#e76565' }, children: probe.error }), probe.value !== undefined && _jsxs(_Fragment, { children: [_jsx("div", { style: { ...muted, marginTop: 8 }, children: tFormat(t['probe.rubric'], { source: probe.value.rubric.source, count: probe.value.rubric.count, file: probe.value.rubric.file ?? '' }) }), probe.value.rubric.error !== undefined && _jsx("div", { style: { marginTop: 6, fontSize: 12, color: '#e3bd63' }, children: tFormat(t['probe.rubricFallback'], { error: probe.value.rubric.error }) }), _jsx("div", { style: { marginTop: 10, display: 'flex', flexDirection: 'column', gap: 8 }, children: probe.value.judges.map(judge => _jsxs("div", { style: { display: 'flex', flexWrap: 'wrap', gap: 10, alignItems: 'center', fontSize: 12, padding: '9px 11px', borderRadius: 9, background: 'var(--dsw-surface-sunken)' }, children: [_jsx("span", { style: { color: judge.ok ? '#77d49b' : '#e76565', fontWeight: 600 }, children: judge.ok ? 'OK' : t['probe.failed'] }), _jsx("strong", { children: judge.label }), _jsxs("span", { style: muted, children: [judge.provider, "/", judge.model] }), judge.ok ? _jsxs(_Fragment, { children: [judge.channel !== undefined && _jsxs("span", { style: muted, children: [tFormat(t['probe.channel'], { channel: judge.channel }), judge.channelProbed === true ? ' · ' + t['probe.reprobed'] : ''] }), judge.scoreA !== undefined && judge.scoreB !== undefined && _jsx("span", { style: muted, children: tFormat(t['probe.scores'], { a: formatPercentage(judge.scoreA), b: formatPercentage(judge.scoreB) }) }), _jsx("span", { style: muted, children: tFormat(t['probe.latency'], { ms: String(judge.latencyMs) }) }), judge.calls !== undefined && _jsx("span", { style: muted, children: tFormat(t['probe.calls'], { calls: String(judge.calls) }) })] }) : _jsx("span", { style: { color: '#e76565' }, children: judge.error })] }, judge.label + judge.model)) })] })] }), loading && !data ? _jsx("div", { style: { ...dashboardCard, padding: 32, textAlign: 'center', ...muted }, children: t['stats.loading'] }) : _jsxs(_Fragment, { children: [_jsxs("section", { style: { ...dashboardCard, padding: '22px 24px', display: 'grid', gridTemplateColumns: 'minmax(220px,1.4fr) minmax(240px,1fr)', gap: 24, alignItems: 'center' }, children: [_jsxs("div", { children: [_jsx("div", { style: muted, children: tFormat(t['stats.costSummary'], { days }) }), _jsx("div", { style: { fontSize: 38, fontWeight: 780, letterSpacing: '-.03em', margin: '5px 0' }, children: money(totals?.estimatedCostUsd ?? 0) }), _jsx("div", { style: muted, children: tFormat(t['stats.callsSummary'], { invocations: compact(totals?.invocations ?? 0, lang), calls: compact(totals?.calls ?? 0, lang) }) })] }), _jsxs("div", { style: { display: 'grid', gridTemplateColumns: '1fr auto', gap: '9px 16px', fontSize: 13 }, children: [_jsx("span", { style: muted, children: t['stats.successCalls'] }), _jsxs("strong", { children: [compact(totals?.successes ?? 0, lang), " ", _jsxs("small", { style: { color: '#77d49b' }, children: ["\u25B2 ", ((totals?.successRate ?? 0) * 100).toFixed(1), "%"] })] }), _jsx("span", { style: muted, children: t['stats.failedCalls'] }), _jsx("strong", { children: compact(totals?.failures ?? 0, lang) }), _jsx("span", { style: muted, children: t['stats.avgDuration'] }), _jsx("strong", { children: duration(totals?.averageDurationMs ?? 0) })] })] }), _jsxs("section", { style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fit,minmax(180px,1fr))', gap: 12 }, children: [_jsx(Metric, { label: t['metric.cacheHitRate'], value: ((totals?.cacheHitRate ?? 0) * 100).toFixed(1) + '%', note: tFormat(t['metric.cacheHitNote'], { hits: compact(totals?.cacheHits ?? 0, lang), total: compact((totals?.cacheHits ?? 0) + (totals?.cacheMisses ?? 0), lang) }), accent: "#b7dd64" }), _jsx(Metric, { label: t['metric.prefixCacheHitRate'], value: ((totals?.prefixCacheHitRate ?? 0) * 100).toFixed(1) + '%', note: tFormat(t['metric.prefixCacheHitNote'], { cached: compact(totals?.cachedInputTokens ?? 0, lang), input: compact((totals?.inputTokens ?? 0) + (totals?.cachedInputTokens ?? 0), lang) }) }), _jsx(Metric, { label: t['metric.tokens'], value: compact(totals?.tokens ?? 0, lang), note: tFormat(t['metric.tokensNote'], { input: compact((totals?.inputTokens ?? 0) + (totals?.cachedInputTokens ?? 0), lang), output: compact(totals?.outputTokens ?? 0, lang) }) }), _jsx(Metric, { label: t['metric.avgModelCalls'], value: (totals?.invocations ?? 0) > 0 ? ((totals?.calls ?? 0) / (totals?.invocations ?? 1)).toFixed(1) : '0', note: tFormat(t['metric.avgModelCallsNote'], { attempts: compact(totals?.attempts ?? 0, lang), retries: compact(totals?.retries ?? 0, lang) }) }), _jsx(Metric, { label: t['metric.scoringMode'], value: compact(totals?.topLogprobScores ?? 0, lang), note: tFormat(t['metric.scoringModeNote'], { explicit: compact(totals?.explicitTagScores ?? 0, lang) }) })] }), _jsxs("section", { style: { ...dashboardCard, padding: '18px 20px 16px' }, children: [_jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 4 }, children: [_jsx("strong", { children: t['chart.title'] }), _jsx("span", { style: muted, children: sessionOnly ? t['stats.currentSession'] : t['stats.allSessions'] })] }), _jsx(TrendChart, { daily: data?.daily ?? [], days: days, lang: lang })] }), _jsxs("section", { style: { ...dashboardCard, padding: '18px 18px 8px', overflow: 'hidden' }, children: [_jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', margin: '0 2px 12px' }, children: [_jsx("strong", { children: t['table.title'] }), _jsx("span", { style: muted, children: tFormat(t['table.toolCount'], { count: (data?.tools ?? []).length }) })] }), _jsx("div", { style: { overflowX: 'auto' }, children: _jsxs("table", { style: { width: '100%', borderCollapse: 'collapse', fontSize: 13, minWidth: 760 }, children: [_jsx("thead", { children: _jsx("tr", { style: { textAlign: 'left', color: 'var(--dsw-text-secondary)', background: 'var(--dsw-surface-sunken)' }, children: [t['table.colTool'], t['table.colInvocations'], t['table.colSuccessRate'], t['table.colAvgDuration'], t['table.colModelCalls'], t['table.colTokens'], t['table.colCacheHits'], t['table.colEstimatedCost']].map(value => _jsx("th", { style: { padding: '10px 12px', fontWeight: 500 }, children: value }, value)) }) }), _jsxs("tbody", { children: [(data?.tools ?? []).map(tool => _jsxs("tr", { style: { borderTop: '1px solid var(--dsw-alias-border-l2, rgba(255,255,255,.1))' }, children: [_jsxs("td", { style: { padding: '13px 12px' }, children: [_jsx("span", { style: { display: 'inline-block', width: 8, height: 8, borderRadius: '50%', background: toolColors[tool.toolName] ?? '#8691a8', marginRight: 8 } }), _jsx("strong", { children: labels[tool.toolName] ?? tool.toolName }), _jsx("div", { style: { ...muted, margin: '3px 0 0 16px' }, children: tool.toolName })] }), _jsx("td", { style: { padding: '13px 12px' }, children: compact(tool.invocations, lang) }), _jsxs("td", { style: { padding: '13px 12px', color: tool.successRate >= .9 ? '#77d49b' : tool.successRate >= .7 ? '#e3bd63' : '#ed7777' }, children: [(tool.successRate * 100).toFixed(1), "%"] }), _jsx("td", { style: { padding: '13px 12px' }, children: duration(tool.averageDurationMs) }), _jsx("td", { style: { padding: '13px 12px' }, children: compact(tool.calls, lang) }), _jsx("td", { style: { padding: '13px 12px' }, children: compact(tool.tokens, lang) }), _jsxs("td", { style: { padding: '13px 12px' }, children: [tool.cacheHits, "/", tool.cacheHits + tool.cacheMisses] }), _jsx("td", { style: { padding: '13px 12px' }, children: money(tool.estimatedCostUsd) })] }, tool.toolName)), (data?.tools.length ?? 0) === 0 && _jsx("tr", { children: _jsx("td", { colSpan: 8, style: { padding: 28, textAlign: 'center', ...muted }, children: t['table.empty'] }) })] })] }) })] }), _jsxs("section", { style: { display: 'grid', gridTemplateColumns: 'minmax(0,1fr) minmax(290px,.45fr)', gap: 16, alignItems: 'start' }, children: [_jsxs("div", { style: { ...dashboardCard, padding: '18px 18px 8px', overflow: 'hidden' }, children: [_jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', margin: '0 2px 12px' }, children: [_jsx("strong", { children: t['recent.title'] }), _jsx("span", { style: muted, children: t['recent.maxCount'] })] }), _jsxs("div", { style: { maxHeight: 360, overflow: 'auto' }, children: [(data?.recent ?? []).map(item => {
325
406
  const verdictInfo = item.verdict ? formatVerdictDetails(item.verdict, t) : undefined;
326
407
  const failed = !item.success || (verdictInfo ? verdictInfo.isFailed : false);
327
- return _jsxs("div", { style: { display: 'grid', gridTemplateColumns: 'minmax(170px,1fr) auto', gap: 12, padding: '11px 8px', borderTop: '1px solid var(--dsw-alias-border-l2, rgba(255,255,255,.1))' }, children: [_jsxs("div", { children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 8 }, children: [_jsx("span", { style: { width: 7, height: 7, borderRadius: '50%', background: failed ? '#e76565' : '#59c985' } }), _jsx("strong", { style: { fontSize: 13 }, children: labels[item.toolName] ?? item.toolName }), _jsxs("span", { style: muted, children: [item.provider, "/", item.model] })] }), !item.success && _jsx("div", { title: item.errorMessage, style: { margin: '5px 0 0 15px', fontSize: 11, color: '#e76565', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: item.errorMessage ?? item.errorName }), item.verdict && verdictInfo && _jsxs("div", { style: { display: 'flex', alignItems: 'center', flexWrap: 'wrap', gap: 6, margin: '6px 0 0 15px', fontSize: 11 }, children: [verdictInfo.outcomeText && _jsx("span", { style: { padding: '1px 5px', borderRadius: 4, fontWeight: 500, fontSize: 11, background: verdictInfo.isFailed ? 'rgba(231,101,101,.16)' : item.verdict.outcome === 'tie' ? 'rgba(227,189,99,.16)' : 'rgba(89,201,133,.16)', color: verdictInfo.isFailed ? '#e76565' : item.verdict.outcome === 'tie' ? '#e3bd63' : '#77d49b', border: `1px solid ${verdictInfo.isFailed ? 'rgba(231,101,101,.3)' : item.verdict.outcome === 'tie' ? 'rgba(227,189,99,.3)' : 'rgba(89,201,133,.3)'}` }, children: verdictInfo.outcomeText }), verdictInfo.phaseText && _jsx("span", { style: { padding: '1px 5px', borderRadius: 4, background: 'var(--dsw-surface-sunken)', color: 'var(--dsw-text-secondary)', border: '1px solid var(--dsw-alias-border-l2, rgba(255,255,255,.1))' }, children: verdictInfo.phaseText }), verdictInfo.scoreText && _jsx("span", { style: { color: (typeof item.verdict.threshold === 'number' && typeof item.verdict.score === 'number' && item.verdict.score < item.verdict.threshold) ? '#e76565' : 'var(--dsw-text-primary)' }, children: verdictInfo.scoreText }), verdictInfo.checkpointsText && _jsx("span", { style: { color: 'var(--dsw-text-secondary)' }, children: verdictInfo.checkpointsText }), verdictInfo.criteriaText && _jsx("span", { style: { color: 'var(--dsw-text-secondary)' }, children: verdictInfo.criteriaText }), verdictInfo.winnerText && _jsx("span", { style: { color: 'var(--dsw-text-secondary)' }, children: verdictInfo.winnerText })] })] }), _jsxs("div", { style: { textAlign: 'right' }, children: [_jsx("div", { style: { fontSize: 12 }, children: duration(item.durationMs) }), _jsx("div", { style: { ...muted, marginTop: 3 }, children: dateTime(item.startedAt, lang) })] })] }, item.id);
408
+ return _jsxs("div", { style: { display: 'grid', gridTemplateColumns: 'minmax(170px,1fr) auto', gap: 12, padding: '11px 8px', borderTop: '1px solid var(--dsw-alias-border-l2, rgba(255,255,255,.1))' }, children: [_jsxs("div", { children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 8 }, children: [_jsx("span", { style: { width: 7, height: 7, borderRadius: '50%', background: failed ? '#e76565' : '#59c985' } }), _jsx("strong", { style: { fontSize: 13 }, children: labels[item.toolName] ?? item.toolName }), _jsxs("span", { style: muted, children: [item.provider, "/", item.model] })] }), !item.success && _jsx("div", { title: item.errorMessage, style: { margin: '5px 0 0 15px', fontSize: 11, color: '#e76565', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: item.errorMessage ?? item.errorName }), item.verdict && verdictInfo && _jsxs("div", { style: { display: 'flex', alignItems: 'center', flexWrap: 'wrap', gap: 6, margin: '6px 0 0 15px', fontSize: 11 }, children: [verdictInfo.outcomeText && _jsx("span", { style: { padding: '1px 5px', borderRadius: 4, fontWeight: 500, fontSize: 11, background: verdictInfo.isFailed ? 'rgba(231,101,101,.16)' : item.verdict.outcome === 'tie' ? 'rgba(227,189,99,.16)' : 'rgba(89,201,133,.16)', color: verdictInfo.isFailed ? '#e76565' : item.verdict.outcome === 'tie' ? '#e3bd63' : '#77d49b', border: `1px solid ${verdictInfo.isFailed ? 'rgba(231,101,101,.3)' : item.verdict.outcome === 'tie' ? 'rgba(227,189,99,.3)' : 'rgba(89,201,133,.3)'}` }, children: verdictInfo.outcomeText }), verdictInfo.phaseText && _jsx("span", { style: { padding: '1px 5px', borderRadius: 4, background: 'var(--dsw-surface-sunken)', color: 'var(--dsw-text-secondary)', border: '1px solid var(--dsw-alias-border-l2, rgba(255,255,255,.1))' }, children: verdictInfo.phaseText }), verdictInfo.scoreText && _jsx("span", { style: { color: (typeof item.verdict.threshold === 'number' && typeof item.verdict.score === 'number' && item.verdict.score < item.verdict.threshold) ? '#e76565' : 'var(--dsw-text-primary)' }, children: verdictInfo.scoreText }), verdictInfo.checkpointsText && _jsx("span", { style: { color: 'var(--dsw-text-secondary)' }, children: verdictInfo.checkpointsText }), verdictInfo.criteriaText && _jsx("span", { style: { color: 'var(--dsw-text-secondary)' }, children: verdictInfo.criteriaText }), verdictInfo.winnerText && _jsx("span", { style: { color: 'var(--dsw-text-secondary)' }, children: verdictInfo.winnerText })] }), _jsx("div", { style: { margin: '6px 0 0 15px' }, children: _jsx("button", { type: "button", onClick: () => void toggleSnapshot(item.id), style: { fontSize: 11, padding: '2px 7px', borderRadius: 5, cursor: 'pointer', color: 'var(--dsw-text-secondary)', background: 'var(--dsw-surface-sunken)', border: '1px solid var(--dsw-alias-border-l2, rgba(255,255,255,.14))' }, children: snapshot?.id === item.id ? t['recent.decisionHide'] : t['recent.decision'] }) }), _jsxs("details", { style: { margin: '6px 0 0 15px' }, children: [_jsx("summary", { style: { cursor: 'pointer', fontSize: 11, color: 'var(--dsw-text-secondary)' }, children: t['recent.details'] }), _jsxs("div", { style: { marginTop: 8, border: '1px solid var(--dsw-alias-border-l2, rgba(255,255,255,.14))', borderRadius: 8, padding: '8px 10px', background: 'var(--dsw-surface-sunken)', fontSize: 11 }, children: [(item.verdict?.criteria?.length ?? 0) > 0 && _jsxs("div", { style: { display: 'grid', gridTemplateColumns: 'minmax(120px,1fr) auto auto', gap: '4px 14px', marginBottom: 8 }, children: [_jsx("strong", { style: { color: 'var(--dsw-text-secondary)' }, children: t['recent.detail.criterion'] }), _jsx("strong", { style: { color: 'var(--dsw-text-secondary)' }, children: t['recent.detail.score'] }), _jsx("strong", { style: { color: 'var(--dsw-text-secondary)' }, children: t['recent.detail.threshold'] }), item.verdict.criteria.map(criterion => {
409
+ const threshold = typeof item.verdict.threshold === 'number' ? item.verdict.threshold : undefined;
410
+ const missed = threshold !== undefined && criterion.score < threshold;
411
+ return _jsxs(Fragment, { children: [_jsx("span", { children: criterion.id }), _jsx("span", { style: { color: missed ? '#e76565' : '#77d49b' }, children: formatPercentage(criterion.score) }), _jsx("span", { style: { color: 'var(--dsw-text-secondary)' }, children: threshold === undefined ? '—' : formatPercentage(threshold) })] }, criterion.id);
412
+ })] }), _jsxs("div", { style: { display: 'flex', flexWrap: 'wrap', gap: 10, color: 'var(--dsw-text-secondary)' }, children: [_jsx("span", { children: tFormat(t['recent.detail.calls'], { calls: compact(item.stats.calls, lang) }) }), _jsx("span", { children: tFormat(t['recent.detail.tokens'], { input: compact(item.stats.inputTokens, lang), cached: compact(item.stats.cachedInputTokens, lang), output: compact(item.stats.outputTokens, lang) }) }), _jsx("span", { children: tFormat(t['recent.detail.scoreCache'], { hits: compact(item.stats.cacheHits, lang), misses: compact(item.stats.cacheMisses, lang) }) }), _jsx("span", { children: tFormat(t['recent.detail.prefixCache'], { rate: ((item.stats.inputTokens + item.stats.cachedInputTokens) > 0 ? (100 * item.stats.cachedInputTokens / (item.stats.inputTokens + item.stats.cachedInputTokens)).toFixed(0) : '0') + '%' }) }), _jsx("span", { children: tFormat(t['recent.detail.cost'], { cost: money(item.stats.estimatedCostUsd) }) })] })] })] }), snapshot?.id === item.id && _jsxs("div", { style: { margin: '8px 0 2px 15px', border: '1px solid var(--dsw-alias-border-l2, rgba(255,255,255,.14))', borderRadius: 8, padding: '8px 10px', background: 'var(--dsw-surface-sunken)' }, children: [snapshot.error !== undefined && _jsx("div", { style: { fontSize: 11, color: '#e76565' }, children: snapshot.error }), snapshot.record === undefined && snapshot.error === undefined && _jsx("div", { style: { ...muted, fontSize: 11 }, children: t['recent.decisionLoading'] }), snapshot.record !== undefined && snapshot.record.calls.length === 0 && _jsx("div", { style: { ...muted, fontSize: 11 }, children: t['recent.decisionEmpty'] }), (snapshot.record?.calls ?? []).map((call, index) => _jsxs("div", { style: { marginBottom: index === snapshot.record.calls.length - 1 ? 0 : 10 }, children: [_jsxs("div", { style: { fontSize: 11, color: 'var(--dsw-text-secondary)' }, children: [call.label, " \u00B7 ", call.channel, call.score === undefined ? '' : ' · ' + formatPercentage(call.score)] }), _jsx("div", { style: { fontSize: 11, marginTop: 4 }, children: t['recent.decisionPrompt'] }), _jsx("pre", { style: { margin: 0, maxHeight: 180, overflow: 'auto', fontSize: 11, whiteSpace: 'pre-wrap', wordBreak: 'break-word', background: 'rgba(0,0,0,.2)', padding: '6px 8px', borderRadius: 6 }, children: call.prompt }), _jsx("div", { style: { fontSize: 11, marginTop: 4 }, children: t['recent.decisionOutput'] }), _jsx("pre", { style: { margin: 0, maxHeight: 140, overflow: 'auto', fontSize: 11, whiteSpace: 'pre-wrap', wordBreak: 'break-word', background: 'rgba(0,0,0,.2)', padding: '6px 8px', borderRadius: 6 }, children: call.output })] }, index))] })] }), _jsxs("div", { style: { textAlign: 'right' }, children: [_jsx("div", { style: { fontSize: 12 }, children: duration(item.durationMs) }), _jsx("div", { style: { ...muted, marginTop: 3 }, children: dateTime(item.startedAt, lang) })] })] }, item.id);
328
413
  }), (data?.recent.length ?? 0) === 0 && _jsx("div", { style: { padding: 24, textAlign: 'center', ...muted }, children: t['recent.empty'] })] })] }), _jsxs("div", { style: { ...dashboardCard, padding: '18px' }, children: [_jsx("strong", { children: t['models.title'] }), _jsxs("div", { style: { marginTop: 10, display: 'flex', flexDirection: 'column', gap: 10 }, children: [(data?.models ?? []).map(model => _jsxs("div", { style: { padding: '11px 12px', borderRadius: 10, background: 'var(--dsw-surface-sunken)' }, children: [_jsx("div", { style: { fontWeight: 650, fontSize: 13, overflow: 'hidden', textOverflow: 'ellipsis' }, children: model.model }), _jsx("div", { style: { ...muted, marginTop: 3 }, children: model.provider }), _jsxs("div", { style: { display: 'flex', justifyContent: 'space-between', marginTop: 9, fontSize: 12 }, children: [_jsx("span", { children: tFormat(t['models.calls'], { calls: compact(model.calls, lang) }) }), _jsx("span", { children: tFormat(t['models.tokens'], { tokens: compact(model.tokens, lang) }) }), _jsx("strong", { children: money(model.estimatedCostUsd) })] })] }, model.provider + '\0' + model.model)), (data?.models.length ?? 0) === 0 && _jsx("div", { style: muted, children: t['models.empty'] })] })] })] })] })] }) });
329
414
  }
330
415
  export function VerifierSidebarIcon({ size, active }) {