inspect-ai 0.3.103__py3-none-any.whl → 0.3.105__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/common.py +2 -1
- inspect_ai/_cli/eval.py +2 -2
- inspect_ai/_display/core/active.py +3 -0
- inspect_ai/_display/core/config.py +1 -0
- inspect_ai/_display/core/panel.py +21 -13
- inspect_ai/_display/core/results.py +3 -7
- inspect_ai/_display/core/rich.py +3 -5
- inspect_ai/_display/log/__init__.py +0 -0
- inspect_ai/_display/log/display.py +173 -0
- inspect_ai/_display/plain/display.py +2 -2
- inspect_ai/_display/rich/display.py +2 -4
- inspect_ai/_display/textual/app.py +1 -6
- inspect_ai/_display/textual/widgets/task_detail.py +3 -14
- inspect_ai/_display/textual/widgets/tasks.py +1 -1
- inspect_ai/_eval/eval.py +1 -1
- inspect_ai/_eval/evalset.py +3 -3
- inspect_ai/_eval/registry.py +6 -1
- inspect_ai/_eval/run.py +5 -1
- inspect_ai/_eval/task/constants.py +1 -0
- inspect_ai/_eval/task/log.py +2 -0
- inspect_ai/_eval/task/run.py +65 -39
- inspect_ai/_util/citation.py +88 -0
- inspect_ai/_util/content.py +24 -2
- inspect_ai/_util/json.py +17 -2
- inspect_ai/_util/registry.py +19 -4
- inspect_ai/_view/schema.py +0 -6
- inspect_ai/_view/server.py +17 -0
- inspect_ai/_view/www/dist/assets/index.css +93 -31
- inspect_ai/_view/www/dist/assets/index.js +10639 -10011
- inspect_ai/_view/www/log-schema.json +418 -1
- inspect_ai/_view/www/node_modules/flatted/python/flatted.py +149 -0
- inspect_ai/_view/www/node_modules/katex/src/fonts/generate_fonts.py +58 -0
- inspect_ai/_view/www/node_modules/katex/src/metrics/extract_tfms.py +114 -0
- inspect_ai/_view/www/node_modules/katex/src/metrics/extract_ttfs.py +122 -0
- inspect_ai/_view/www/node_modules/katex/src/metrics/format_json.py +28 -0
- inspect_ai/_view/www/node_modules/katex/src/metrics/parse_tfm.py +211 -0
- inspect_ai/_view/www/package.json +2 -2
- inspect_ai/_view/www/src/@types/log.d.ts +140 -39
- inspect_ai/_view/www/src/app/content/RecordTree.tsx +13 -0
- inspect_ai/_view/www/src/app/log-view/LogView.tsx +1 -1
- inspect_ai/_view/www/src/app/routing/logNavigation.ts +31 -0
- inspect_ai/_view/www/src/app/routing/{navigationHooks.ts → sampleNavigation.ts} +39 -86
- inspect_ai/_view/www/src/app/samples/SampleDialog.tsx +1 -1
- inspect_ai/_view/www/src/app/samples/SampleDisplay.tsx +1 -1
- inspect_ai/_view/www/src/app/samples/chat/ChatMessage.module.css +4 -0
- inspect_ai/_view/www/src/app/samples/chat/ChatMessage.tsx +17 -0
- inspect_ai/_view/www/src/app/samples/chat/MessageCitations.module.css +16 -0
- inspect_ai/_view/www/src/app/samples/chat/MessageCitations.tsx +63 -0
- inspect_ai/_view/www/src/app/samples/chat/MessageContent.module.css +6 -0
- inspect_ai/_view/www/src/app/samples/chat/MessageContent.tsx +174 -25
- inspect_ai/_view/www/src/app/samples/chat/MessageContents.tsx +21 -3
- inspect_ai/_view/www/src/app/samples/chat/content-data/ContentDataView.module.css +7 -0
- inspect_ai/_view/www/src/app/samples/chat/content-data/ContentDataView.tsx +111 -0
- inspect_ai/_view/www/src/app/samples/chat/content-data/WebSearch.module.css +10 -0
- inspect_ai/_view/www/src/app/samples/chat/content-data/WebSearch.tsx +14 -0
- inspect_ai/_view/www/src/app/samples/chat/content-data/WebSearchResults.module.css +19 -0
- inspect_ai/_view/www/src/app/samples/chat/content-data/WebSearchResults.tsx +49 -0
- inspect_ai/_view/www/src/app/samples/chat/messages.ts +7 -1
- inspect_ai/_view/www/src/app/samples/chat/tools/ToolCallView.tsx +12 -2
- inspect_ai/_view/www/src/app/samples/chat/types.ts +4 -0
- inspect_ai/_view/www/src/app/samples/list/SampleList.tsx +1 -1
- inspect_ai/_view/www/src/app/samples/sample-tools/filters.ts +26 -0
- inspect_ai/_view/www/src/app/samples/sample-tools/sample-filter/SampleFilter.tsx +14 -3
- inspect_ai/_view/www/src/app/samples/sample-tools/sample-filter/completions.ts +359 -7
- inspect_ai/_view/www/src/app/samples/sample-tools/sample-filter/language.ts +6 -0
- inspect_ai/_view/www/src/app/samples/sampleLimit.ts +2 -2
- inspect_ai/_view/www/src/app/samples/transcript/ModelEventView.tsx +1 -1
- inspect_ai/_view/www/src/app/samples/transcript/SampleLimitEventView.tsx +4 -4
- inspect_ai/_view/www/src/app/samples/transcript/outline/OutlineRow.tsx +1 -1
- inspect_ai/_view/www/src/app/samples/transcript/outline/TranscriptOutline.tsx +1 -1
- inspect_ai/_view/www/src/client/api/api-browser.ts +25 -0
- inspect_ai/_view/www/src/client/api/api-http.ts +3 -0
- inspect_ai/_view/www/src/client/api/api-vscode.ts +6 -0
- inspect_ai/_view/www/src/client/api/client-api.ts +3 -0
- inspect_ai/_view/www/src/client/api/jsonrpc.ts +1 -0
- inspect_ai/_view/www/src/client/api/types.ts +3 -0
- inspect_ai/_view/www/src/components/MarkdownDiv.tsx +15 -2
- inspect_ai/_view/www/src/state/samplePolling.ts +17 -1
- inspect_ai/_view/www/src/tests/README.md +2 -2
- inspect_ai/_view/www/src/utils/git.ts +3 -1
- inspect_ai/_view/www/src/utils/html.ts +6 -0
- inspect_ai/agent/_handoff.py +8 -5
- inspect_ai/agent/_react.py +5 -5
- inspect_ai/dataset/_dataset.py +1 -1
- inspect_ai/log/_condense.py +5 -0
- inspect_ai/log/_file.py +4 -1
- inspect_ai/log/_log.py +9 -4
- inspect_ai/log/_recorders/json.py +4 -2
- inspect_ai/log/_samples.py +5 -0
- inspect_ai/log/_util.py +2 -0
- inspect_ai/model/__init__.py +14 -0
- inspect_ai/model/_call_tools.py +17 -8
- inspect_ai/model/_chat_message.py +3 -0
- inspect_ai/model/_openai_responses.py +80 -34
- inspect_ai/model/_providers/_anthropic_citations.py +158 -0
- inspect_ai/model/_providers/_google_citations.py +100 -0
- inspect_ai/model/_providers/anthropic.py +219 -36
- inspect_ai/model/_providers/google.py +98 -22
- inspect_ai/model/_providers/mistral.py +20 -7
- inspect_ai/model/_providers/openai.py +11 -10
- inspect_ai/model/_providers/openai_compatible.py +3 -2
- inspect_ai/model/_providers/openai_responses.py +2 -5
- inspect_ai/model/_providers/perplexity.py +123 -0
- inspect_ai/model/_providers/providers.py +13 -2
- inspect_ai/model/_providers/vertex.py +3 -0
- inspect_ai/model/_trim.py +5 -0
- inspect_ai/tool/__init__.py +14 -0
- inspect_ai/tool/_mcp/_mcp.py +5 -2
- inspect_ai/tool/_mcp/sampling.py +19 -3
- inspect_ai/tool/_mcp/server.py +1 -1
- inspect_ai/tool/_tool.py +10 -1
- inspect_ai/tool/_tools/_web_search/_base_http_provider.py +104 -0
- inspect_ai/tool/_tools/_web_search/_exa.py +78 -0
- inspect_ai/tool/_tools/_web_search/_google.py +22 -25
- inspect_ai/tool/_tools/_web_search/_tavily.py +47 -65
- inspect_ai/tool/_tools/_web_search/_web_search.py +83 -36
- inspect_ai/tool/_tools/_web_search/_web_search_provider.py +7 -0
- inspect_ai/util/__init__.py +8 -0
- inspect_ai/util/_background.py +64 -0
- inspect_ai/util/_display.py +11 -2
- inspect_ai/util/_limit.py +72 -5
- inspect_ai/util/_sandbox/__init__.py +2 -0
- inspect_ai/util/_sandbox/docker/compose.py +2 -2
- inspect_ai/util/_sandbox/service.py +28 -7
- inspect_ai/util/_span.py +12 -1
- inspect_ai/util/_subprocess.py +51 -38
- {inspect_ai-0.3.103.dist-info → inspect_ai-0.3.105.dist-info}/METADATA +2 -2
- {inspect_ai-0.3.103.dist-info → inspect_ai-0.3.105.dist-info}/RECORD +134 -109
- /inspect_ai/model/{_openai_computer_use.py → _providers/_openai_computer_use.py} +0 -0
- /inspect_ai/model/{_openai_web_search.py → _providers/_openai_web_search.py} +0 -0
- {inspect_ai-0.3.103.dist-info → inspect_ai-0.3.105.dist-info}/WHEEL +0 -0
- {inspect_ai-0.3.103.dist-info → inspect_ai-0.3.105.dist-info}/entry_points.txt +0 -0
- {inspect_ai-0.3.103.dist-info → inspect_ai-0.3.105.dist-info}/licenses/LICENSE +0 -0
- {inspect_ai-0.3.103.dist-info → inspect_ai-0.3.105.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,111 @@
|
|
1
|
+
import { FC, ReactNode } from "react";
|
2
|
+
import { WebSearch } from "./WebSearch";
|
3
|
+
|
4
|
+
import clsx from "clsx";
|
5
|
+
import { ContentData } from "../../../../@types/log";
|
6
|
+
import { RecordTree } from "../../../content/RecordTree";
|
7
|
+
import styles from "./ContentDataView.module.css";
|
8
|
+
import { WebSearchContentData, WebSearchResults } from "./WebSearchResults";
|
9
|
+
|
10
|
+
export interface ContentDataProps {
|
11
|
+
id: string;
|
12
|
+
contentData: ContentData;
|
13
|
+
}
|
14
|
+
|
15
|
+
interface RenderableData {
|
16
|
+
type: string;
|
17
|
+
name?: string;
|
18
|
+
[key: string]: any;
|
19
|
+
}
|
20
|
+
|
21
|
+
export const ContentDataView: FC<ContentDataProps> = ({ id, contentData }) => {
|
22
|
+
const renderableData = contentData.data as RenderableData;
|
23
|
+
|
24
|
+
const renderer = contentDataRenderers.find((r) =>
|
25
|
+
r.canRender(renderableData),
|
26
|
+
);
|
27
|
+
|
28
|
+
if (!renderer) {
|
29
|
+
const { encrypted_content, ...record } = renderableData;
|
30
|
+
return (
|
31
|
+
<div className={clsx(styles.contentData)}>
|
32
|
+
<RecordTree
|
33
|
+
id={`${id}-tree`}
|
34
|
+
record={record}
|
35
|
+
className={clsx(styles.data)}
|
36
|
+
defaultExpandLevel={0}
|
37
|
+
/>
|
38
|
+
</div>
|
39
|
+
);
|
40
|
+
}
|
41
|
+
|
42
|
+
return (
|
43
|
+
<div className={clsx(styles.contentData)}>
|
44
|
+
{renderer.render(renderableData)}
|
45
|
+
</div>
|
46
|
+
);
|
47
|
+
};
|
48
|
+
|
49
|
+
// The following handles rendering of the content data based on its type
|
50
|
+
// and name, allowing for different renderers to be used for different types of content data.
|
51
|
+
|
52
|
+
interface ContentDataRenderer {
|
53
|
+
name: string;
|
54
|
+
canRender: (data: RenderableData) => boolean;
|
55
|
+
render: (data: RenderableData) => ReactNode;
|
56
|
+
}
|
57
|
+
|
58
|
+
const webSearchServerToolRenderer: ContentDataRenderer = {
|
59
|
+
name: "WebSearch",
|
60
|
+
canRender: (data: RenderableData) => {
|
61
|
+
return data.type === "server_tool_use" && data.name === "web_search";
|
62
|
+
},
|
63
|
+
render: (data: RenderableData): ReactNode => {
|
64
|
+
return <WebSearch query={data.input.query} />;
|
65
|
+
},
|
66
|
+
};
|
67
|
+
|
68
|
+
const webSearchResultsServerToolRenderer: ContentDataRenderer = {
|
69
|
+
name: "WebSearchResults",
|
70
|
+
canRender: (data: RenderableData) => {
|
71
|
+
return (
|
72
|
+
data.type === "web_search_tool_result" && Array.isArray(data.content)
|
73
|
+
);
|
74
|
+
},
|
75
|
+
render: (data: RenderableData): ReactNode => {
|
76
|
+
const results: WebSearchContentData[] =
|
77
|
+
data.content as WebSearchContentData[];
|
78
|
+
return <WebSearchResults results={results} />;
|
79
|
+
},
|
80
|
+
};
|
81
|
+
|
82
|
+
const serverToolRenderer: ContentDataRenderer = {
|
83
|
+
name: "ServerTool",
|
84
|
+
canRender: (data: RenderableData) => data.type === "server_tool_use",
|
85
|
+
render: (data: RenderableData): ReactNode => {
|
86
|
+
return (
|
87
|
+
<>
|
88
|
+
<div
|
89
|
+
className={clsx(
|
90
|
+
"text-style-label",
|
91
|
+
"text-style-secondary",
|
92
|
+
"text-size-smaller",
|
93
|
+
)}
|
94
|
+
>
|
95
|
+
Server Tool
|
96
|
+
</div>
|
97
|
+
<RecordTree
|
98
|
+
id={data.name || "server-tool"}
|
99
|
+
record={data}
|
100
|
+
className={clsx(styles.data)}
|
101
|
+
/>
|
102
|
+
</>
|
103
|
+
);
|
104
|
+
},
|
105
|
+
};
|
106
|
+
|
107
|
+
export const contentDataRenderers: ContentDataRenderer[] = [
|
108
|
+
webSearchServerToolRenderer,
|
109
|
+
webSearchResultsServerToolRenderer,
|
110
|
+
serverToolRenderer,
|
111
|
+
];
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import clsx from "clsx";
|
2
|
+
import { FC } from "react";
|
3
|
+
import styles from "./WebSearch.module.css";
|
4
|
+
|
5
|
+
export const WebSearch: FC<{ query: string }> = ({ query }) => {
|
6
|
+
return (
|
7
|
+
<div className={clsx(styles.webSearch, "text-size-smaller")}>
|
8
|
+
<span className={clsx("text-style-label", "text-style-secondary")}>
|
9
|
+
Web Search:
|
10
|
+
</span>
|
11
|
+
<span className={clsx(styles.query, "text-size-smallest")}>{query}</span>
|
12
|
+
</div>
|
13
|
+
);
|
14
|
+
};
|
@@ -0,0 +1,19 @@
|
|
1
|
+
.webSearch {
|
2
|
+
display: grid;
|
3
|
+
grid-template-columns: max-content 1fr;
|
4
|
+
column-gap: 0.5em;
|
5
|
+
align-items: baseline;
|
6
|
+
}
|
7
|
+
|
8
|
+
.query {
|
9
|
+
font-family: var(--bs-font-monospace);
|
10
|
+
}
|
11
|
+
|
12
|
+
.result a:hover {
|
13
|
+
text-decoration: underline;
|
14
|
+
}
|
15
|
+
|
16
|
+
.result a {
|
17
|
+
opacity: 0.8;
|
18
|
+
text-decoration: none;
|
19
|
+
}
|
@@ -0,0 +1,49 @@
|
|
1
|
+
import clsx from "clsx";
|
2
|
+
import { FC } from "react";
|
3
|
+
import styles from "./WebSearchResults.module.css";
|
4
|
+
|
5
|
+
export interface WebSearchContentData {
|
6
|
+
title: string;
|
7
|
+
url: string;
|
8
|
+
page_age: string;
|
9
|
+
}
|
10
|
+
|
11
|
+
export const WebSearchResults: FC<{ results: WebSearchContentData[] }> = ({
|
12
|
+
results,
|
13
|
+
}) => {
|
14
|
+
return (
|
15
|
+
<>
|
16
|
+
<div
|
17
|
+
className={clsx(
|
18
|
+
styles.label,
|
19
|
+
"text-style-label",
|
20
|
+
"text-style-secondary",
|
21
|
+
"text-size-smaller",
|
22
|
+
)}
|
23
|
+
>
|
24
|
+
Results
|
25
|
+
</div>
|
26
|
+
|
27
|
+
<ol className={clsx(styles.results, "text-size-smaller")}>
|
28
|
+
{results.map((result, index) => (
|
29
|
+
<li
|
30
|
+
key={index}
|
31
|
+
className={clsx(styles.result, "text-style-secondary")}
|
32
|
+
>
|
33
|
+
<a
|
34
|
+
href={result.url}
|
35
|
+
target="_blank"
|
36
|
+
rel="noopener noreferrer"
|
37
|
+
title={
|
38
|
+
result.url +
|
39
|
+
(result.page_age ? `\n(Age: ${result.page_age})` : "")
|
40
|
+
}
|
41
|
+
>
|
42
|
+
{result.title}
|
43
|
+
</a>
|
44
|
+
</li>
|
45
|
+
))}
|
46
|
+
</ol>
|
47
|
+
</>
|
48
|
+
);
|
49
|
+
};
|
@@ -4,6 +4,7 @@ import {
|
|
4
4
|
ChatMessageTool,
|
5
5
|
ChatMessageUser,
|
6
6
|
ContentAudio,
|
7
|
+
ContentData,
|
7
8
|
ContentImage,
|
8
9
|
ContentReasoning,
|
9
10
|
ContentText,
|
@@ -64,6 +65,7 @@ export const resolveMessages = (messages: Messages) => {
|
|
64
65
|
| ContentAudio
|
65
66
|
| ContentVideo
|
66
67
|
| ContentReasoning
|
68
|
+
| ContentData
|
67
69
|
)[] = [];
|
68
70
|
for (const systemMessage of systemMessages) {
|
69
71
|
const contents = Array.isArray(systemMessage.content)
|
@@ -78,6 +80,7 @@ export const resolveMessages = (messages: Messages) => {
|
|
78
80
|
content: systemContent,
|
79
81
|
source: "input",
|
80
82
|
internal: null,
|
83
|
+
metadata: null,
|
81
84
|
};
|
82
85
|
|
83
86
|
// Converge them
|
@@ -117,19 +120,22 @@ const normalizeContent = (
|
|
117
120
|
| ContentAudio
|
118
121
|
| ContentVideo
|
119
122
|
| ContentReasoning
|
123
|
+
| ContentData
|
120
124
|
| string,
|
121
125
|
):
|
122
126
|
| ContentText
|
123
127
|
| ContentImage
|
124
128
|
| ContentAudio
|
125
129
|
| ContentVideo
|
126
|
-
| ContentReasoning
|
130
|
+
| ContentReasoning
|
131
|
+
| ContentData => {
|
127
132
|
if (typeof content === "string") {
|
128
133
|
return {
|
129
134
|
type: "text",
|
130
135
|
text: content,
|
131
136
|
refusal: null,
|
132
137
|
internal: null,
|
138
|
+
citations: null,
|
133
139
|
};
|
134
140
|
} else {
|
135
141
|
return content;
|
@@ -2,6 +2,7 @@ import clsx from "clsx";
|
|
2
2
|
import { FC, useMemo } from "react";
|
3
3
|
import {
|
4
4
|
ContentAudio,
|
5
|
+
ContentData,
|
5
6
|
ContentImage,
|
6
7
|
ContentReasoning,
|
7
8
|
ContentText,
|
@@ -11,6 +12,7 @@ import {
|
|
11
12
|
import { ContentTool } from "../../../../app/types";
|
12
13
|
import ExpandablePanel from "../../../../components/ExpandablePanel";
|
13
14
|
import { MessageContent } from "../MessageContent";
|
15
|
+
import { defaultContext } from "../MessageContents";
|
14
16
|
import styles from "./ToolCallView.module.css";
|
15
17
|
import { ToolInput } from "./ToolInput";
|
16
18
|
import { ToolTitle } from "./ToolTitle";
|
@@ -31,6 +33,7 @@ interface ToolCallViewProps {
|
|
31
33
|
| ContentVideo
|
32
34
|
| ContentTool
|
33
35
|
| ContentReasoning
|
36
|
+
| ContentData
|
34
37
|
| (
|
35
38
|
| ContentText
|
36
39
|
| ContentAudio
|
@@ -38,6 +41,7 @@ interface ToolCallViewProps {
|
|
38
41
|
| ContentVideo
|
39
42
|
| ContentTool
|
40
43
|
| ContentReasoning
|
44
|
+
| ContentData
|
41
45
|
)[];
|
42
46
|
mode?: "compact";
|
43
47
|
}
|
@@ -65,7 +69,8 @@ export const ToolCallView: FC<ToolCallViewProps> = ({
|
|
65
69
|
| ContentImage
|
66
70
|
| ContentVideo
|
67
71
|
| ContentTool
|
68
|
-
| ContentReasoning
|
72
|
+
| ContentReasoning
|
73
|
+
| ContentData,
|
69
74
|
) {
|
70
75
|
if (value && typeof value === "object") {
|
71
76
|
if (value.type === "image") {
|
@@ -105,6 +110,7 @@ export const ToolCallView: FC<ToolCallViewProps> = ({
|
|
105
110
|
});
|
106
111
|
|
107
112
|
const contents = mode !== "compact" ? input : input || functionCall;
|
113
|
+
const context = defaultContext();
|
108
114
|
return (
|
109
115
|
<div className={clsx(styles.toolCallView)}>
|
110
116
|
<div>
|
@@ -127,7 +133,7 @@ export const ToolCallView: FC<ToolCallViewProps> = ({
|
|
127
133
|
lines={15}
|
128
134
|
className={clsx("text-size-small")}
|
129
135
|
>
|
130
|
-
<MessageContent contents={normalizedContent} />
|
136
|
+
<MessageContent contents={normalizedContent} context={context} />
|
131
137
|
</ExpandablePanel>
|
132
138
|
) : undefined}
|
133
139
|
</div>
|
@@ -148,6 +154,7 @@ const normalizeContent = (
|
|
148
154
|
| ContentVideo
|
149
155
|
| ContentTool
|
150
156
|
| ContentReasoning
|
157
|
+
| ContentData
|
151
158
|
| (
|
152
159
|
| ContentText
|
153
160
|
| ContentImage
|
@@ -155,6 +162,7 @@ const normalizeContent = (
|
|
155
162
|
| ContentVideo
|
156
163
|
| ContentTool
|
157
164
|
| ContentReasoning
|
165
|
+
| ContentData
|
158
166
|
)[],
|
159
167
|
): (
|
160
168
|
| ContentText
|
@@ -163,6 +171,7 @@ const normalizeContent = (
|
|
163
171
|
| ContentVideo
|
164
172
|
| ContentTool
|
165
173
|
| ContentReasoning
|
174
|
+
| ContentData
|
166
175
|
)[] => {
|
167
176
|
if (Array.isArray(output)) {
|
168
177
|
return output;
|
@@ -176,6 +185,7 @@ const normalizeContent = (
|
|
176
185
|
text: String(output),
|
177
186
|
refusal: null,
|
178
187
|
internal: null,
|
188
|
+
citations: null,
|
179
189
|
},
|
180
190
|
],
|
181
191
|
},
|
@@ -20,7 +20,7 @@ import clsx from "clsx";
|
|
20
20
|
import { useProperty, useSampleDescriptor } from "../../../state/hooks";
|
21
21
|
import { useVirtuosoState } from "../../../state/scrolling";
|
22
22
|
import { useStore } from "../../../state/store";
|
23
|
-
import { useSampleNavigation } from "../../routing/
|
23
|
+
import { useSampleNavigation } from "../../routing/sampleNavigation";
|
24
24
|
import { SampleFooter } from "./SampleFooter";
|
25
25
|
import { SampleHeader } from "./SampleHeader";
|
26
26
|
import styles from "./SampleList.module.css";
|
@@ -5,6 +5,7 @@ import { SampleSummary } from "../../../client/api/types";
|
|
5
5
|
import { kScoreTypeBoolean } from "../../../constants";
|
6
6
|
import { inputString } from "../../../utils/format";
|
7
7
|
import { EvalDescriptor, ScoreDescriptor } from "../descriptor/types";
|
8
|
+
import { kSampleMetadataPrefix } from "./sample-filter/language";
|
8
9
|
|
9
10
|
export interface SampleFilterItem {
|
10
11
|
shortName?: string;
|
@@ -100,10 +101,25 @@ const scoreVariables = (
|
|
100
101
|
return variables;
|
101
102
|
};
|
102
103
|
|
104
|
+
const getNestedPropertyValue = (obj: any, path: string): any => {
|
105
|
+
const keys = path.split(".");
|
106
|
+
let current = obj;
|
107
|
+
for (const key of keys) {
|
108
|
+
if (current && typeof current === "object" && key in current) {
|
109
|
+
current = current[key];
|
110
|
+
} else {
|
111
|
+
return undefined;
|
112
|
+
}
|
113
|
+
}
|
114
|
+
return current;
|
115
|
+
};
|
116
|
+
|
103
117
|
const sampleVariables = (sample: SampleSummary): Record<string, unknown> => {
|
104
118
|
return {
|
105
119
|
has_error: !!sample.error,
|
106
120
|
has_retries: sample.retries !== undefined && sample.retries > 0,
|
121
|
+
id: sample.id,
|
122
|
+
metadata: sample.metadata,
|
107
123
|
};
|
108
124
|
};
|
109
125
|
|
@@ -217,6 +233,12 @@ export const filterExpression = (
|
|
217
233
|
const value = get(name);
|
218
234
|
return value;
|
219
235
|
}
|
236
|
+
// Handle metadata property access
|
237
|
+
if (name.startsWith(kSampleMetadataPrefix)) {
|
238
|
+
const propertyPath = name.substring(kSampleMetadataPrefix.length);
|
239
|
+
const metadata = sample.metadata || {};
|
240
|
+
return getNestedPropertyValue(metadata, propertyPath);
|
241
|
+
}
|
220
242
|
// Score variables exist only if the sample completed successfully.
|
221
243
|
return sample.error ? undefined : get(name);
|
222
244
|
};
|
@@ -240,6 +262,10 @@ export const filterExpression = (
|
|
240
262
|
const errorObj = error as any as Record<string, unknown>;
|
241
263
|
const propertyName: string = (errorObj["propertyName"] as string) || "";
|
242
264
|
if (propertyName) {
|
265
|
+
// Don't show errors for metadata properties - they might not exist in all samples
|
266
|
+
if (propertyName.startsWith(kSampleMetadataPrefix)) {
|
267
|
+
return { matches: false, error: undefined };
|
268
|
+
}
|
243
269
|
const regex = new RegExp(`\\b${propertyName}\\b`);
|
244
270
|
const match = regex.exec(filterValue);
|
245
271
|
if (match) {
|
@@ -34,6 +34,8 @@ Filter samples by:
|
|
34
34
|
• Samples with errors: has_error
|
35
35
|
• Input, target and error regex search: input_contains, target_contains, error_contains
|
36
36
|
• Samples that have been retried: has_retries
|
37
|
+
• Sample Id: e.g. "id == 'sample123'"
|
38
|
+
• Sample metadata: e.g. "metadata.key == 'value'"
|
37
39
|
|
38
40
|
Supported expressions:
|
39
41
|
• Arithmetic: +, -, *, /, mod, ^
|
@@ -93,6 +95,12 @@ const editorTheme = EditorView.theme({
|
|
93
95
|
".cm-scroller": {
|
94
96
|
overflow: "hidden",
|
95
97
|
},
|
98
|
+
".cm-line": {
|
99
|
+
"font-size": "var(--inspect-font-size-smallest) !important",
|
100
|
+
},
|
101
|
+
".token": {
|
102
|
+
"font-size": "var(--inspect-font-size-smallest) !important",
|
103
|
+
},
|
96
104
|
});
|
97
105
|
|
98
106
|
const ensureOneLine = (tr: Transaction): TransactionSpec => {
|
@@ -145,6 +153,9 @@ export const SampleFilter: FC<SampleFilterProps> = () => {
|
|
145
153
|
|
146
154
|
const filter = useStore((state) => state.log.filter);
|
147
155
|
const filterError = useStore((state) => state.log.filterError);
|
156
|
+
const samples = useStore(
|
157
|
+
(state) => state.log.selectedLogSummary?.sampleSummaries,
|
158
|
+
);
|
148
159
|
const setFilter = useStore((state) => state.logActions.setFilter);
|
149
160
|
|
150
161
|
const handleFocus = useCallback((event: FocusEvent, view: EditorView) => {
|
@@ -156,10 +167,10 @@ export const SampleFilter: FC<SampleFilterProps> = () => {
|
|
156
167
|
const makeAutocompletion = useCallback(
|
157
168
|
() =>
|
158
169
|
autocompletion({
|
159
|
-
override: [(context) => getCompletions(context, filterItems)],
|
170
|
+
override: [(context) => getCompletions(context, filterItems, samples)],
|
160
171
|
activateOnCompletion: (c) => c.label.endsWith(" "),
|
161
172
|
}),
|
162
|
-
[],
|
173
|
+
[filterItems, samples],
|
163
174
|
);
|
164
175
|
|
165
176
|
const makeLinter = useCallback(
|
@@ -240,7 +251,7 @@ export const SampleFilter: FC<SampleFilterProps> = () => {
|
|
240
251
|
effects:
|
241
252
|
autocompletionCompartment.current.reconfigure(makeAutocompletion()),
|
242
253
|
});
|
243
|
-
}, [filterItems]);
|
254
|
+
}, [filterItems, samples]);
|
244
255
|
|
245
256
|
useEffect(() => {
|
246
257
|
editorViewRef.current?.dispatch({
|