inspect-ai 0.3.80__py3-none-any.whl → 0.3.82__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/_cli/eval.py +35 -2
- inspect_ai/_cli/util.py +44 -1
- inspect_ai/_display/core/config.py +1 -1
- inspect_ai/_display/core/display.py +13 -4
- inspect_ai/_display/core/results.py +1 -1
- inspect_ai/_display/textual/widgets/task_detail.py +5 -4
- inspect_ai/_eval/eval.py +38 -1
- inspect_ai/_eval/evalset.py +5 -0
- inspect_ai/_eval/run.py +5 -2
- inspect_ai/_eval/task/log.py +53 -6
- inspect_ai/_eval/task/run.py +51 -10
- inspect_ai/_util/constants.py +2 -0
- inspect_ai/_util/file.py +17 -1
- inspect_ai/_util/json.py +36 -1
- inspect_ai/_view/server.py +113 -1
- inspect_ai/_view/www/App.css +1 -1
- inspect_ai/_view/www/dist/assets/index.css +518 -296
- inspect_ai/_view/www/dist/assets/index.js +38803 -36307
- inspect_ai/_view/www/eslint.config.mjs +1 -1
- inspect_ai/_view/www/log-schema.json +13 -0
- inspect_ai/_view/www/node_modules/flatted/python/flatted.py +149 -0
- inspect_ai/_view/www/package.json +8 -2
- inspect_ai/_view/www/src/App.tsx +151 -855
- inspect_ai/_view/www/src/api/api-browser.ts +176 -5
- inspect_ai/_view/www/src/api/api-vscode.ts +75 -1
- inspect_ai/_view/www/src/api/client-api.ts +66 -10
- inspect_ai/_view/www/src/api/jsonrpc.ts +2 -0
- inspect_ai/_view/www/src/api/types.ts +107 -2
- inspect_ai/_view/www/src/appearance/icons.ts +1 -0
- inspect_ai/_view/www/src/components/AsciinemaPlayer.tsx +3 -3
- inspect_ai/_view/www/src/components/DownloadPanel.tsx +2 -2
- inspect_ai/_view/www/src/components/ExpandablePanel.tsx +56 -61
- inspect_ai/_view/www/src/components/FindBand.tsx +17 -9
- inspect_ai/_view/www/src/components/HumanBaselineView.tsx +1 -1
- inspect_ai/_view/www/src/components/JsonPanel.tsx +14 -24
- inspect_ai/_view/www/src/components/LargeModal.tsx +2 -35
- inspect_ai/_view/www/src/components/LightboxCarousel.tsx +27 -11
- inspect_ai/_view/www/src/components/LiveVirtualList.module.css +11 -0
- inspect_ai/_view/www/src/components/LiveVirtualList.tsx +177 -0
- inspect_ai/_view/www/src/components/MarkdownDiv.tsx +3 -3
- inspect_ai/_view/www/src/components/MessageBand.tsx +14 -9
- inspect_ai/_view/www/src/components/MorePopOver.tsx +3 -3
- inspect_ai/_view/www/src/components/NavPills.tsx +20 -8
- inspect_ai/_view/www/src/components/NoContentsPanel.module.css +12 -0
- inspect_ai/_view/www/src/components/NoContentsPanel.tsx +20 -0
- inspect_ai/_view/www/src/components/ProgressBar.module.css +5 -4
- inspect_ai/_view/www/src/components/ProgressBar.tsx +3 -2
- inspect_ai/_view/www/src/components/PulsingDots.module.css +81 -0
- inspect_ai/_view/www/src/components/PulsingDots.tsx +45 -0
- inspect_ai/_view/www/src/components/TabSet.tsx +4 -37
- inspect_ai/_view/www/src/components/ToolButton.tsx +3 -4
- inspect_ai/_view/www/src/index.tsx +26 -94
- inspect_ai/_view/www/src/logfile/remoteLogFile.ts +9 -1
- inspect_ai/_view/www/src/logfile/remoteZipFile.ts +30 -4
- inspect_ai/_view/www/src/metadata/RenderedContent.tsx +4 -6
- inspect_ai/_view/www/src/plan/ScorerDetailView.tsx +1 -1
- inspect_ai/_view/www/src/samples/InlineSampleDisplay.module.css +9 -1
- inspect_ai/_view/www/src/samples/InlineSampleDisplay.tsx +67 -28
- inspect_ai/_view/www/src/samples/SampleDialog.tsx +51 -22
- inspect_ai/_view/www/src/samples/SampleDisplay.module.css +4 -0
- inspect_ai/_view/www/src/samples/SampleDisplay.tsx +144 -90
- inspect_ai/_view/www/src/samples/SampleSummaryView.module.css +4 -0
- inspect_ai/_view/www/src/samples/SampleSummaryView.tsx +82 -35
- inspect_ai/_view/www/src/samples/SamplesTools.tsx +23 -30
- inspect_ai/_view/www/src/samples/chat/ChatMessage.tsx +2 -1
- inspect_ai/_view/www/src/samples/chat/ChatMessageRenderer.tsx +1 -1
- inspect_ai/_view/www/src/samples/chat/ChatViewVirtualList.tsx +45 -53
- inspect_ai/_view/www/src/samples/chat/MessageContent.tsx +4 -1
- inspect_ai/_view/www/src/samples/chat/MessageContents.tsx +3 -0
- inspect_ai/_view/www/src/samples/chat/messages.ts +34 -0
- inspect_ai/_view/www/src/samples/chat/tools/ToolCallView.module.css +3 -0
- inspect_ai/_view/www/src/samples/chat/tools/ToolCallView.tsx +10 -1
- inspect_ai/_view/www/src/samples/chat/tools/ToolInput.tsx +22 -46
- inspect_ai/_view/www/src/samples/descriptor/samplesDescriptor.tsx +25 -17
- inspect_ai/_view/www/src/samples/descriptor/score/ObjectScoreDescriptor.tsx +2 -1
- inspect_ai/_view/www/src/samples/descriptor/types.ts +6 -5
- inspect_ai/_view/www/src/samples/list/SampleFooter.module.css +21 -3
- inspect_ai/_view/www/src/samples/list/SampleFooter.tsx +20 -1
- inspect_ai/_view/www/src/samples/list/SampleList.tsx +105 -85
- inspect_ai/_view/www/src/samples/list/SampleRow.module.css +6 -0
- inspect_ai/_view/www/src/samples/list/SampleRow.tsx +27 -14
- inspect_ai/_view/www/src/samples/sample-tools/SelectScorer.tsx +29 -18
- inspect_ai/_view/www/src/samples/sample-tools/SortFilter.tsx +28 -28
- inspect_ai/_view/www/src/samples/sample-tools/sample-filter/SampleFilter.tsx +19 -9
- inspect_ai/_view/www/src/samples/sampleDataAdapter.ts +33 -0
- inspect_ai/_view/www/src/samples/sampleLimit.ts +2 -2
- inspect_ai/_view/www/src/samples/scores/SampleScoreView.tsx +7 -9
- inspect_ai/_view/www/src/samples/scores/SampleScores.tsx +7 -11
- inspect_ai/_view/www/src/samples/transcript/ErrorEventView.tsx +0 -13
- inspect_ai/_view/www/src/samples/transcript/InfoEventView.tsx +0 -13
- inspect_ai/_view/www/src/samples/transcript/InputEventView.tsx +0 -13
- inspect_ai/_view/www/src/samples/transcript/ModelEventView.module.css +4 -0
- inspect_ai/_view/www/src/samples/transcript/ModelEventView.tsx +10 -24
- inspect_ai/_view/www/src/samples/transcript/SampleInitEventView.tsx +0 -13
- inspect_ai/_view/www/src/samples/transcript/SampleLimitEventView.tsx +4 -22
- inspect_ai/_view/www/src/samples/transcript/SandboxEventView.tsx +15 -24
- inspect_ai/_view/www/src/samples/transcript/ScoreEventView.tsx +0 -13
- inspect_ai/_view/www/src/samples/transcript/StepEventView.tsx +6 -28
- inspect_ai/_view/www/src/samples/transcript/SubtaskEventView.tsx +24 -34
- inspect_ai/_view/www/src/samples/transcript/ToolEventView.module.css +4 -0
- inspect_ai/_view/www/src/samples/transcript/ToolEventView.tsx +8 -13
- inspect_ai/_view/www/src/samples/transcript/TranscriptView.tsx +197 -338
- inspect_ai/_view/www/src/samples/transcript/TranscriptVirtualListComponent.module.css +16 -0
- inspect_ai/_view/www/src/samples/transcript/TranscriptVirtualListComponent.tsx +44 -0
- inspect_ai/_view/www/src/samples/transcript/event/EventNav.tsx +7 -4
- inspect_ai/_view/www/src/samples/transcript/event/EventPanel.tsx +52 -58
- inspect_ai/_view/www/src/samples/transcript/event/EventProgressPanel.module.css +23 -0
- inspect_ai/_view/www/src/samples/transcript/event/EventProgressPanel.tsx +27 -0
- inspect_ai/_view/www/src/samples/transcript/state/StateEventRenderers.tsx +30 -1
- inspect_ai/_view/www/src/samples/transcript/state/StateEventView.tsx +102 -72
- inspect_ai/_view/www/src/scoring/utils.ts +87 -0
- inspect_ai/_view/www/src/state/appSlice.ts +244 -0
- inspect_ai/_view/www/src/state/hooks.ts +397 -0
- inspect_ai/_view/www/src/state/logPolling.ts +196 -0
- inspect_ai/_view/www/src/state/logSlice.ts +214 -0
- inspect_ai/_view/www/src/state/logsPolling.ts +118 -0
- inspect_ai/_view/www/src/state/logsSlice.ts +181 -0
- inspect_ai/_view/www/src/state/samplePolling.ts +311 -0
- inspect_ai/_view/www/src/state/sampleSlice.ts +127 -0
- inspect_ai/_view/www/src/state/sampleUtils.ts +21 -0
- inspect_ai/_view/www/src/state/scrolling.ts +206 -0
- inspect_ai/_view/www/src/state/store.ts +168 -0
- inspect_ai/_view/www/src/state/store_filter.ts +84 -0
- inspect_ai/_view/www/src/state/utils.ts +23 -0
- inspect_ai/_view/www/src/storage/index.ts +26 -0
- inspect_ai/_view/www/src/types/log.d.ts +2 -0
- inspect_ai/_view/www/src/types.ts +94 -32
- inspect_ai/_view/www/src/utils/attachments.ts +58 -23
- inspect_ai/_view/www/src/utils/logger.ts +52 -0
- inspect_ai/_view/www/src/utils/polling.ts +100 -0
- inspect_ai/_view/www/src/utils/react.ts +30 -0
- inspect_ai/_view/www/src/utils/vscode.ts +1 -1
- inspect_ai/_view/www/src/workspace/WorkSpace.tsx +181 -216
- inspect_ai/_view/www/src/workspace/WorkSpaceView.tsx +11 -53
- inspect_ai/_view/www/src/workspace/navbar/Navbar.tsx +8 -18
- inspect_ai/_view/www/src/workspace/navbar/PrimaryBar.module.css +1 -0
- inspect_ai/_view/www/src/workspace/navbar/PrimaryBar.tsx +40 -22
- inspect_ai/_view/www/src/workspace/navbar/ResultsPanel.module.css +0 -1
- inspect_ai/_view/www/src/workspace/navbar/ResultsPanel.tsx +98 -39
- inspect_ai/_view/www/src/workspace/navbar/RunningStatusPanel.module.css +32 -0
- inspect_ai/_view/www/src/workspace/navbar/RunningStatusPanel.tsx +32 -0
- inspect_ai/_view/www/src/workspace/navbar/SecondaryBar.tsx +11 -13
- inspect_ai/_view/www/src/workspace/navbar/StatusPanel.tsx +6 -2
- inspect_ai/_view/www/src/workspace/sidebar/LogDirectoryTitleView.tsx +4 -4
- inspect_ai/_view/www/src/workspace/sidebar/Sidebar.tsx +28 -13
- inspect_ai/_view/www/src/workspace/tabs/InfoTab.tsx +5 -10
- inspect_ai/_view/www/src/workspace/tabs/JsonTab.tsx +4 -4
- inspect_ai/_view/www/src/workspace/tabs/RunningNoSamples.module.css +22 -0
- inspect_ai/_view/www/src/workspace/tabs/RunningNoSamples.tsx +19 -0
- inspect_ai/_view/www/src/workspace/tabs/SamplesTab.tsx +110 -115
- inspect_ai/_view/www/src/workspace/tabs/grouping.ts +37 -5
- inspect_ai/_view/www/src/workspace/tabs/types.ts +4 -0
- inspect_ai/_view/www/src/workspace/types.ts +4 -3
- inspect_ai/_view/www/src/workspace/utils.ts +4 -4
- inspect_ai/_view/www/vite.config.js +6 -0
- inspect_ai/_view/www/yarn.lock +370 -354
- inspect_ai/log/_condense.py +26 -0
- inspect_ai/log/_log.py +6 -3
- inspect_ai/log/_recorders/buffer/__init__.py +14 -0
- inspect_ai/log/_recorders/buffer/buffer.py +30 -0
- inspect_ai/log/_recorders/buffer/database.py +685 -0
- inspect_ai/log/_recorders/buffer/filestore.py +259 -0
- inspect_ai/log/_recorders/buffer/types.py +84 -0
- inspect_ai/log/_recorders/eval.py +2 -11
- inspect_ai/log/_recorders/types.py +30 -0
- inspect_ai/log/_transcript.py +27 -1
- inspect_ai/model/_call_tools.py +1 -0
- inspect_ai/model/_generate_config.py +2 -2
- inspect_ai/model/_model.py +1 -0
- inspect_ai/tool/_tool_support_helpers.py +4 -4
- inspect_ai/tool/_tools/_web_browser/_web_browser.py +3 -1
- inspect_ai/util/_subtask.py +1 -0
- {inspect_ai-0.3.80.dist-info → inspect_ai-0.3.82.dist-info}/METADATA +2 -2
- {inspect_ai-0.3.80.dist-info → inspect_ai-0.3.82.dist-info}/RECORD +178 -138
- inspect_ai/_view/www/src/samples/transcript/SampleTranscript.tsx +0 -22
- {inspect_ai-0.3.80.dist-info → inspect_ai-0.3.82.dist-info}/WHEEL +0 -0
- {inspect_ai-0.3.80.dist-info → inspect_ai-0.3.82.dist-info}/entry_points.txt +0 -0
- {inspect_ai-0.3.80.dist-info → inspect_ai-0.3.82.dist-info}/licenses/LICENSE +0 -0
- {inspect_ai-0.3.80.dist-info → inspect_ai-0.3.82.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
import clsx from "clsx";
|
2
2
|
|
3
|
-
import { FC } from "react";
|
3
|
+
import { FC, useCallback } from "react";
|
4
4
|
import styles from "./EventNav.module.css";
|
5
5
|
|
6
6
|
interface EventNavProps {
|
@@ -19,6 +19,11 @@ export const EventNav: FC<EventNavProps> = ({
|
|
19
19
|
setSelectedNav,
|
20
20
|
}) => {
|
21
21
|
const active = target === selectedNav;
|
22
|
+
|
23
|
+
const handleClick = useCallback(() => {
|
24
|
+
setSelectedNav(target);
|
25
|
+
}, [setSelectedNav, target]);
|
26
|
+
|
22
27
|
return (
|
23
28
|
<li className="nav-item">
|
24
29
|
<button
|
@@ -33,9 +38,7 @@ export const EventNav: FC<EventNavProps> = ({
|
|
33
38
|
"text-size-small",
|
34
39
|
styles.tab,
|
35
40
|
)}
|
36
|
-
onClick={
|
37
|
-
setSelectedNav(target);
|
38
|
-
}}
|
41
|
+
onClick={handleClick}
|
39
42
|
>
|
40
43
|
{title}
|
41
44
|
</button>
|
@@ -1,9 +1,10 @@
|
|
1
1
|
import clsx from "clsx";
|
2
|
-
import { ReactNode } from "react";
|
2
|
+
import { FC, isValidElement, ReactNode, useCallback } from "react";
|
3
3
|
import { ApplicationIcons } from "../../../appearance/icons";
|
4
4
|
import { EventNavs } from "./EventNavs";
|
5
5
|
|
6
|
-
import
|
6
|
+
import { ProgressBar } from "../../../components/ProgressBar";
|
7
|
+
import { useProperty } from "../../../state/hooks";
|
7
8
|
import styles from "./EventPanel.module.css";
|
8
9
|
|
9
10
|
interface EventPanelProps {
|
@@ -14,11 +15,8 @@ interface EventPanelProps {
|
|
14
15
|
text?: string;
|
15
16
|
icon?: string;
|
16
17
|
collapse?: boolean;
|
17
|
-
collapsed?: boolean;
|
18
|
-
setCollapsed: (collapse: boolean) => void;
|
19
|
-
selectedNav: string;
|
20
|
-
setSelectedNav: (nav: string) => void;
|
21
18
|
children?: ReactNode | ReactNode[];
|
19
|
+
running?: boolean;
|
22
20
|
}
|
23
21
|
|
24
22
|
interface ChildProps {
|
@@ -28,7 +26,7 @@ interface ChildProps {
|
|
28
26
|
/**
|
29
27
|
* Renders the StateEventView component.
|
30
28
|
*/
|
31
|
-
export const EventPanel:
|
29
|
+
export const EventPanel: FC<EventPanelProps> = ({
|
32
30
|
id,
|
33
31
|
className,
|
34
32
|
title,
|
@@ -36,24 +34,27 @@ export const EventPanel: React.FC<EventPanelProps> = ({
|
|
36
34
|
text,
|
37
35
|
icon,
|
38
36
|
collapse,
|
39
|
-
collapsed,
|
40
|
-
setCollapsed,
|
41
37
|
children,
|
42
|
-
|
43
|
-
selectedNav,
|
38
|
+
running,
|
44
39
|
}) => {
|
40
|
+
const [isCollapsed, setCollapsed] = useProperty(id, "collapsed", {
|
41
|
+
defaultValue: !!collapse,
|
42
|
+
});
|
43
|
+
|
45
44
|
const hasCollapse = collapse !== undefined;
|
46
|
-
const isCollapsed = collapsed === undefined ? collapse : collapsed;
|
47
45
|
|
48
46
|
const pillId = (index: number) => {
|
49
47
|
return `${id}-nav-pill-${index}`;
|
50
48
|
};
|
51
|
-
|
52
49
|
const filteredArrChildren = (
|
53
50
|
Array.isArray(children) ? children : [children]
|
54
51
|
).filter((child) => !!child);
|
55
52
|
const defaultPillId = pillId(0);
|
56
53
|
|
54
|
+
const [selectedNav, setSelectedNav] = useProperty(id, "selectedNav", {
|
55
|
+
defaultValue: defaultPillId,
|
56
|
+
});
|
57
|
+
|
57
58
|
const gridColumns = [];
|
58
59
|
|
59
60
|
// chevron
|
@@ -72,6 +73,10 @@ export const EventPanel: React.FC<EventPanelProps> = ({
|
|
72
73
|
gridColumns.push("minmax(0, max-content)");
|
73
74
|
gridColumns.push("minmax(0, max-content)");
|
74
75
|
|
76
|
+
const toggleCollapse = useCallback(() => {
|
77
|
+
setCollapsed(!isCollapsed);
|
78
|
+
}, [setCollapsed, isCollapsed]);
|
79
|
+
|
75
80
|
const titleEl =
|
76
81
|
title || icon || filteredArrChildren.length > 1 ? (
|
77
82
|
<div
|
@@ -86,9 +91,7 @@ export const EventPanel: React.FC<EventPanelProps> = ({
|
|
86
91
|
>
|
87
92
|
{hasCollapse ? (
|
88
93
|
<i
|
89
|
-
onClick={
|
90
|
-
setCollapsed(!isCollapsed);
|
91
|
-
}}
|
94
|
+
onClick={toggleCollapse}
|
92
95
|
className={
|
93
96
|
isCollapsed
|
94
97
|
? ApplicationIcons.chevron.right
|
@@ -104,33 +107,23 @@ export const EventPanel: React.FC<EventPanelProps> = ({
|
|
104
107
|
icon || ApplicationIcons.metadata,
|
105
108
|
"text-style-secondary",
|
106
109
|
)}
|
107
|
-
onClick={
|
108
|
-
setCollapsed(!isCollapsed);
|
109
|
-
}}
|
110
|
+
onClick={toggleCollapse}
|
110
111
|
/>
|
111
112
|
) : (
|
112
113
|
""
|
113
114
|
)}
|
114
115
|
<div
|
115
116
|
className={clsx("text-style-secondary", "text-style-label")}
|
116
|
-
onClick={
|
117
|
-
setCollapsed(!isCollapsed);
|
118
|
-
}}
|
117
|
+
onClick={toggleCollapse}
|
119
118
|
>
|
120
119
|
{title}
|
121
120
|
</div>
|
122
|
-
<div
|
123
|
-
onClick={() => {
|
124
|
-
setCollapsed(!isCollapsed);
|
125
|
-
}}
|
126
|
-
></div>
|
121
|
+
<div onClick={toggleCollapse}></div>
|
127
122
|
<div
|
128
123
|
className={clsx("text-style-secondary", styles.label)}
|
129
|
-
onClick={
|
130
|
-
setCollapsed(!isCollapsed);
|
131
|
-
}}
|
124
|
+
onClick={toggleCollapse}
|
132
125
|
>
|
133
|
-
{
|
126
|
+
{isCollapsed ? text : ""}
|
134
127
|
</div>
|
135
128
|
<div className={styles.navs}>
|
136
129
|
{(!hasCollapse || !isCollapsed) &&
|
@@ -140,7 +133,7 @@ export const EventPanel: React.FC<EventPanelProps> = ({
|
|
140
133
|
navs={filteredArrChildren.map((child, index) => {
|
141
134
|
const defaultTitle = `Tab ${index}`;
|
142
135
|
const title =
|
143
|
-
child &&
|
136
|
+
child && isValidElement<ChildProps>(child)
|
144
137
|
? (child.props as ChildProps)["data-name"] || defaultTitle
|
145
138
|
: defaultTitle;
|
146
139
|
return {
|
@@ -149,7 +142,7 @@ export const EventPanel: React.FC<EventPanelProps> = ({
|
|
149
142
|
target: pillId(index),
|
150
143
|
};
|
151
144
|
})}
|
152
|
-
selectedNav={selectedNav
|
145
|
+
selectedNav={selectedNav}
|
153
146
|
setSelectedNav={setSelectedNav}
|
154
147
|
/>
|
155
148
|
) : (
|
@@ -162,33 +155,34 @@ export const EventPanel: React.FC<EventPanelProps> = ({
|
|
162
155
|
);
|
163
156
|
|
164
157
|
const card = (
|
165
|
-
|
166
|
-
{
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
: id === defaultPillId;
|
158
|
+
<>
|
159
|
+
<div id={id} className={clsx(className, styles.card)}>
|
160
|
+
{titleEl}
|
161
|
+
<div
|
162
|
+
className={clsx(
|
163
|
+
"tab-content",
|
164
|
+
styles.cardContent,
|
165
|
+
hasCollapse && isCollapsed ? styles.hidden : undefined,
|
166
|
+
)}
|
167
|
+
>
|
168
|
+
{filteredArrChildren?.map((child, index) => {
|
169
|
+
const id = pillId(index);
|
170
|
+
const isSelected = id === selectedNav;
|
179
171
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
172
|
+
return (
|
173
|
+
<div
|
174
|
+
key={`children-${id}-${index}`}
|
175
|
+
id={id}
|
176
|
+
className={clsx("tab-pane", "show", isSelected ? "active" : "")}
|
177
|
+
>
|
178
|
+
{child}
|
179
|
+
</div>
|
180
|
+
);
|
181
|
+
})}
|
182
|
+
</div>
|
190
183
|
</div>
|
191
|
-
|
184
|
+
<ProgressBar animating={!!running} />
|
185
|
+
</>
|
192
186
|
);
|
193
187
|
return card;
|
194
188
|
};
|
@@ -0,0 +1,23 @@
|
|
1
|
+
.panel {
|
2
|
+
display: flex;
|
3
|
+
justify-content: center;
|
4
|
+
padding-top: 1em;
|
5
|
+
padding-bottom: 1em;
|
6
|
+
}
|
7
|
+
|
8
|
+
.container {
|
9
|
+
display: grid;
|
10
|
+
grid-template-columns: max-content max-content;
|
11
|
+
column-gap: 0.3em;
|
12
|
+
}
|
13
|
+
|
14
|
+
.spinner {
|
15
|
+
height: 15px;
|
16
|
+
width: 14px;
|
17
|
+
border-width: 2px;
|
18
|
+
color: var(--bs-secondary);
|
19
|
+
}
|
20
|
+
|
21
|
+
.text {
|
22
|
+
margin-top: -2px;
|
23
|
+
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import clsx from "clsx";
|
2
|
+
import { FC } from "react";
|
3
|
+
|
4
|
+
import styles from "./EventProgressPanel.module.css";
|
5
|
+
|
6
|
+
interface EventProgressPanelProps {
|
7
|
+
text: string;
|
8
|
+
}
|
9
|
+
|
10
|
+
export const EventProgressPanel: FC<EventProgressPanelProps> = ({ text }) => {
|
11
|
+
return (
|
12
|
+
<div className={clsx(styles.panel)}>
|
13
|
+
<div className={clsx(styles.container)}>
|
14
|
+
<Spinner />
|
15
|
+
<div className={clsx("text-size-smaller", styles.text)}>{text}</div>
|
16
|
+
</div>
|
17
|
+
</div>
|
18
|
+
);
|
19
|
+
};
|
20
|
+
|
21
|
+
const Spinner: FC = () => {
|
22
|
+
return (
|
23
|
+
<div className={clsx(styles.spinner, "spinner-border")} role="status">
|
24
|
+
<span className={clsx("visually-hidden")}>generating...</span>
|
25
|
+
</div>
|
26
|
+
);
|
27
|
+
};
|
@@ -17,7 +17,8 @@ interface Signature {
|
|
17
17
|
|
18
18
|
interface ChangeType {
|
19
19
|
type: string;
|
20
|
-
signature
|
20
|
+
signature?: Signature;
|
21
|
+
match?: (changes: JsonChange[]) => boolean;
|
21
22
|
render: (
|
22
23
|
changes: JsonChange[],
|
23
24
|
state: Record<string, unknown>,
|
@@ -211,8 +212,36 @@ const renderTools = (
|
|
211
212
|
);
|
212
213
|
};
|
213
214
|
|
215
|
+
const createMessageRenderer = (name: string, role: string): ChangeType => {
|
216
|
+
return {
|
217
|
+
type: name,
|
218
|
+
match: (changes: JsonChange[]) => {
|
219
|
+
console.log(changes);
|
220
|
+
if (changes.length === 1) {
|
221
|
+
const change = changes[0];
|
222
|
+
if (change.op === "add" && change.path.match(/\/messages\/\d+/)) {
|
223
|
+
return change.value["role"] === role;
|
224
|
+
}
|
225
|
+
}
|
226
|
+
return false;
|
227
|
+
},
|
228
|
+
render: (changes) => {
|
229
|
+
const message = changes[0].value as unknown;
|
230
|
+
return (
|
231
|
+
<ChatView
|
232
|
+
key="system_msg_event_preview"
|
233
|
+
id="system_msg_event_preview"
|
234
|
+
messages={[message] as Messages}
|
235
|
+
/>
|
236
|
+
);
|
237
|
+
},
|
238
|
+
};
|
239
|
+
};
|
240
|
+
|
214
241
|
export const RenderableChangeTypes: ChangeType[] = [
|
215
242
|
system_msg_added_sig,
|
243
|
+
createMessageRenderer("assistant_msg", "assistant"),
|
244
|
+
createMessageRenderer("user_msg", "user"),
|
216
245
|
use_tools,
|
217
246
|
add_tools,
|
218
247
|
];
|
@@ -10,7 +10,6 @@ import {
|
|
10
10
|
} from "../../../types/log";
|
11
11
|
import { formatDateTime } from "../../../utils/format";
|
12
12
|
import { EventPanel } from "../event/EventPanel";
|
13
|
-
import { TranscriptEventState } from "../types";
|
14
13
|
import { StateDiffView } from "./StateDiffView";
|
15
14
|
import {
|
16
15
|
RenderableChangeTypes,
|
@@ -23,8 +22,6 @@ import styles from "./StateEventView.module.css";
|
|
23
22
|
interface StateEventViewProps {
|
24
23
|
id: string;
|
25
24
|
event: StateEvent | StoreEvent;
|
26
|
-
eventState: TranscriptEventState;
|
27
|
-
setEventState: (state: TranscriptEventState) => void;
|
28
25
|
isStore?: boolean;
|
29
26
|
className?: string | string[];
|
30
27
|
}
|
@@ -35,8 +32,6 @@ interface StateEventViewProps {
|
|
35
32
|
export const StateEventView: FC<StateEventViewProps> = ({
|
36
33
|
id,
|
37
34
|
event,
|
38
|
-
eventState,
|
39
|
-
setEventState,
|
40
35
|
isStore = false,
|
41
36
|
className,
|
42
37
|
}) => {
|
@@ -46,7 +41,15 @@ export const StateEventView: FC<StateEventViewProps> = ({
|
|
46
41
|
|
47
42
|
// Synthesize objects for comparison
|
48
43
|
const [before, after] = useMemo(() => {
|
49
|
-
|
44
|
+
try {
|
45
|
+
return synthesizeComparable(event.changes);
|
46
|
+
} catch (e) {
|
47
|
+
console.error(
|
48
|
+
"Unable to synthesize comparable object to display state diffs.",
|
49
|
+
e,
|
50
|
+
);
|
51
|
+
return [{}, {}];
|
52
|
+
}
|
50
53
|
}, [event.changes]);
|
51
54
|
|
52
55
|
// This clone is important since the state is used by react as potential values that are rendered
|
@@ -66,14 +69,6 @@ export const StateEventView: FC<StateEventViewProps> = ({
|
|
66
69
|
subTitle={formatDateTime(new Date(event.timestamp))}
|
67
70
|
text={!changePreview ? summary : undefined}
|
68
71
|
collapse={changePreview === undefined ? true : undefined}
|
69
|
-
selectedNav={eventState.selectedNav || ""}
|
70
|
-
setSelectedNav={(selectedNav) => {
|
71
|
-
setEventState({ ...eventState, selectedNav });
|
72
|
-
}}
|
73
|
-
collapsed={eventState.collapsed}
|
74
|
-
setCollapsed={(collapsed) => {
|
75
|
-
setEventState({ ...eventState, collapsed });
|
76
|
-
}}
|
77
72
|
>
|
78
73
|
{changePreview ? (
|
79
74
|
<div data-name="Summary" className={clsx(styles.summary)}>
|
@@ -103,59 +98,71 @@ const generatePreview = (
|
|
103
98
|
...RenderableChangeTypes,
|
104
99
|
...(isStore ? StoreSpecificRenderableTypes : []),
|
105
100
|
]) {
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
const
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
101
|
+
if (changeType.signature) {
|
102
|
+
// Note that we currently only have renderers that depend upon
|
103
|
+
// add, remove, replace, but we should likely add
|
104
|
+
// move, copy, test
|
105
|
+
const requiredMatchCount =
|
106
|
+
changeType.signature.remove.length +
|
107
|
+
changeType.signature.replace.length +
|
108
|
+
changeType.signature.add.length;
|
109
|
+
let matchingOps = 0;
|
110
|
+
for (const change of changes) {
|
111
|
+
const op = change.op;
|
112
|
+
switch (op) {
|
113
|
+
case "add":
|
114
|
+
if (
|
115
|
+
changeType.signature.add &&
|
116
|
+
changeType.signature.add.length > 0
|
117
|
+
) {
|
118
|
+
changeType.signature.add.forEach((signature) => {
|
119
|
+
if (change.path.match(signature)) {
|
120
|
+
matchingOps++;
|
121
|
+
}
|
122
|
+
});
|
123
|
+
}
|
124
|
+
break;
|
125
|
+
case "remove":
|
126
|
+
if (
|
127
|
+
changeType.signature.remove &&
|
128
|
+
changeType.signature.remove.length > 0
|
129
|
+
) {
|
130
|
+
changeType.signature.remove.forEach((signature) => {
|
131
|
+
if (change.path.match(signature)) {
|
132
|
+
matchingOps++;
|
133
|
+
}
|
134
|
+
});
|
135
|
+
}
|
136
|
+
break;
|
137
|
+
case "replace":
|
138
|
+
if (
|
139
|
+
changeType.signature.replace &&
|
140
|
+
changeType.signature.replace.length > 0
|
141
|
+
) {
|
142
|
+
changeType.signature.replace.forEach((signature) => {
|
143
|
+
if (change.path.match(signature)) {
|
144
|
+
matchingOps++;
|
145
|
+
}
|
146
|
+
});
|
147
|
+
}
|
148
|
+
break;
|
149
|
+
}
|
150
|
+
}
|
151
|
+
if (matchingOps === requiredMatchCount) {
|
152
|
+
const el = changeType.render(changes, resolvedState);
|
153
|
+
results.push(el);
|
154
|
+
// Only one renderer can process a change
|
155
|
+
// TODO: consider changing this to allow many handlers to render (though then we sort of need
|
156
|
+
// to match the renderer to the key (e.g. a rendered for `tool_choice` a renderer for `tools` etc..))
|
157
|
+
break;
|
158
|
+
}
|
159
|
+
} else if (changeType.match) {
|
160
|
+
const matches = changeType.match(changes);
|
161
|
+
if (matches) {
|
162
|
+
const el = changeType.render(changes, resolvedState);
|
163
|
+
results.push(el);
|
164
|
+
break;
|
150
165
|
}
|
151
|
-
}
|
152
|
-
if (matchingOps === requiredMatchCount) {
|
153
|
-
const el = changeType.render(changes, resolvedState);
|
154
|
-
results.push(el);
|
155
|
-
// Only one renderer can process a change
|
156
|
-
// TODO: consider changing this to allow many handlers to render (though then we sort of need
|
157
|
-
// to match the renderer to the key (e.g. a rendered for `tool_choice` a renderer for `tools` etc..))
|
158
|
-
break;
|
159
166
|
}
|
160
167
|
}
|
161
168
|
return results.length > 0 ? results : undefined;
|
@@ -269,21 +276,44 @@ function setPath(
|
|
269
276
|
value: unknown,
|
270
277
|
): void {
|
271
278
|
const keys = parsePath(path);
|
272
|
-
let current: Record<string, unknown> = target;
|
279
|
+
let current: Record<string, unknown> | unknown[] = target;
|
273
280
|
|
274
281
|
for (let i = 0; i < keys.length - 1; i++) {
|
275
282
|
const key = keys[i];
|
276
|
-
|
277
|
-
|
278
|
-
|
283
|
+
|
284
|
+
if (Array.isArray(current)) {
|
285
|
+
const numericIndex = getIndex(key);
|
286
|
+
current[numericIndex] = isArrayIndex(keys[i + 1]) ? [] : {};
|
287
|
+
current = current[numericIndex] as
|
288
|
+
| Record<string, unknown>
|
289
|
+
| Array<unknown>;
|
290
|
+
} else {
|
291
|
+
if (!(key in current)) {
|
292
|
+
// If the next key is a number, create an array, otherwise an object
|
293
|
+
current[key] = isArrayIndex(keys[i + 1]) ? [] : {};
|
294
|
+
}
|
295
|
+
current = current[key] as Record<string, unknown> | Array<unknown>;
|
279
296
|
}
|
280
|
-
current = current[key] as Record<string, unknown>;
|
281
297
|
}
|
282
298
|
|
283
299
|
const lastKey = keys[keys.length - 1];
|
284
|
-
current
|
300
|
+
if (Array.isArray(current)) {
|
301
|
+
const numericIndex = getIndex(lastKey);
|
302
|
+
current[numericIndex] = value;
|
303
|
+
} else {
|
304
|
+
current[lastKey] = value;
|
305
|
+
}
|
285
306
|
}
|
286
307
|
|
308
|
+
const getIndex = (key: string): number => {
|
309
|
+
const numericIndex = isArrayIndex(key) ? parseInt(key) : undefined;
|
310
|
+
if (numericIndex === undefined) {
|
311
|
+
throw new Error(`The key ${key} isn't a valid Array index!`);
|
312
|
+
}
|
313
|
+
|
314
|
+
return numericIndex;
|
315
|
+
};
|
316
|
+
|
287
317
|
/**
|
288
318
|
* Places structure in an object (without placing values)
|
289
319
|
*/
|
@@ -0,0 +1,87 @@
|
|
1
|
+
import { EvalSummary, SampleSummary } from "../api/types";
|
2
|
+
import { EvalResults } from "../types/log";
|
3
|
+
|
4
|
+
export interface ScorerInfo {
|
5
|
+
name: string;
|
6
|
+
scorer: string;
|
7
|
+
}
|
8
|
+
|
9
|
+
/**
|
10
|
+
* Extracts scorer information from evaluation results
|
11
|
+
*/
|
12
|
+
const getScorersFromResults = (results?: EvalResults): ScorerInfo[] => {
|
13
|
+
if (!results?.scores) {
|
14
|
+
return [];
|
15
|
+
}
|
16
|
+
|
17
|
+
return results.scores.reduce((uniqueScorers, score) => {
|
18
|
+
const isDuplicate = uniqueScorers.some(
|
19
|
+
(existing) =>
|
20
|
+
existing.scorer === score.scorer && existing.name === score.name,
|
21
|
+
);
|
22
|
+
|
23
|
+
if (!isDuplicate) {
|
24
|
+
uniqueScorers.push({
|
25
|
+
name: score.name,
|
26
|
+
scorer: score.scorer,
|
27
|
+
});
|
28
|
+
}
|
29
|
+
|
30
|
+
return uniqueScorers;
|
31
|
+
}, [] as ScorerInfo[]);
|
32
|
+
};
|
33
|
+
|
34
|
+
/**
|
35
|
+
* Extracts scorer information from sample summaries
|
36
|
+
*/
|
37
|
+
const getScorersFromSamples = (samples: SampleSummary[]): ScorerInfo[] => {
|
38
|
+
// Find a sample with scores
|
39
|
+
const scoredSample = samples.find((sample) => {
|
40
|
+
return !!sample.scores;
|
41
|
+
});
|
42
|
+
|
43
|
+
return Object.keys(scoredSample?.scores || {}).map((key) => ({
|
44
|
+
name: key,
|
45
|
+
scorer: key,
|
46
|
+
}));
|
47
|
+
};
|
48
|
+
|
49
|
+
/**
|
50
|
+
* Gets all available scorers for a log, prioritizing results over samples
|
51
|
+
*/
|
52
|
+
export const getAvailableScorers = (
|
53
|
+
log: EvalSummary,
|
54
|
+
sampleSummaries: SampleSummary[],
|
55
|
+
): ScorerInfo[] | undefined => {
|
56
|
+
const resultScorers = log.results ? getScorersFromResults(log.results) : [];
|
57
|
+
if (resultScorers.length > 0) {
|
58
|
+
return resultScorers;
|
59
|
+
}
|
60
|
+
|
61
|
+
const sampleScorers = getScorersFromSamples(sampleSummaries);
|
62
|
+
if (sampleScorers.length > 0) {
|
63
|
+
return sampleScorers;
|
64
|
+
}
|
65
|
+
|
66
|
+
return undefined;
|
67
|
+
};
|
68
|
+
|
69
|
+
/**
|
70
|
+
* Gets the default scorer to use, preferring the first scorer from results
|
71
|
+
* or falling back to the first scorer from samples
|
72
|
+
*/
|
73
|
+
export const getDefaultScorer = (
|
74
|
+
log: EvalSummary,
|
75
|
+
sampleSummaries: SampleSummary[],
|
76
|
+
): ScorerInfo | undefined => {
|
77
|
+
if (sampleSummaries.length === 0) {
|
78
|
+
return undefined;
|
79
|
+
}
|
80
|
+
|
81
|
+
const allScorers = getAvailableScorers(log, sampleSummaries);
|
82
|
+
if (allScorers) {
|
83
|
+
return allScorers[0];
|
84
|
+
} else {
|
85
|
+
return undefined;
|
86
|
+
}
|
87
|
+
};
|