@prismatic-io/lux 0.0.2-preview.4 → 0.0.2-preview.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/lib/assertions/authoring.d.ts +2 -2
- package/lib/assertions/authoring.d.ts.map +1 -1
- package/lib/assertions/authoring.js.map +1 -1
- package/lib/assertions/core/index.d.ts.map +1 -1
- package/lib/assertions/core/index.js +2 -1
- package/lib/assertions/core/index.js.map +1 -1
- package/lib/assertions/core/resource-checks.d.ts +19 -0
- package/lib/assertions/core/resource-checks.d.ts.map +1 -1
- package/lib/assertions/core/resource-checks.js +32 -0
- package/lib/assertions/core/resource-checks.js.map +1 -1
- package/lib/cli/program.d.ts.map +1 -1
- package/lib/cli/program.js +6 -65
- package/lib/cli/program.js.map +1 -1
- package/lib/cli/view.d.ts +13 -0
- package/lib/cli/view.d.ts.map +1 -0
- package/lib/cli/view.js +126 -0
- package/lib/cli/view.js.map +1 -0
- package/lib/core/action-events.d.ts +29 -0
- package/lib/core/action-events.d.ts.map +1 -0
- package/lib/core/action-events.js +51 -0
- package/lib/core/action-events.js.map +1 -0
- package/lib/core/driver-metrics.d.ts +98 -0
- package/lib/core/driver-metrics.d.ts.map +1 -0
- package/lib/core/driver-metrics.js +36 -0
- package/lib/core/driver-metrics.js.map +1 -0
- package/lib/core/events.js +2 -2
- package/lib/core/experiment.d.ts +19 -0
- package/lib/core/experiment.d.ts.map +1 -1
- package/lib/core/experiment.js +2 -0
- package/lib/core/experiment.js.map +1 -1
- package/lib/core/index.d.ts +2 -0
- package/lib/core/index.d.ts.map +1 -1
- package/lib/core/index.js +2 -0
- package/lib/core/index.js.map +1 -1
- package/lib/core/run.d.ts +50 -0
- package/lib/core/run.d.ts.map +1 -1
- package/lib/core/run.js +6 -0
- package/lib/core/run.js.map +1 -1
- package/lib/index.d.ts +3 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +3 -1
- package/lib/index.js.map +1 -1
- package/lib/orchestrator/compare.d.ts +9 -1
- package/lib/orchestrator/compare.d.ts.map +1 -1
- package/lib/orchestrator/compare.js +8 -0
- package/lib/orchestrator/compare.js.map +1 -1
- package/lib/orchestrator/experiment-contracts.d.ts +19 -0
- package/lib/orchestrator/experiment-contracts.d.ts.map +1 -1
- package/lib/orchestrator/experiment-evaluation.d.ts.map +1 -1
- package/lib/orchestrator/experiment-evaluation.js +17 -0
- package/lib/orchestrator/experiment-evaluation.js.map +1 -1
- package/lib/orchestrator/experiment-report.d.ts +19 -0
- package/lib/orchestrator/experiment-report.d.ts.map +1 -1
- package/lib/orchestrator/experiment-runs.d.ts +38 -0
- package/lib/orchestrator/experiment-runs.d.ts.map +1 -1
- package/lib/orchestrator/index.d.ts +1 -1
- package/lib/orchestrator/index.d.ts.map +1 -1
- package/lib/orchestrator/index.js +1 -1
- package/lib/orchestrator/index.js.map +1 -1
- package/lib/orchestrator/list-runs.d.ts +6 -1
- package/lib/orchestrator/list-runs.d.ts.map +1 -1
- package/lib/orchestrator/list-runs.js +15 -1
- package/lib/orchestrator/list-runs.js.map +1 -1
- package/lib/orchestrator/run-execution.d.ts.map +1 -1
- package/lib/orchestrator/run-execution.js +11 -1
- package/lib/orchestrator/run-execution.js.map +1 -1
- package/lib/orchestrator/suite-compare.d.ts +34 -0
- package/lib/orchestrator/suite-compare.d.ts.map +1 -1
- package/lib/orchestrator/suite-summary.d.ts +68 -0
- package/lib/orchestrator/suite-summary.d.ts.map +1 -1
- package/lib/orchestrator/suite-summary.js +22 -7
- package/lib/orchestrator/suite-summary.js.map +1 -1
- package/lib/previewer/artifacts.d.ts +25 -0
- package/lib/previewer/artifacts.d.ts.map +1 -0
- package/lib/previewer/artifacts.js +180 -0
- package/lib/previewer/artifacts.js.map +1 -0
- package/lib/previewer/server.d.ts +104 -0
- package/lib/previewer/server.d.ts.map +1 -0
- package/lib/previewer/server.js +541 -0
- package/lib/previewer/server.js.map +1 -0
- package/package.json +2 -1
- package/skills/lux/references/eval-authoring.md +4 -2
- package/skills/lux-answerer/SKILL.md +1 -1
- package/src/assertions/authoring.ts +2 -0
- package/src/assertions/core/index.ts +2 -0
- package/src/assertions/core/resource-checks.ts +35 -0
- package/src/cli/program.ts +5 -91
- package/src/cli/view.ts +168 -0
- package/src/core/action-events.ts +59 -0
- package/src/core/driver-metrics.ts +51 -0
- package/src/core/events.ts +2 -2
- package/src/core/experiment.ts +2 -0
- package/src/core/index.ts +2 -0
- package/src/core/run.ts +6 -0
- package/src/index.ts +25 -0
- package/src/orchestrator/compare.ts +12 -0
- package/src/orchestrator/experiment-evaluation.ts +23 -0
- package/src/orchestrator/index.ts +1 -0
- package/src/orchestrator/list-runs.ts +25 -0
- package/src/orchestrator/run-execution.ts +12 -0
- package/src/orchestrator/suite-summary.ts +36 -8
- package/src/previewer/artifacts.ts +221 -0
- package/src/previewer/server.ts +763 -0
- package/viewer/app.css +2022 -0
- package/viewer/app.js +601 -0
- package/viewer/artifact-view.js +48 -0
- package/viewer/charts.js +86 -0
- package/viewer/detail.js +1108 -0
- package/viewer/format.js +129 -0
- package/viewer/index.html +151 -0
package/viewer/format.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
export const escapeHtml = (value) =>
|
|
2
|
+
String(value ?? "").replace(
|
|
3
|
+
/[&<>"']/g,
|
|
4
|
+
(character) =>
|
|
5
|
+
({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[character],
|
|
6
|
+
);
|
|
7
|
+
|
|
8
|
+
export const percentage = (value) =>
|
|
9
|
+
typeof value === "number" ? `${Math.round(value * 100)}%` : "—";
|
|
10
|
+
|
|
11
|
+
export const signedPercentage = (value) => {
|
|
12
|
+
if (typeof value !== "number") return "—";
|
|
13
|
+
const rounded = Math.round(value * 1_000) / 10;
|
|
14
|
+
return `${rounded > 0 ? "+" : ""}${rounded}%`;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export const duration = (milliseconds) => {
|
|
18
|
+
if (typeof milliseconds !== "number") return "—";
|
|
19
|
+
if (milliseconds < 1_000) return `${Math.round(milliseconds)}ms`;
|
|
20
|
+
if (milliseconds < 60_000) return `${(milliseconds / 1_000).toFixed(1)}s`;
|
|
21
|
+
return `${Math.floor(milliseconds / 60_000)}m ${Math.round((milliseconds % 60_000) / 1_000)}s`;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const signedDuration = (milliseconds) => {
|
|
25
|
+
if (typeof milliseconds !== "number") return "—";
|
|
26
|
+
return `${milliseconds > 0 ? "+" : ""}${duration(milliseconds)}`;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const compactNumber = (value) =>
|
|
30
|
+
new Intl.NumberFormat(undefined, { notation: "compact", maximumFractionDigits: 1 }).format(
|
|
31
|
+
value ?? 0,
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
export const relativeTime = (value) => {
|
|
35
|
+
if (!value) return "unknown";
|
|
36
|
+
const elapsed = Date.now() - Date.parse(value);
|
|
37
|
+
if (!Number.isFinite(elapsed)) return "unknown";
|
|
38
|
+
const minutes = Math.floor(elapsed / 60_000);
|
|
39
|
+
if (minutes < 1) return "now";
|
|
40
|
+
if (minutes < 60) return `${minutes}m`;
|
|
41
|
+
const hours = Math.floor(minutes / 60);
|
|
42
|
+
if (hours < 24) return `${hours}h`;
|
|
43
|
+
return `${Math.floor(hours / 24)}d`;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const fullDate = (value) => {
|
|
47
|
+
if (!value) return "—";
|
|
48
|
+
const date = new Date(value);
|
|
49
|
+
return Number.isNaN(date.valueOf())
|
|
50
|
+
? "—"
|
|
51
|
+
: new Intl.DateTimeFormat(undefined, {
|
|
52
|
+
month: "short",
|
|
53
|
+
day: "numeric",
|
|
54
|
+
hour: "numeric",
|
|
55
|
+
minute: "2-digit",
|
|
56
|
+
}).format(date);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const statusLabel = (status) =>
|
|
60
|
+
({
|
|
61
|
+
passed: "Passed",
|
|
62
|
+
failed: "Failed",
|
|
63
|
+
running: "Running",
|
|
64
|
+
aborted: "Aborted",
|
|
65
|
+
error: "Error",
|
|
66
|
+
promote: "Promote",
|
|
67
|
+
retain: "Retain",
|
|
68
|
+
reject: "Reject",
|
|
69
|
+
incomplete: "Incomplete",
|
|
70
|
+
})[status] ?? "Ungraded";
|
|
71
|
+
|
|
72
|
+
export const badge = (status) =>
|
|
73
|
+
`<span class="status-badge ${escapeHtml(status)}">${escapeHtml(statusLabel(status))}</span>`;
|
|
74
|
+
|
|
75
|
+
export const totalTokens = (usage = {}) =>
|
|
76
|
+
(usage.input ?? 0) + (usage.output ?? 0) + (usage.cacheRead ?? 0) + (usage.cacheCreation ?? 0);
|
|
77
|
+
|
|
78
|
+
export const toneForDelta = (value, lowerIsBetter = false) => {
|
|
79
|
+
if (!value) return "metric-neutral";
|
|
80
|
+
const better = lowerIsBetter ? value < 0 : value > 0;
|
|
81
|
+
return better ? "metric-good" : "metric-bad";
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const finite = (value, digits = 2) =>
|
|
85
|
+
typeof value === "number" && Number.isFinite(value)
|
|
86
|
+
? value.toLocaleString(undefined, { maximumFractionDigits: digits })
|
|
87
|
+
: "—";
|
|
88
|
+
|
|
89
|
+
const bytes = (value) => {
|
|
90
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return "—";
|
|
91
|
+
if (Math.abs(value) < 1_024) return `${finite(value)} B`;
|
|
92
|
+
if (Math.abs(value) < 1_048_576) return `${finite(value / 1_024)} KiB`;
|
|
93
|
+
return `${finite(value / 1_048_576)} MiB`;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
export const metricValue = (value, unit = "number") => {
|
|
97
|
+
if (unit === "milliseconds") return duration(value);
|
|
98
|
+
if (unit === "bytes") return bytes(value);
|
|
99
|
+
if (unit === "tokens") return typeof value === "number" ? `${compactNumber(value)} tokens` : "—";
|
|
100
|
+
if (unit === "usd") return typeof value === "number" ? `$${finite(value, 4)}` : "—";
|
|
101
|
+
if (unit === "ratio" || unit === "score") return percentage(value);
|
|
102
|
+
if (unit === "percent") return typeof value === "number" ? `${finite(value)}%` : "—";
|
|
103
|
+
return finite(value);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export const metricName = (name, label) => {
|
|
107
|
+
if (label) return label;
|
|
108
|
+
const tail =
|
|
109
|
+
String(name)
|
|
110
|
+
.replace(/^driver\./, "")
|
|
111
|
+
.split(".")
|
|
112
|
+
.at(-1) ?? String(name);
|
|
113
|
+
return tail
|
|
114
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
|
115
|
+
.replace(/[-_]+/g, " ")
|
|
116
|
+
.replace(/^./, (character) => character.toUpperCase());
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
export const detailLoading = (label) =>
|
|
120
|
+
`<div class="loading-card"><span></span><span></span><span></span><p>${escapeHtml(label)}</p></div>`;
|
|
121
|
+
|
|
122
|
+
export const detailError = (message) => `<div class="error-card">${escapeHtml(message)}</div>`;
|
|
123
|
+
|
|
124
|
+
export const detailEmpty = () => `
|
|
125
|
+
<div class="inspector-empty">
|
|
126
|
+
<span class="empty-glyph" aria-hidden="true">↗</span>
|
|
127
|
+
<h2>Select evidence to inspect</h2>
|
|
128
|
+
<p>Scores, assertions, traces, spend, and artifacts meet here.</p>
|
|
129
|
+
</div>`;
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<meta name="color-scheme" content="dark" />
|
|
7
|
+
<meta name="theme-color" content="#0b0d0f" />
|
|
8
|
+
<meta
|
|
9
|
+
name="description"
|
|
10
|
+
content="A local review cockpit for Lux evaluation runs and experiments."
|
|
11
|
+
/>
|
|
12
|
+
<title>Lux Review</title>
|
|
13
|
+
<link rel="stylesheet" href="/assets/app.css" />
|
|
14
|
+
<script src="/assets/app.js" type="module"></script>
|
|
15
|
+
</head>
|
|
16
|
+
<body>
|
|
17
|
+
<div class="app-shell">
|
|
18
|
+
<aside class="sidebar">
|
|
19
|
+
<a class="brand" href="/" aria-label="Lux Review home">
|
|
20
|
+
<span class="brand-mark" aria-hidden="true">LX</span>
|
|
21
|
+
<span>
|
|
22
|
+
<strong>LUX</strong>
|
|
23
|
+
<small>REVIEW</small>
|
|
24
|
+
</span>
|
|
25
|
+
</a>
|
|
26
|
+
|
|
27
|
+
<nav class="primary-nav" aria-label="Evidence type">
|
|
28
|
+
<button class="nav-item is-active" type="button" data-tab="runs">
|
|
29
|
+
<span class="nav-glyph" aria-hidden="true">R</span>
|
|
30
|
+
<span>Runs</span>
|
|
31
|
+
<span class="nav-count" data-count="runs">0</span>
|
|
32
|
+
</button>
|
|
33
|
+
<button class="nav-item" type="button" data-tab="suites">
|
|
34
|
+
<span class="nav-glyph" aria-hidden="true">S</span>
|
|
35
|
+
<span>Suites</span>
|
|
36
|
+
<span class="nav-count" data-count="suites">0</span>
|
|
37
|
+
</button>
|
|
38
|
+
<button class="nav-item" type="button" data-tab="experiments">
|
|
39
|
+
<span class="nav-glyph" aria-hidden="true">E</span>
|
|
40
|
+
<span>Experiments</span>
|
|
41
|
+
<span class="nav-count" data-count="experiments">0</span>
|
|
42
|
+
</button>
|
|
43
|
+
</nav>
|
|
44
|
+
|
|
45
|
+
<div class="sidebar-note">
|
|
46
|
+
<span class="pulse-dot" aria-hidden="true"></span>
|
|
47
|
+
<span>
|
|
48
|
+
<strong>Local evidence</strong>
|
|
49
|
+
<small>Read-only · auto-refreshing</small>
|
|
50
|
+
</span>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<div class="shortcut-card">
|
|
54
|
+
<p>Shortcuts</p>
|
|
55
|
+
<dl>
|
|
56
|
+
<div class="shortcut-row"><dt><kbd>/</kbd></dt><dd>Search</dd></div>
|
|
57
|
+
<div class="shortcut-row"><dt><kbd>J</kbd> <kbd>K</kbd></dt><dd>Move</dd></div>
|
|
58
|
+
<div class="shortcut-row"><dt><kbd>R</kbd></dt><dd>Refresh</dd></div>
|
|
59
|
+
</dl>
|
|
60
|
+
</div>
|
|
61
|
+
</aside>
|
|
62
|
+
|
|
63
|
+
<main>
|
|
64
|
+
<header class="topbar">
|
|
65
|
+
<div>
|
|
66
|
+
<span class="eyebrow">Evaluation evidence</span>
|
|
67
|
+
<h1>Evidence, at a glance.</h1>
|
|
68
|
+
</div>
|
|
69
|
+
<div class="topbar-actions">
|
|
70
|
+
<label class="search">
|
|
71
|
+
<span aria-hidden="true">⌕</span>
|
|
72
|
+
<input
|
|
73
|
+
id="search-input"
|
|
74
|
+
type="search"
|
|
75
|
+
placeholder="Search cases, drivers, campaigns…"
|
|
76
|
+
autocomplete="off"
|
|
77
|
+
/>
|
|
78
|
+
<kbd>/</kbd>
|
|
79
|
+
</label>
|
|
80
|
+
<button class="icon-button" id="refresh-button" type="button" aria-label="Refresh data">
|
|
81
|
+
↻
|
|
82
|
+
</button>
|
|
83
|
+
</div>
|
|
84
|
+
</header>
|
|
85
|
+
|
|
86
|
+
<section class="metrics" aria-label="Evidence summary">
|
|
87
|
+
<article>
|
|
88
|
+
<span>Graded pass rate</span>
|
|
89
|
+
<strong id="metric-pass-rate">—</strong>
|
|
90
|
+
<small id="metric-pass-note">No graded runs</small>
|
|
91
|
+
</article>
|
|
92
|
+
<article>
|
|
93
|
+
<span>Needs attention</span>
|
|
94
|
+
<strong id="metric-failures">0</strong>
|
|
95
|
+
<small>Failed or errored runs</small>
|
|
96
|
+
</article>
|
|
97
|
+
<article>
|
|
98
|
+
<span>Experiment activity</span>
|
|
99
|
+
<strong id="metric-experiments">0</strong>
|
|
100
|
+
<small id="metric-experiment-note">No campaigns yet</small>
|
|
101
|
+
</article>
|
|
102
|
+
<article>
|
|
103
|
+
<span>Last evidence</span>
|
|
104
|
+
<strong id="metric-recency">—</strong>
|
|
105
|
+
<small id="metric-refresh">Waiting for local data</small>
|
|
106
|
+
</article>
|
|
107
|
+
</section>
|
|
108
|
+
|
|
109
|
+
<section class="workspace">
|
|
110
|
+
<div class="collection-pane">
|
|
111
|
+
<div class="collection-toolbar">
|
|
112
|
+
<div>
|
|
113
|
+
<span class="eyebrow" id="collection-eyebrow">Individual evidence</span>
|
|
114
|
+
<h2 id="collection-title">Runs</h2>
|
|
115
|
+
</div>
|
|
116
|
+
<div class="collection-actions">
|
|
117
|
+
<span class="result-count" id="result-count">0 records</span>
|
|
118
|
+
<button class="compare-button" id="compare-button" type="button">Compare</button>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
<div class="compare-tray" id="compare-tray" hidden></div>
|
|
122
|
+
<fieldset
|
|
123
|
+
class="status-filters"
|
|
124
|
+
id="status-filters"
|
|
125
|
+
aria-label="Filter by status"
|
|
126
|
+
></fieldset>
|
|
127
|
+
<div class="collection-list" id="collection-list" aria-live="polite">
|
|
128
|
+
<div class="loading-card">
|
|
129
|
+
<span></span><span></span><span></span>
|
|
130
|
+
<p>Reading Lux evidence…</p>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
|
|
135
|
+
<aside class="inspector" id="inspector" aria-label="Evidence detail">
|
|
136
|
+
<div class="inspector-empty">
|
|
137
|
+
<span class="empty-glyph" aria-hidden="true">↗</span>
|
|
138
|
+
<h2>Select evidence to inspect</h2>
|
|
139
|
+
<p>Scores, assertions, traces, spend, and artifacts meet here.</p>
|
|
140
|
+
</div>
|
|
141
|
+
</aside>
|
|
142
|
+
</section>
|
|
143
|
+
|
|
144
|
+
<footer>
|
|
145
|
+
<span id="runs-root">Local Lux run store</span>
|
|
146
|
+
<span id="connection-state"><i></i> Connected</span>
|
|
147
|
+
</footer>
|
|
148
|
+
</main>
|
|
149
|
+
</div>
|
|
150
|
+
</body>
|
|
151
|
+
</html>
|