inspect-ai 0.3.108__py3-none-any.whl → 0.3.109__py3-none-any.whl
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.
- inspect_ai/_eval/task/log.py +1 -1
- inspect_ai/_eval/task/run.py +1 -1
- inspect_ai/_util/dateutil.py +40 -0
- inspect_ai/_view/schema.py +11 -0
- inspect_ai/_view/www/CLAUDE.md +1 -1
- inspect_ai/_view/www/dist/assets/index.css +2068 -1796
- inspect_ai/_view/www/dist/assets/index.js +7951 -3643
- inspect_ai/_view/www/package.json +3 -2
- inspect_ai/_view/www/src/@types/log.d.ts +5 -5
- inspect_ai/_view/www/src/app/App.css +71 -4
- inspect_ai/_view/www/src/app/App.tsx +7 -0
- inspect_ai/_view/www/src/app/appearance/icons.ts +18 -2
- inspect_ai/_view/www/src/app/content/RenderedContent.tsx +7 -9
- inspect_ai/_view/www/src/app/log-list/LogItem.ts +18 -0
- inspect_ai/_view/www/src/app/log-list/LogListFooter.module.css +55 -0
- inspect_ai/_view/www/src/app/log-list/LogListFooter.tsx +67 -0
- inspect_ai/_view/www/src/app/log-list/LogPager.module.css +29 -0
- inspect_ai/_view/www/src/app/log-list/LogPager.tsx +134 -0
- inspect_ai/_view/www/src/app/log-list/LogsFilterInput.module.css +5 -0
- inspect_ai/_view/www/src/app/log-list/LogsFilterInput.tsx +31 -0
- inspect_ai/_view/www/src/app/log-list/LogsPanel.module.css +12 -0
- inspect_ai/_view/www/src/app/log-list/LogsPanel.tsx +178 -0
- inspect_ai/_view/www/src/app/log-list/grid/LogListGrid.module.css +115 -0
- inspect_ai/_view/www/src/app/log-list/grid/LogListGrid.tsx +304 -0
- inspect_ai/_view/www/src/app/log-list/grid/columns/CompletedDate.module.css +6 -0
- inspect_ai/_view/www/src/app/log-list/grid/columns/CompletedDate.tsx +64 -0
- inspect_ai/_view/www/src/app/log-list/grid/columns/EmptyCell.module.css +3 -0
- inspect_ai/_view/www/src/app/log-list/grid/columns/EmptyCell.tsx +7 -0
- inspect_ai/_view/www/src/app/log-list/grid/columns/FileName.module.css +20 -0
- inspect_ai/_view/www/src/app/log-list/grid/columns/FileName.tsx +52 -0
- inspect_ai/_view/www/src/app/log-list/grid/columns/Icon.module.css +11 -0
- inspect_ai/_view/www/src/app/log-list/grid/columns/Icon.tsx +35 -0
- inspect_ai/_view/www/src/app/log-list/grid/columns/Model.module.css +6 -0
- inspect_ai/_view/www/src/app/log-list/grid/columns/Model.tsx +34 -0
- inspect_ai/_view/www/src/app/log-list/grid/columns/Score.module.css +6 -0
- inspect_ai/_view/www/src/app/log-list/grid/columns/Score.tsx +61 -0
- inspect_ai/_view/www/src/app/log-list/grid/columns/Status.module.css +15 -0
- inspect_ai/_view/www/src/app/log-list/grid/columns/Status.tsx +95 -0
- inspect_ai/_view/www/src/app/log-list/grid/columns/Task.module.css +20 -0
- inspect_ai/_view/www/src/app/log-list/grid/columns/Task.tsx +50 -0
- inspect_ai/_view/www/src/app/log-list/grid/columns/columns.ts +27 -0
- inspect_ai/_view/www/src/app/log-view/LogView.tsx +2 -5
- inspect_ai/_view/www/src/app/log-view/LogViewContainer.tsx +4 -30
- inspect_ai/_view/www/src/app/log-view/LogViewLayout.tsx +5 -30
- inspect_ai/_view/www/src/app/log-view/tabs/TaskTab.tsx +4 -7
- inspect_ai/_view/www/src/app/log-view/{navbar → title-view}/PrimaryBar.module.css +2 -0
- inspect_ai/_view/www/src/app/log-view/{navbar → title-view}/PrimaryBar.tsx +3 -31
- inspect_ai/_view/www/src/app/log-view/{navbar → title-view}/ResultsPanel.tsx +7 -57
- inspect_ai/_view/www/src/app/log-view/{navbar → title-view}/ScoreGrid.tsx +2 -2
- inspect_ai/_view/www/src/app/log-view/{navbar → title-view}/SecondaryBar.tsx +7 -1
- inspect_ai/_view/www/src/app/log-view/{navbar/Navbar.tsx → title-view/TitleView.tsx} +3 -6
- inspect_ai/_view/www/src/app/navbar/Navbar.module.css +57 -0
- inspect_ai/_view/www/src/app/navbar/Navbar.tsx +117 -0
- inspect_ai/_view/www/src/app/navbar/useBreadcrumbTruncation.ts +128 -0
- inspect_ai/_view/www/src/app/plan/DatasetDetailView.tsx +3 -3
- inspect_ai/_view/www/src/app/plan/DetailStep.tsx +6 -6
- inspect_ai/_view/www/src/app/plan/PlanDetailView.module.css +1 -0
- inspect_ai/_view/www/src/app/plan/ScorerDetailView.tsx +1 -1
- inspect_ai/_view/www/src/app/routing/AppRouter.tsx +28 -4
- inspect_ai/_view/www/src/app/routing/RouteDispatcher.tsx +28 -0
- inspect_ai/_view/www/src/app/routing/sampleNavigation.ts +76 -7
- inspect_ai/_view/www/src/app/routing/url.ts +193 -20
- inspect_ai/_view/www/src/app/samples/SampleDisplay.tsx +3 -17
- inspect_ai/_view/www/src/app/samples/descriptor/score/ScoreDescriptor.tsx +1 -1
- inspect_ai/_view/www/src/app/samples/transcript/SubtaskEventView.tsx +2 -2
- inspect_ai/_view/www/src/app/samples/transcript/TranscriptPanel.tsx +2 -2
- inspect_ai/_view/www/src/app/samples/transcript/outline/tree-visitors.ts +5 -0
- inspect_ai/_view/www/src/app/samples/transcript/transform/treeify.ts +26 -10
- inspect_ai/_view/www/src/app/types.ts +21 -1
- inspect_ai/_view/www/src/client/api/api-http.ts +2 -1
- inspect_ai/_view/www/src/client/api/api-shared.ts +0 -32
- inspect_ai/_view/www/src/client/api/client-api.ts +1 -1
- inspect_ai/_view/www/src/client/remote/remoteLogFile.ts +38 -6
- inspect_ai/_view/www/src/components/TextInput.module.css +45 -0
- inspect_ai/_view/www/src/components/TextInput.tsx +52 -0
- inspect_ai/_view/www/src/constants.ts +18 -0
- inspect_ai/_view/www/src/img/inspect-16.svg +10 -0
- inspect_ai/_view/www/src/img/inspect-back.svg +5 -0
- inspect_ai/_view/www/src/img/inspect-file.svg +26 -0
- inspect_ai/_view/www/src/img/inspect-forward.svg +7 -0
- inspect_ai/_view/www/src/img/inspect-home.svg +18 -0
- inspect_ai/_view/www/src/scoring/metrics.ts +75 -0
- inspect_ai/_view/www/src/scoring/scores.ts +19 -0
- inspect_ai/_view/www/src/scoring/types.ts +11 -0
- inspect_ai/_view/www/src/state/appSlice.ts +27 -7
- inspect_ai/_view/www/src/state/clientEvents.ts +73 -0
- inspect_ai/_view/www/src/state/clientEventsService.ts +105 -0
- inspect_ai/_view/www/src/state/hooks.ts +118 -1
- inspect_ai/_view/www/src/state/log.ts +19 -0
- inspect_ai/_view/www/src/state/logPolling.ts +3 -1
- inspect_ai/_view/www/src/state/logSlice.ts +9 -0
- inspect_ai/_view/www/src/state/logsSlice.ts +157 -15
- inspect_ai/_view/www/src/state/samplePolling.ts +4 -2
- inspect_ai/_view/www/src/tests/utils/path.test.ts +3 -3
- inspect_ai/_view/www/src/utils/evallog.ts +31 -0
- inspect_ai/_view/www/src/utils/path.ts +28 -0
- inspect_ai/_view/www/src/utils/uri.ts +49 -0
- inspect_ai/_view/www/yarn.lock +54 -17
- inspect_ai/analysis/beta/_dataframe/util.py +106 -10
- inspect_ai/log/_recorders/buffer/database.py +55 -16
- inspect_ai/model/_model.py +1 -1
- inspect_ai/model/_providers/providers.py +2 -2
- inspect_ai/model/_providers/vertex.py +3 -0
- inspect_ai/tool/_mcp/_mcp.py +6 -1
- inspect_ai/tool/_mcp/sampling.py +8 -1
- inspect_ai/tool/_tools/_bash_session.py +3 -6
- inspect_ai/tool/_tools/_web_browser/_web_browser.py +3 -8
- inspect_ai/util/_anyio.py +12 -3
- {inspect_ai-0.3.108.dist-info → inspect_ai-0.3.109.dist-info}/METADATA +2 -2
- {inspect_ai-0.3.108.dist-info → inspect_ai-0.3.109.dist-info}/RECORD +124 -94
- inspect_ai/_util/datetime.py +0 -10
- inspect_ai/_view/www/src/app/content/MetaDataView.module.css +0 -35
- inspect_ai/_view/www/src/app/content/MetaDataView.tsx +0 -101
- inspect_ai/_view/www/src/app/log-view/utils.ts +0 -34
- inspect_ai/_view/www/src/app/sidebar/EvalStatus.module.css +0 -15
- inspect_ai/_view/www/src/app/sidebar/EvalStatus.tsx +0 -72
- inspect_ai/_view/www/src/app/sidebar/LogDirectoryTitleView.module.css +0 -16
- inspect_ai/_view/www/src/app/sidebar/LogDirectoryTitleView.tsx +0 -70
- inspect_ai/_view/www/src/app/sidebar/Sidebar.module.css +0 -77
- inspect_ai/_view/www/src/app/sidebar/Sidebar.tsx +0 -119
- inspect_ai/_view/www/src/app/sidebar/SidebarLogEntry.module.css +0 -29
- inspect_ai/_view/www/src/app/sidebar/SidebarLogEntry.tsx +0 -96
- inspect_ai/_view/www/src/app/sidebar/SidebarScoreView.module.css +0 -23
- inspect_ai/_view/www/src/app/sidebar/SidebarScoreView.tsx +0 -44
- inspect_ai/_view/www/src/app/sidebar/SidebarScoresView.module.css +0 -35
- inspect_ai/_view/www/src/app/sidebar/SidebarScoresView.tsx +0 -63
- inspect_ai/_view/www/src/state/logsPolling.ts +0 -118
- /inspect_ai/_view/www/src/app/log-view/{navbar → title-view}/ModelRolesView.module.css +0 -0
- /inspect_ai/_view/www/src/app/log-view/{navbar → title-view}/ModelRolesView.tsx +0 -0
- /inspect_ai/_view/www/src/app/log-view/{navbar → title-view}/ResultsPanel.module.css +0 -0
- /inspect_ai/_view/www/src/app/log-view/{navbar → title-view}/RunningStatusPanel.module.css +0 -0
- /inspect_ai/_view/www/src/app/log-view/{navbar → title-view}/RunningStatusPanel.tsx +0 -0
- /inspect_ai/_view/www/src/app/log-view/{navbar → title-view}/ScoreGrid.module.css +0 -0
- /inspect_ai/_view/www/src/app/log-view/{navbar → title-view}/SecondaryBar.module.css +0 -0
- /inspect_ai/_view/www/src/app/log-view/{navbar → title-view}/StatusPanel.module.css +0 -0
- /inspect_ai/_view/www/src/app/log-view/{navbar → title-view}/StatusPanel.tsx +0 -0
- /inspect_ai/_view/www/src/app/log-view/{navbar/Navbar.module.css → title-view/TitleView.module.css} +0 -0
- {inspect_ai-0.3.108.dist-info → inspect_ai-0.3.109.dist-info}/WHEEL +0 -0
- {inspect_ai-0.3.108.dist-info → inspect_ai-0.3.109.dist-info}/entry_points.txt +0 -0
- {inspect_ai-0.3.108.dist-info → inspect_ai-0.3.109.dist-info}/licenses/LICENSE +0 -0
- {inspect_ai-0.3.108.dist-info → inspect_ai-0.3.109.dist-info}/top_level.txt +0 -0
@@ -1,24 +1,19 @@
|
|
1
1
|
import clsx from "clsx";
|
2
|
-
import { FC
|
2
|
+
import { FC } from "react";
|
3
3
|
import { EvalResults, EvalSpec, Status } from "../../../@types/log";
|
4
4
|
import { RunningMetric } from "../../../client/api/types";
|
5
5
|
import { CopyButton } from "../../../components/CopyButton";
|
6
6
|
import { kModelNone } from "../../../constants";
|
7
|
+
import { toDisplayScorers } from "../../../scoring/metrics";
|
7
8
|
import { useStore } from "../../../state/store";
|
8
9
|
import { filename } from "../../../utils/path";
|
9
|
-
import { ApplicationIcons } from "../../appearance/icons";
|
10
10
|
import { ModelRolesView } from "./ModelRolesView";
|
11
11
|
import styles from "./PrimaryBar.module.css";
|
12
|
-
import {
|
13
|
-
displayScorersFromRunningMetrics,
|
14
|
-
ResultsPanel,
|
15
|
-
toDisplayScorers,
|
16
|
-
} from "./ResultsPanel";
|
12
|
+
import { displayScorersFromRunningMetrics, ResultsPanel } from "./ResultsPanel";
|
17
13
|
import { RunningStatusPanel } from "./RunningStatusPanel";
|
18
14
|
import { CancelledPanel, ErroredPanel } from "./StatusPanel";
|
19
15
|
|
20
16
|
interface PrimaryBarProps {
|
21
|
-
showToggle: boolean;
|
22
17
|
status?: Status;
|
23
18
|
evalResults?: EvalResults | null;
|
24
19
|
runningMetrics?: RunningMetric[];
|
@@ -27,24 +22,17 @@ interface PrimaryBarProps {
|
|
27
22
|
}
|
28
23
|
|
29
24
|
export const PrimaryBar: FC<PrimaryBarProps> = ({
|
30
|
-
showToggle,
|
31
25
|
status,
|
32
26
|
evalResults,
|
33
27
|
runningMetrics,
|
34
28
|
evalSpec,
|
35
29
|
sampleCount,
|
36
30
|
}) => {
|
37
|
-
const offCanvas = useStore((state) => state.app.offcanvas);
|
38
|
-
const setOffCanvas = useStore((state) => state.appActions.setOffcanvas);
|
39
31
|
const streamSamples = useStore((state) => state.capabilities.streamSamples);
|
40
32
|
const selectedLogFile = useStore((state) => state.logs.selectedLogFile);
|
41
33
|
|
42
34
|
const logFileName = selectedLogFile ? filename(selectedLogFile) : "";
|
43
35
|
|
44
|
-
const handleToggle = useCallback(() => {
|
45
|
-
setOffCanvas(!offCanvas);
|
46
|
-
}, [offCanvas, setOffCanvas]);
|
47
|
-
|
48
36
|
const hasRunningMetrics = runningMetrics && runningMetrics.length > 0;
|
49
37
|
|
50
38
|
return (
|
@@ -57,22 +45,6 @@ export const PrimaryBar: FC<PrimaryBarProps> = ({
|
|
57
45
|
styles.container,
|
58
46
|
)}
|
59
47
|
>
|
60
|
-
{showToggle ? (
|
61
|
-
<button
|
62
|
-
id="sidebarToggle"
|
63
|
-
onClick={handleToggle}
|
64
|
-
className={clsx(
|
65
|
-
"btn",
|
66
|
-
offCanvas ? "d-md-none" : undefined,
|
67
|
-
styles.toggle,
|
68
|
-
)}
|
69
|
-
type="button"
|
70
|
-
>
|
71
|
-
<i className={ApplicationIcons.menu}></i>
|
72
|
-
</button>
|
73
|
-
) : (
|
74
|
-
""
|
75
|
-
)}
|
76
48
|
<div className={styles.body}>
|
77
49
|
<div className={styles.bodyContainer}>
|
78
50
|
<div
|
@@ -1,27 +1,16 @@
|
|
1
1
|
import clsx from "clsx";
|
2
2
|
import { FC } from "react";
|
3
|
-
import { Scores } from "../../../@types/log";
|
4
3
|
import { RunningMetric } from "../../../client/api/types";
|
5
4
|
import { LinkButton } from "../../../components/LinkButton";
|
6
5
|
import { Modal } from "../../../components/Modal";
|
6
|
+
import { metricDisplayName } from "../../../scoring/metrics";
|
7
|
+
import { groupScorers } from "../../../scoring/scores";
|
8
|
+
import { MetricSummary, ScoreSummary } from "../../../scoring/types";
|
7
9
|
import { useProperty } from "../../../state/hooks";
|
8
10
|
import { formatPrettyDecimal } from "../../../utils/format";
|
9
|
-
import { metricDisplayName } from "../utils";
|
10
11
|
import styles from "./ResultsPanel.module.css";
|
11
12
|
import { ScoreGrid } from "./ScoreGrid";
|
12
13
|
|
13
|
-
export interface ResultsMetric {
|
14
|
-
name: string;
|
15
|
-
params?: {};
|
16
|
-
value: number;
|
17
|
-
}
|
18
|
-
|
19
|
-
export interface ResultsScorer {
|
20
|
-
scorer: string;
|
21
|
-
reducer?: string;
|
22
|
-
metrics: ResultsMetric[];
|
23
|
-
}
|
24
|
-
|
25
14
|
const kMaxPrimaryScoreRows = 4;
|
26
15
|
|
27
16
|
export const displayScorersFromRunningMetrics = (metrics?: RunningMetric[]) => {
|
@@ -35,7 +24,7 @@ export const displayScorersFromRunningMetrics = (metrics?: RunningMetric[]) => {
|
|
35
24
|
: metric.scorer;
|
36
25
|
};
|
37
26
|
|
38
|
-
const scorers: Record<string,
|
27
|
+
const scorers: Record<string, ScoreSummary> = {};
|
39
28
|
metrics.forEach((metric) => {
|
40
29
|
if (metric.value !== undefined && metric.value !== null) {
|
41
30
|
const key = getKey(metric);
|
@@ -62,29 +51,8 @@ export const displayScorersFromRunningMetrics = (metrics?: RunningMetric[]) => {
|
|
62
51
|
return Object.values(scorers);
|
63
52
|
};
|
64
53
|
|
65
|
-
export const toDisplayScorers = (scores?: Scores): ResultsScorer[] => {
|
66
|
-
if (!scores) {
|
67
|
-
return [];
|
68
|
-
}
|
69
|
-
|
70
|
-
return scores.map((score) => {
|
71
|
-
return {
|
72
|
-
scorer: score.name,
|
73
|
-
reducer: score.reducer === null ? undefined : score.reducer,
|
74
|
-
metrics: Object.keys(score.metrics).map((key) => {
|
75
|
-
const metric = score.metrics[key];
|
76
|
-
return {
|
77
|
-
name: metric.name,
|
78
|
-
value: metric.value,
|
79
|
-
params: metric.params,
|
80
|
-
};
|
81
|
-
}),
|
82
|
-
};
|
83
|
-
});
|
84
|
-
};
|
85
|
-
|
86
54
|
interface ResultsPanelProps {
|
87
|
-
scorers?:
|
55
|
+
scorers?: ScoreSummary[];
|
88
56
|
}
|
89
57
|
|
90
58
|
export const ResultsPanel: FC<ResultsPanelProps> = ({ scorers }) => {
|
@@ -121,7 +89,7 @@ export const ResultsPanel: FC<ResultsPanelProps> = ({ scorers }) => {
|
|
121
89
|
);
|
122
90
|
} else {
|
123
91
|
const showReducer = scorers.findIndex((score) => !!score.reducer) !== -1;
|
124
|
-
const grouped =
|
92
|
+
const grouped = groupScorers(scorers);
|
125
93
|
|
126
94
|
// Try to select metrics with a group size 5 or less, if possible
|
127
95
|
let primaryResults = grouped[0];
|
@@ -174,26 +142,8 @@ export const ResultsPanel: FC<ResultsPanelProps> = ({ scorers }) => {
|
|
174
142
|
}
|
175
143
|
};
|
176
144
|
|
177
|
-
const metricsKey = (metrics: ResultsMetric[]): string => {
|
178
|
-
const metricKey = metrics.map((m) => m.name).join("");
|
179
|
-
return metricKey;
|
180
|
-
};
|
181
|
-
|
182
|
-
const groupMetrics = (scorers: ResultsScorer[]): ResultsScorer[][] => {
|
183
|
-
const results: Record<string, ResultsScorer[]> = {};
|
184
|
-
scorers.forEach((scorer) => {
|
185
|
-
if (scorer.metrics.length > 0) {
|
186
|
-
const key = metricsKey(scorer.metrics);
|
187
|
-
results[key] = results[key] || [];
|
188
|
-
|
189
|
-
results[key].push(scorer);
|
190
|
-
}
|
191
|
-
});
|
192
|
-
return Object.values(results);
|
193
|
-
};
|
194
|
-
|
195
145
|
interface VerticalMetricProps {
|
196
|
-
metric:
|
146
|
+
metric: MetricSummary;
|
197
147
|
reducer?: string;
|
198
148
|
isFirst: boolean;
|
199
149
|
showReducer: boolean;
|
@@ -1,12 +1,12 @@
|
|
1
1
|
import clsx from "clsx";
|
2
2
|
import { FC, ReactNode } from "react";
|
3
3
|
import { formatPrettyDecimal } from "../../../utils/format";
|
4
|
-
import { ResultsScorer } from "./ResultsPanel";
|
5
4
|
|
5
|
+
import { ScoreSummary } from "../../../scoring/types";
|
6
6
|
import styles from "./ScoreGrid.module.css";
|
7
7
|
|
8
8
|
interface ScoreGridProps {
|
9
|
-
scoreGroups:
|
9
|
+
scoreGroups: ScoreSummary[][];
|
10
10
|
showReducer?: boolean;
|
11
11
|
className?: string | string[];
|
12
12
|
striped?: boolean;
|
@@ -215,7 +215,13 @@ const ParamSummary: FC<ParamSummaryProps> = ({ params }) => {
|
|
215
215
|
});
|
216
216
|
if (paraValues.length > 0) {
|
217
217
|
return (
|
218
|
-
<code
|
218
|
+
<code
|
219
|
+
style={{
|
220
|
+
padding: 0,
|
221
|
+
color: "var(--bs-body-color)",
|
222
|
+
overflowWrap: "anywhere",
|
223
|
+
}}
|
224
|
+
>
|
219
225
|
{paraValues.join(", ")}
|
220
226
|
</code>
|
221
227
|
);
|
@@ -9,29 +9,27 @@ import {
|
|
9
9
|
} from "../../../@types/log";
|
10
10
|
import { RunningMetric } from "../../../client/api/types";
|
11
11
|
import { useTotalSampleCount } from "../../../state/hooks";
|
12
|
-
import styles from "./Navbar.module.css";
|
13
12
|
import { PrimaryBar } from "./PrimaryBar";
|
14
13
|
import { SecondaryBar } from "./SecondaryBar";
|
14
|
+
import styles from "./TitleView.module.css";
|
15
15
|
|
16
|
-
interface
|
16
|
+
interface TitleViewProps {
|
17
17
|
evalSpec?: EvalSpec;
|
18
18
|
evalResults?: EvalResults | null;
|
19
19
|
runningMetrics?: RunningMetric[];
|
20
20
|
evalPlan?: EvalPlan;
|
21
21
|
evalStats?: EvalStats;
|
22
22
|
status?: Status;
|
23
|
-
showToggle: boolean;
|
24
23
|
}
|
25
24
|
|
26
25
|
/**
|
27
26
|
* Renders the Navbar
|
28
27
|
*/
|
29
|
-
export const
|
28
|
+
export const TitleView: FC<TitleViewProps> = ({
|
30
29
|
evalSpec,
|
31
30
|
evalPlan,
|
32
31
|
evalResults,
|
33
32
|
evalStats,
|
34
|
-
showToggle,
|
35
33
|
status,
|
36
34
|
runningMetrics,
|
37
35
|
}) => {
|
@@ -41,7 +39,6 @@ export const Navbar: FC<NavBarProps> = ({
|
|
41
39
|
<PrimaryBar
|
42
40
|
evalSpec={evalSpec}
|
43
41
|
evalResults={evalResults}
|
44
|
-
showToggle={showToggle}
|
45
42
|
status={status}
|
46
43
|
runningMetrics={runningMetrics}
|
47
44
|
sampleCount={totalSampleCount}
|
@@ -0,0 +1,57 @@
|
|
1
|
+
.header {
|
2
|
+
border-bottom: solid var(--bs-border-color) 1px;
|
3
|
+
background: var(--bs-light);
|
4
|
+
display: grid;
|
5
|
+
grid-template-columns: 1fr max-content;
|
6
|
+
justify-content: space-between;
|
7
|
+
padding: 0.2em 0.5em;
|
8
|
+
--bs-breadcrumb-divider: ">";
|
9
|
+
overflow: hidden;
|
10
|
+
}
|
11
|
+
|
12
|
+
.breadcrumbs {
|
13
|
+
border-left: solid var(--bs-border-color) 1px;
|
14
|
+
padding-left: 0.5em;
|
15
|
+
margin-bottom: 0;
|
16
|
+
min-width: 0;
|
17
|
+
overflow: hidden;
|
18
|
+
width: max-content;
|
19
|
+
display: flex;
|
20
|
+
flex-wrap: nowrap;
|
21
|
+
}
|
22
|
+
|
23
|
+
.ellipsis {
|
24
|
+
color: var(--bs-secondary);
|
25
|
+
font-weight: normal;
|
26
|
+
}
|
27
|
+
|
28
|
+
.left {
|
29
|
+
display: grid;
|
30
|
+
grid-template-columns: max-content max-content 1fr;
|
31
|
+
align-items: center;
|
32
|
+
column-gap: 0.75em;
|
33
|
+
overflow: hidden;
|
34
|
+
min-width: 0;
|
35
|
+
max-width: 100%;
|
36
|
+
}
|
37
|
+
|
38
|
+
.right {
|
39
|
+
display: grid;
|
40
|
+
grid-auto-columns: max-content;
|
41
|
+
grid-auto-flow: column;
|
42
|
+
justify-content: end;
|
43
|
+
align-items: center;
|
44
|
+
column-gap: 0.5em;
|
45
|
+
}
|
46
|
+
|
47
|
+
.toolbarButton {
|
48
|
+
color: var(--bs-body);
|
49
|
+
}
|
50
|
+
|
51
|
+
.toolbarButton:hover {
|
52
|
+
color: var(--bs-link-hover-color);
|
53
|
+
}
|
54
|
+
|
55
|
+
.pathContainer {
|
56
|
+
overflow-x: hidden;
|
57
|
+
}
|
@@ -0,0 +1,117 @@
|
|
1
|
+
import clsx from "clsx";
|
2
|
+
import { FC, Fragment, ReactNode, useMemo, useRef } from "react";
|
3
|
+
import { Link } from "react-router-dom";
|
4
|
+
import { useStore } from "../../state/store";
|
5
|
+
import { basename, dirname, ensureTrailingSlash } from "../../utils/path";
|
6
|
+
import { ApplicationIcons } from "../appearance/icons";
|
7
|
+
import { logUrl, useLogRouteParams } from "../routing/url";
|
8
|
+
import styles from "./Navbar.module.css";
|
9
|
+
import { useBreadcrumbTruncation } from "./useBreadcrumbTruncation";
|
10
|
+
|
11
|
+
interface NavbarProps {
|
12
|
+
children?: ReactNode;
|
13
|
+
}
|
14
|
+
|
15
|
+
export const Navbar: FC<NavbarProps> = ({ children }) => {
|
16
|
+
const { logPath } = useLogRouteParams();
|
17
|
+
const logs = useStore((state) => state.logs.logs);
|
18
|
+
const baseLogDir = dirname(logs.log_dir || "");
|
19
|
+
const baseLogName = basename(logs.log_dir || "");
|
20
|
+
const pathContainerRef = useRef<HTMLDivElement>(null);
|
21
|
+
|
22
|
+
const backUrl = logUrl(
|
23
|
+
ensureTrailingSlash(dirname(logPath || "")),
|
24
|
+
logs.log_dir,
|
25
|
+
);
|
26
|
+
|
27
|
+
const segments = useMemo(() => {
|
28
|
+
const pathSegments = logPath ? logPath.split("/") : [];
|
29
|
+
const dirSegments: Array<{ text: string; url: string }> = [];
|
30
|
+
const currentSegment = [];
|
31
|
+
for (const pathSegment of pathSegments) {
|
32
|
+
currentSegment.push(pathSegment);
|
33
|
+
const segmentUrl = logUrl(currentSegment.join("/"), logs.log_dir);
|
34
|
+
dirSegments.push({
|
35
|
+
text: pathSegment,
|
36
|
+
url: segmentUrl,
|
37
|
+
});
|
38
|
+
}
|
39
|
+
|
40
|
+
return [
|
41
|
+
{ text: prettyDirUri(baseLogDir) },
|
42
|
+
{ text: baseLogName, url: logUrl("", logs.log_dir) },
|
43
|
+
...dirSegments,
|
44
|
+
];
|
45
|
+
}, [baseLogDir, baseLogName, logPath, logs.log_dir]);
|
46
|
+
|
47
|
+
const { visibleSegments, showEllipsis } = useBreadcrumbTruncation(
|
48
|
+
segments,
|
49
|
+
pathContainerRef,
|
50
|
+
);
|
51
|
+
|
52
|
+
return (
|
53
|
+
<nav
|
54
|
+
className={clsx("text-size-smaller", styles.header)}
|
55
|
+
aria-label="breadcrumb"
|
56
|
+
>
|
57
|
+
<div className={clsx(styles.left)}>
|
58
|
+
<Link to={backUrl} className={clsx(styles.toolbarButton)}>
|
59
|
+
<i className={clsx(ApplicationIcons.navbar.back)} />
|
60
|
+
</Link>
|
61
|
+
<Link
|
62
|
+
to={logUrl("", logs.log_dir)}
|
63
|
+
className={clsx(styles.toolbarButton)}
|
64
|
+
>
|
65
|
+
<i className={clsx(ApplicationIcons.navbar.home)} />
|
66
|
+
</Link>
|
67
|
+
<div className={clsx(styles.pathContainer)} ref={pathContainerRef}>
|
68
|
+
{logs.log_dir ? (
|
69
|
+
<ol className={clsx("breadcrumb", styles.breadcrumbs)}>
|
70
|
+
{visibleSegments?.map((segment, index) => {
|
71
|
+
const isLast = index === visibleSegments.length - 1;
|
72
|
+
const shouldShowEllipsis =
|
73
|
+
showEllipsis && index === 1 && visibleSegments.length >= 2;
|
74
|
+
|
75
|
+
return (
|
76
|
+
<Fragment key={index}>
|
77
|
+
{shouldShowEllipsis && (
|
78
|
+
<li className={clsx("breadcrumb-item", styles.ellipsis)}>
|
79
|
+
<span>...</span>
|
80
|
+
</li>
|
81
|
+
)}
|
82
|
+
<li
|
83
|
+
className={clsx(
|
84
|
+
styles.pathLink,
|
85
|
+
"breadcrumb-item",
|
86
|
+
isLast ? "active" : undefined,
|
87
|
+
)}
|
88
|
+
>
|
89
|
+
{segment.url ? (
|
90
|
+
<Link to={segment.url}>{segment.text}</Link>
|
91
|
+
) : (
|
92
|
+
<span className={clsx(styles.pathSegment)}>
|
93
|
+
{segment.text}
|
94
|
+
</span>
|
95
|
+
)}
|
96
|
+
</li>
|
97
|
+
</Fragment>
|
98
|
+
);
|
99
|
+
})}
|
100
|
+
</ol>
|
101
|
+
) : (
|
102
|
+
""
|
103
|
+
)}
|
104
|
+
</div>
|
105
|
+
</div>
|
106
|
+
<div className={clsx(styles.right)}>{children}</div>
|
107
|
+
</nav>
|
108
|
+
);
|
109
|
+
};
|
110
|
+
|
111
|
+
const prettyDirUri = (uri: string) => {
|
112
|
+
if (uri.startsWith("file://")) {
|
113
|
+
return uri.replace("file://", "");
|
114
|
+
} else {
|
115
|
+
return uri;
|
116
|
+
}
|
117
|
+
};
|
@@ -0,0 +1,128 @@
|
|
1
|
+
import { useEffect, useState, useCallback, RefObject } from "react";
|
2
|
+
|
3
|
+
interface BreadcrumbSegment {
|
4
|
+
text: string;
|
5
|
+
url?: string;
|
6
|
+
}
|
7
|
+
|
8
|
+
interface TruncatedBreadcrumbs {
|
9
|
+
visibleSegments: BreadcrumbSegment[];
|
10
|
+
hiddenCount: number;
|
11
|
+
showEllipsis: boolean;
|
12
|
+
}
|
13
|
+
|
14
|
+
export const useBreadcrumbTruncation = (
|
15
|
+
segments: BreadcrumbSegment[],
|
16
|
+
containerRef: RefObject<HTMLElement | null>,
|
17
|
+
): TruncatedBreadcrumbs => {
|
18
|
+
const [truncatedData, setTruncatedData] = useState<TruncatedBreadcrumbs>({
|
19
|
+
visibleSegments: segments,
|
20
|
+
hiddenCount: 0,
|
21
|
+
showEllipsis: false,
|
22
|
+
});
|
23
|
+
|
24
|
+
const measureAndTruncate = useCallback(() => {
|
25
|
+
if (!containerRef.current || segments.length <= 3) {
|
26
|
+
setTruncatedData({
|
27
|
+
visibleSegments: segments,
|
28
|
+
hiddenCount: 0,
|
29
|
+
showEllipsis: false,
|
30
|
+
});
|
31
|
+
return;
|
32
|
+
}
|
33
|
+
|
34
|
+
const container = containerRef.current;
|
35
|
+
const containerWidth = container.offsetWidth;
|
36
|
+
|
37
|
+
// Create a test element to measure breadcrumb widths
|
38
|
+
const testElement = document.createElement("ol");
|
39
|
+
testElement.className = "breadcrumb";
|
40
|
+
testElement.style.position = "absolute";
|
41
|
+
testElement.style.visibility = "hidden";
|
42
|
+
testElement.style.whiteSpace = "nowrap";
|
43
|
+
testElement.style.margin = "0";
|
44
|
+
testElement.style.padding = "0";
|
45
|
+
|
46
|
+
container.appendChild(testElement);
|
47
|
+
|
48
|
+
// Test if all segments fit
|
49
|
+
testElement.innerHTML = segments
|
50
|
+
.map((segment) => `<li class="breadcrumb-item">${segment.text}</li>`)
|
51
|
+
.join("");
|
52
|
+
|
53
|
+
if (testElement.scrollWidth <= containerWidth) {
|
54
|
+
container.removeChild(testElement);
|
55
|
+
setTruncatedData({
|
56
|
+
visibleSegments: segments,
|
57
|
+
hiddenCount: 0,
|
58
|
+
showEllipsis: false,
|
59
|
+
});
|
60
|
+
return;
|
61
|
+
}
|
62
|
+
|
63
|
+
// Find the maximum number of segments we can show
|
64
|
+
// Always keep first and last segments
|
65
|
+
const firstSegment = segments[0];
|
66
|
+
const lastSegment = segments[segments.length - 1];
|
67
|
+
|
68
|
+
let maxVisible = 2; // Start with just first and last
|
69
|
+
|
70
|
+
// Try adding segments from the end (most recent path) first
|
71
|
+
for (let endCount = 1; endCount < segments.length - 1; endCount++) {
|
72
|
+
const candidateSegments = [
|
73
|
+
firstSegment,
|
74
|
+
...segments.slice(segments.length - 1 - endCount, -1),
|
75
|
+
lastSegment,
|
76
|
+
];
|
77
|
+
|
78
|
+
// Test with ellipsis
|
79
|
+
const testHTML = [
|
80
|
+
`<li class="breadcrumb-item">${firstSegment.text}</li>`,
|
81
|
+
`<li class="breadcrumb-item">...</li>`,
|
82
|
+
...segments
|
83
|
+
.slice(segments.length - 1 - endCount, -1)
|
84
|
+
.map((s) => `<li class="breadcrumb-item">${s.text}</li>`),
|
85
|
+
`<li class="breadcrumb-item">${lastSegment.text}</li>`,
|
86
|
+
].join("");
|
87
|
+
|
88
|
+
testElement.innerHTML = testHTML;
|
89
|
+
|
90
|
+
if (testElement.scrollWidth <= containerWidth) {
|
91
|
+
maxVisible = candidateSegments.length;
|
92
|
+
setTruncatedData({
|
93
|
+
visibleSegments: candidateSegments,
|
94
|
+
hiddenCount: segments.length - candidateSegments.length,
|
95
|
+
showEllipsis: true,
|
96
|
+
});
|
97
|
+
} else {
|
98
|
+
break;
|
99
|
+
}
|
100
|
+
}
|
101
|
+
|
102
|
+
// If we couldn't fit any middle segments, just show first ... last
|
103
|
+
if (maxVisible === 2) {
|
104
|
+
setTruncatedData({
|
105
|
+
visibleSegments: [firstSegment, lastSegment],
|
106
|
+
hiddenCount: segments.length - 2,
|
107
|
+
showEllipsis: true,
|
108
|
+
});
|
109
|
+
}
|
110
|
+
|
111
|
+
container.removeChild(testElement);
|
112
|
+
}, [segments, containerRef]);
|
113
|
+
|
114
|
+
useEffect(() => {
|
115
|
+
measureAndTruncate();
|
116
|
+
|
117
|
+
const resizeObserver = new ResizeObserver(measureAndTruncate);
|
118
|
+
if (containerRef.current) {
|
119
|
+
resizeObserver.observe(containerRef.current);
|
120
|
+
}
|
121
|
+
|
122
|
+
return () => {
|
123
|
+
resizeObserver.disconnect();
|
124
|
+
};
|
125
|
+
}, [measureAndTruncate]);
|
126
|
+
|
127
|
+
return truncatedData;
|
128
|
+
};
|
@@ -1,8 +1,8 @@
|
|
1
1
|
import clsx from "clsx";
|
2
2
|
import { EvalDataset } from "../../@types/log";
|
3
|
-
import { MetaDataView } from "../content/MetaDataView";
|
4
3
|
|
5
4
|
import { CSSProperties, FC } from "react";
|
5
|
+
import { MetaDataGrid } from "../content/MetaDataGrid";
|
6
6
|
import styles from "./DatasetDetailView.module.css";
|
7
7
|
|
8
8
|
interface DatasetDetailViewProps {
|
@@ -28,11 +28,11 @@ export const DatasetDetailView: FC<DatasetDetailViewProps> = ({
|
|
28
28
|
}
|
29
29
|
|
30
30
|
return (
|
31
|
-
<
|
31
|
+
<MetaDataGrid
|
32
32
|
className={clsx("text-size-base", styles.item)}
|
33
33
|
entries={filtered}
|
34
|
-
tableOptions="borderless,sm"
|
35
34
|
style={style}
|
35
|
+
plain={true}
|
36
36
|
/>
|
37
37
|
);
|
38
38
|
};
|
@@ -20,16 +20,16 @@ export const DetailStep: FC<DetailStepProps> = ({
|
|
20
20
|
return (
|
21
21
|
<div className={clsx(className)}>
|
22
22
|
{iconHtml} {name}
|
23
|
-
|
24
|
-
{
|
23
|
+
{params && Object.keys(params).length > 0 ? (
|
24
|
+
<div className={styles.container}>
|
25
25
|
<MetaDataGrid
|
26
26
|
entries={params}
|
27
27
|
className={clsx("text-size-small", styles.metadata)}
|
28
28
|
/>
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
29
|
+
</div>
|
30
|
+
) : (
|
31
|
+
""
|
32
|
+
)}
|
33
33
|
</div>
|
34
34
|
);
|
35
35
|
};
|
@@ -1,8 +1,8 @@
|
|
1
1
|
import clsx from "clsx";
|
2
2
|
import { FC } from "react";
|
3
3
|
import { ApplicationIcons } from "../appearance/icons";
|
4
|
-
import styles from "./DatasetDetailView.module.css";
|
5
4
|
import { DetailStep } from "./DetailStep";
|
5
|
+
import styles from "./ScorerDetailView.module.css";
|
6
6
|
|
7
7
|
interface ScorerDetailViewProps {
|
8
8
|
name: string;
|
@@ -5,10 +5,16 @@ import {
|
|
5
5
|
Outlet,
|
6
6
|
useLocation,
|
7
7
|
} from "react-router-dom";
|
8
|
-
import { storeImplementation } from "../../state/store";
|
8
|
+
import { storeImplementation, useStore } from "../../state/store";
|
9
9
|
import { AppErrorBoundary } from "../AppErrorBoundary";
|
10
|
+
import { LogsPanel } from "../log-list/LogsPanel";
|
10
11
|
import { LogViewContainer } from "../log-view/LogViewContainer";
|
11
|
-
import {
|
12
|
+
import { RouteDispatcher } from "./RouteDispatcher";
|
13
|
+
import {
|
14
|
+
kLogRouteUrlPattern,
|
15
|
+
kLogsRoutUrlPattern as kLogsRouteUrlPattern,
|
16
|
+
kSampleRouteUrlPattern,
|
17
|
+
} from "./url";
|
12
18
|
|
13
19
|
// Create a layout component that includes the RouteTracker
|
14
20
|
const AppLayout = () => {
|
@@ -21,6 +27,20 @@ const AppLayout = () => {
|
|
21
27
|
}
|
22
28
|
}, [location]);
|
23
29
|
|
30
|
+
// Get log selection state from store
|
31
|
+
const singleFileMode = useStore((state) => state.app.singleFileMode);
|
32
|
+
|
33
|
+
// Single file mode is a legacy mode that is used when an explicit
|
34
|
+
// file is passed via URL (task_file or log_file params) or via
|
35
|
+
// embedded state (VSCode)
|
36
|
+
if (singleFileMode) {
|
37
|
+
return (
|
38
|
+
<AppErrorBoundary>
|
39
|
+
<LogViewContainer />
|
40
|
+
</AppErrorBoundary>
|
41
|
+
);
|
42
|
+
}
|
43
|
+
|
24
44
|
return (
|
25
45
|
<AppErrorBoundary>
|
26
46
|
<Outlet />
|
@@ -37,11 +57,15 @@ export const AppRouter = createHashRouter(
|
|
37
57
|
children: [
|
38
58
|
{
|
39
59
|
index: true, // This will match exactly the "/" path
|
40
|
-
element: <
|
60
|
+
element: <LogsPanel />,
|
61
|
+
},
|
62
|
+
{
|
63
|
+
path: kLogsRouteUrlPattern,
|
64
|
+
element: <LogsPanel />,
|
41
65
|
},
|
42
66
|
{
|
43
67
|
path: kLogRouteUrlPattern,
|
44
|
-
element: <
|
68
|
+
element: <RouteDispatcher />,
|
45
69
|
},
|
46
70
|
{
|
47
71
|
path: kSampleRouteUrlPattern,
|