inspect-ai 0.3.63__py3-none-any.whl → 0.3.64__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/cache.py +8 -7
- inspect_ai/_cli/common.py +0 -12
- inspect_ai/_cli/eval.py +32 -4
- inspect_ai/_cli/info.py +1 -0
- inspect_ai/_cli/list.py +1 -1
- inspect_ai/_cli/log.py +2 -0
- inspect_ai/_cli/sandbox.py +4 -1
- inspect_ai/_cli/score.py +181 -32
- inspect_ai/_cli/trace.py +2 -0
- inspect_ai/_cli/view.py +4 -2
- inspect_ai/_display/core/config.py +7 -1
- inspect_ai/_display/textual/widgets/samples.py +4 -3
- inspect_ai/_display/textual/widgets/sandbox.py +6 -0
- inspect_ai/_eval/__init__.py +0 -0
- inspect_ai/_eval/eval.py +100 -97
- inspect_ai/_eval/evalset.py +69 -69
- inspect_ai/_eval/loader.py +122 -12
- inspect_ai/_eval/registry.py +1 -1
- inspect_ai/_eval/run.py +14 -0
- inspect_ai/_eval/score.py +125 -36
- inspect_ai/_eval/task/log.py +105 -4
- inspect_ai/_eval/task/results.py +92 -38
- inspect_ai/_eval/task/run.py +6 -2
- inspect_ai/_eval/task/sandbox.py +35 -2
- inspect_ai/_eval/task/task.py +49 -46
- inspect_ai/_util/__init__.py +0 -0
- inspect_ai/_util/constants.py +1 -1
- inspect_ai/_util/content.py +8 -0
- inspect_ai/_util/error.py +2 -0
- inspect_ai/_util/file.py +15 -1
- inspect_ai/_util/logger.py +4 -2
- inspect_ai/_util/registry.py +7 -1
- inspect_ai/_view/view.py +1 -2
- inspect_ai/_view/www/App.css +5 -0
- inspect_ai/_view/www/README.md +1 -1
- inspect_ai/_view/www/dist/assets/index.css +39 -11
- inspect_ai/_view/www/dist/assets/index.js +504 -501
- inspect_ai/_view/www/log-schema.json +86 -73
- inspect_ai/_view/www/package.json +1 -1
- inspect_ai/_view/www/src/App.tsx +1 -0
- inspect_ai/_view/www/src/components/AnsiDisplay.tsx +1 -1
- inspect_ai/_view/www/src/components/JsonPanel.tsx +1 -1
- inspect_ai/_view/www/src/components/LargeModal.tsx +39 -49
- inspect_ai/_view/www/src/components/NavPills.tsx +3 -1
- inspect_ai/_view/www/src/components/TabSet.tsx +19 -4
- inspect_ai/_view/www/src/logfile/remoteLogFile.ts +0 -1
- inspect_ai/_view/www/src/metadata/MetaDataGrid.tsx +1 -1
- inspect_ai/_view/www/src/metadata/MetaDataView.tsx +1 -1
- inspect_ai/_view/www/src/plan/PlanDetailView.tsx +17 -2
- inspect_ai/_view/www/src/plan/SolverDetailView.tsx +1 -1
- inspect_ai/_view/www/src/samples/SampleDisplay.tsx +9 -4
- inspect_ai/_view/www/src/samples/SampleSummaryView.tsx +4 -2
- inspect_ai/_view/www/src/samples/SamplesTools.tsx +16 -24
- inspect_ai/_view/www/src/samples/chat/ChatMessage.tsx +1 -1
- inspect_ai/_view/www/src/samples/chat/ChatView.tsx +1 -0
- inspect_ai/_view/www/src/samples/chat/MessageContent.tsx +27 -13
- inspect_ai/_view/www/src/samples/chat/MessageContents.tsx +19 -17
- inspect_ai/_view/www/src/samples/chat/tools/ToolCallView.tsx +12 -10
- inspect_ai/_view/www/src/samples/chat/tools/ToolInput.tsx +56 -66
- inspect_ai/_view/www/src/samples/chat/tools/ToolOutput.tsx +12 -5
- inspect_ai/_view/www/src/samples/chat/tools/tool.ts +21 -36
- inspect_ai/_view/www/src/samples/descriptor/samplesDescriptor.tsx +3 -1
- inspect_ai/_view/www/src/samples/sample-tools/SelectScorer.tsx +27 -25
- inspect_ai/_view/www/src/samples/sample-tools/SortFilter.tsx +5 -1
- inspect_ai/_view/www/src/samples/transcript/InfoEventView.tsx +1 -1
- inspect_ai/_view/www/src/samples/transcript/ModelEventView.tsx +2 -2
- inspect_ai/_view/www/src/samples/transcript/SampleInitEventView.tsx +9 -5
- inspect_ai/_view/www/src/samples/transcript/ScoreEventView.tsx +1 -1
- inspect_ai/_view/www/src/samples/transcript/ToolEventView.tsx +5 -4
- inspect_ai/_view/www/src/samples/transcript/event/EventNavs.tsx +1 -0
- inspect_ai/_view/www/src/samples/transcript/event/EventPanel.tsx +1 -0
- inspect_ai/_view/www/src/samples/transcript/state/StateEventRenderers.tsx +17 -6
- inspect_ai/_view/www/src/samples/transcript/state/StateEventView.tsx +14 -19
- inspect_ai/_view/www/src/types/log.d.ts +107 -19
- inspect_ai/_view/www/src/usage/ModelTokenTable.tsx +7 -1
- inspect_ai/_view/www/src/usage/ModelUsagePanel.tsx +5 -3
- inspect_ai/_view/www/src/workspace/WorkSpaceView.tsx +25 -27
- inspect_ai/_view/www/src/workspace/navbar/PrimaryBar.tsx +12 -11
- inspect_ai/_view/www/src/workspace/navbar/ResultsPanel.module.css +25 -2
- inspect_ai/_view/www/src/workspace/navbar/ResultsPanel.tsx +60 -36
- inspect_ai/_view/www/src/workspace/navbar/SecondaryBar.tsx +4 -0
- inspect_ai/_view/www/src/workspace/sidebar/SidebarScoreView.tsx +6 -4
- inspect_ai/_view/www/src/workspace/sidebar/SidebarScoresView.tsx +16 -14
- inspect_ai/_view/www/src/workspace/tabs/InfoTab.tsx +9 -19
- inspect_ai/_view/www/src/workspace/utils.ts +34 -0
- inspect_ai/approval/_approval.py +2 -0
- inspect_ai/approval/_approver.py +4 -4
- inspect_ai/approval/_auto.py +1 -1
- inspect_ai/approval/_human/approver.py +3 -0
- inspect_ai/approval/_policy.py +5 -0
- inspect_ai/approval/_registry.py +2 -2
- inspect_ai/dataset/_dataset.py +36 -45
- inspect_ai/dataset/_sources/__init__.py +0 -0
- inspect_ai/dataset/_sources/csv.py +13 -13
- inspect_ai/dataset/_sources/hf.py +29 -29
- inspect_ai/dataset/_sources/json.py +10 -10
- inspect_ai/log/__init__.py +2 -0
- inspect_ai/log/_convert.py +3 -3
- inspect_ai/log/_file.py +24 -9
- inspect_ai/log/_log.py +98 -7
- inspect_ai/log/_message.py +3 -1
- inspect_ai/log/_recorders/file.py +4 -0
- inspect_ai/log/_recorders/recorder.py +3 -0
- inspect_ai/log/_transcript.py +19 -8
- inspect_ai/model/__init__.py +2 -0
- inspect_ai/model/_cache.py +39 -21
- inspect_ai/model/_call_tools.py +2 -2
- inspect_ai/model/_chat_message.py +14 -4
- inspect_ai/model/_generate_config.py +1 -1
- inspect_ai/model/_model.py +31 -24
- inspect_ai/model/_model_output.py +14 -1
- inspect_ai/model/_openai.py +10 -18
- inspect_ai/model/_providers/google.py +9 -5
- inspect_ai/model/_providers/openai.py +5 -9
- inspect_ai/model/_providers/openrouter.py +1 -1
- inspect_ai/scorer/__init__.py +6 -1
- inspect_ai/scorer/_answer.py +1 -1
- inspect_ai/scorer/_classification.py +4 -0
- inspect_ai/scorer/_match.py +4 -5
- inspect_ai/scorer/_metric.py +87 -28
- inspect_ai/scorer/_metrics/__init__.py +3 -3
- inspect_ai/scorer/_metrics/accuracy.py +8 -10
- inspect_ai/scorer/_metrics/mean.py +3 -17
- inspect_ai/scorer/_metrics/std.py +111 -30
- inspect_ai/scorer/_model.py +12 -12
- inspect_ai/scorer/_pattern.py +3 -3
- inspect_ai/scorer/_reducer/reducer.py +36 -21
- inspect_ai/scorer/_reducer/registry.py +2 -2
- inspect_ai/scorer/_reducer/types.py +7 -1
- inspect_ai/scorer/_score.py +11 -1
- inspect_ai/scorer/_scorer.py +110 -16
- inspect_ai/solver/__init__.py +1 -1
- inspect_ai/solver/_basic_agent.py +19 -22
- inspect_ai/solver/_bridge/__init__.py +0 -3
- inspect_ai/solver/_bridge/bridge.py +3 -3
- inspect_ai/solver/_chain.py +1 -2
- inspect_ai/solver/_critique.py +3 -3
- inspect_ai/solver/_fork.py +2 -2
- inspect_ai/solver/_human_agent/__init__.py +0 -0
- inspect_ai/solver/_human_agent/agent.py +5 -8
- inspect_ai/solver/_human_agent/commands/clock.py +14 -10
- inspect_ai/solver/_human_agent/commands/note.py +1 -1
- inspect_ai/solver/_human_agent/commands/score.py +0 -11
- inspect_ai/solver/_multiple_choice.py +15 -18
- inspect_ai/solver/_prompt.py +7 -7
- inspect_ai/solver/_solver.py +53 -52
- inspect_ai/solver/_task_state.py +80 -69
- inspect_ai/solver/_use_tools.py +9 -9
- inspect_ai/tool/__init__.py +2 -1
- inspect_ai/tool/_tool.py +43 -14
- inspect_ai/tool/_tool_call.py +6 -2
- inspect_ai/tool/_tool_choice.py +3 -1
- inspect_ai/tool/_tool_def.py +10 -8
- inspect_ai/tool/_tool_params.py +24 -0
- inspect_ai/tool/_tool_with.py +7 -7
- inspect_ai/tool/_tools/__init__.py +0 -0
- inspect_ai/tool/_tools/_computer/_common.py +2 -2
- inspect_ai/tool/_tools/_computer/_computer.py +11 -0
- inspect_ai/tool/_tools/_execute.py +15 -9
- inspect_ai/tool/_tools/_web_browser/_resources/README.md +2 -2
- inspect_ai/tool/_tools/_web_browser/_web_browser.py +5 -3
- inspect_ai/tool/_tools/_web_search.py +7 -5
- inspect_ai/util/_concurrency.py +3 -3
- inspect_ai/util/_panel.py +2 -0
- inspect_ai/util/_resource.py +12 -12
- inspect_ai/util/_sandbox/docker/compose.py +23 -20
- inspect_ai/util/_sandbox/docker/config.py +2 -1
- inspect_ai/util/_sandbox/docker/docker.py +10 -1
- inspect_ai/util/_sandbox/docker/service.py +100 -0
- inspect_ai/util/_sandbox/environment.py +99 -96
- inspect_ai/util/_subprocess.py +5 -3
- inspect_ai/util/_subtask.py +15 -16
- {inspect_ai-0.3.63.dist-info → inspect_ai-0.3.64.dist-info}/LICENSE +1 -1
- {inspect_ai-0.3.63.dist-info → inspect_ai-0.3.64.dist-info}/METADATA +10 -6
- {inspect_ai-0.3.63.dist-info → inspect_ai-0.3.64.dist-info}/RECORD +178 -171
- {inspect_ai-0.3.63.dist-info → inspect_ai-0.3.64.dist-info}/WHEEL +0 -0
- {inspect_ai-0.3.63.dist-info → inspect_ai-0.3.64.dist-info}/entry_points.txt +0 -0
- {inspect_ai-0.3.63.dist-info → inspect_ai-0.3.64.dist-info}/top_level.txt +0 -0
@@ -26,7 +26,7 @@ export const MetaDataGrid: React.FC<MetadataGridProps> = ({
|
|
26
26
|
const entryEls = entryRecords(entries).map((entry, index) => {
|
27
27
|
const id = `${baseId}-value-${index}`;
|
28
28
|
return (
|
29
|
-
<Fragment>
|
29
|
+
<Fragment key={`${baseId}-record-${index}`}>
|
30
30
|
<div
|
31
31
|
style={{
|
32
32
|
gridColumn: "1 / -1",
|
@@ -125,6 +125,7 @@ export const PlanDetailView: React.FC<PlanDetailViewProps> = ({
|
|
125
125
|
const scorerPanels = Object.keys(scorers).map((key) => {
|
126
126
|
return (
|
127
127
|
<ScorerDetailView
|
128
|
+
key={key}
|
128
129
|
name={key}
|
129
130
|
scores={scorers[key].scores}
|
130
131
|
params={scorers[key].params as Record<string, unknown>}
|
@@ -159,6 +160,7 @@ export const PlanDetailView: React.FC<PlanDetailViewProps> = ({
|
|
159
160
|
className: cols === 1 ? styles.oneCol : styles.twoCol,
|
160
161
|
contents: (
|
161
162
|
<MetaDataView
|
163
|
+
key={`plan-md-task`}
|
162
164
|
className={"text-size-small"}
|
163
165
|
entries={taskInformation}
|
164
166
|
tableOptions="sm"
|
@@ -172,6 +174,7 @@ export const PlanDetailView: React.FC<PlanDetailViewProps> = ({
|
|
172
174
|
className: cols === 1 ? styles.oneCol : styles.twoCol,
|
173
175
|
contents: (
|
174
176
|
<MetaDataView
|
177
|
+
key={`plan-md-task-args`}
|
175
178
|
className={"text-size-small"}
|
176
179
|
entries={task_args as Record<string, unknown>}
|
177
180
|
tableOptions="sm"
|
@@ -185,6 +188,7 @@ export const PlanDetailView: React.FC<PlanDetailViewProps> = ({
|
|
185
188
|
className: cols === 1 ? styles.oneCol : styles.twoCol,
|
186
189
|
contents: (
|
187
190
|
<MetaDataView
|
191
|
+
key={`plan-md-model-args`}
|
188
192
|
className={"text-size-small"}
|
189
193
|
entries={model_args as Record<string, unknown>}
|
190
194
|
tableOptions="sm"
|
@@ -199,6 +203,7 @@ export const PlanDetailView: React.FC<PlanDetailViewProps> = ({
|
|
199
203
|
className: cols === 1 ? styles.oneCol : styles.twoCol,
|
200
204
|
contents: (
|
201
205
|
<MetaDataView
|
206
|
+
key={`plan-md-config`}
|
202
207
|
className={"text-size-small"}
|
203
208
|
entries={config}
|
204
209
|
tableOptions="sm"
|
@@ -217,6 +222,7 @@ export const PlanDetailView: React.FC<PlanDetailViewProps> = ({
|
|
217
222
|
className: cols === 1 ? styles.oneCol : styles.twoCol,
|
218
223
|
contents: (
|
219
224
|
<MetaDataView
|
225
|
+
key={`plan-md-generate-config`}
|
220
226
|
className={"text-size-small"}
|
221
227
|
entries={generate_record}
|
222
228
|
tableOptions="sm"
|
@@ -231,6 +237,7 @@ export const PlanDetailView: React.FC<PlanDetailViewProps> = ({
|
|
231
237
|
className: cols === 1 ? styles.oneCol : styles.twoCol,
|
232
238
|
contents: (
|
233
239
|
<MetaDataView
|
240
|
+
key={`plan-md-metadata`}
|
234
241
|
className={"text-size-small"}
|
235
242
|
entries={metadata}
|
236
243
|
tableOptions="sm"
|
@@ -249,7 +256,11 @@ export const PlanDetailView: React.FC<PlanDetailViewProps> = ({
|
|
249
256
|
>
|
250
257
|
{taskColumns.map((col) => {
|
251
258
|
return (
|
252
|
-
<PlanColumn
|
259
|
+
<PlanColumn
|
260
|
+
title={col.title}
|
261
|
+
className={col.className}
|
262
|
+
key={`plan-col-${col.title}`}
|
263
|
+
>
|
253
264
|
{col.contents}
|
254
265
|
</PlanColumn>
|
255
266
|
);
|
@@ -259,7 +270,11 @@ export const PlanDetailView: React.FC<PlanDetailViewProps> = ({
|
|
259
270
|
<div className={clsx(styles.row)}>
|
260
271
|
{metadataColumns.map((col) => {
|
261
272
|
return (
|
262
|
-
<PlanColumn
|
273
|
+
<PlanColumn
|
274
|
+
title={col.title}
|
275
|
+
className={col.className}
|
276
|
+
key={`plan-col-${col.title}`}
|
277
|
+
>
|
263
278
|
{col.contents}
|
264
279
|
</PlanColumn>
|
265
280
|
);
|
@@ -18,7 +18,7 @@ export const SolversDetailView: React.FC<SolversDetailView> = ({ steps }) => {
|
|
18
18
|
|
19
19
|
const details = steps?.map((step, index) => {
|
20
20
|
return (
|
21
|
-
<Fragment>
|
21
|
+
<Fragment key={`solver-step-${index}`}>
|
22
22
|
<DetailStep
|
23
23
|
name={step.solver}
|
24
24
|
className={clsx(styles.items, "text-size-small")}
|
@@ -77,6 +77,7 @@ export const SampleDisplay: React.FC<SampleDisplayProps> = ({
|
|
77
77
|
if (!isVscode()) {
|
78
78
|
tools.push(
|
79
79
|
<ToolButton
|
80
|
+
key="sample-print-tool"
|
80
81
|
label="Print"
|
81
82
|
icon={ApplicationIcons.copy}
|
82
83
|
onClick={() => {
|
@@ -101,6 +102,7 @@ export const SampleDisplay: React.FC<SampleDisplayProps> = ({
|
|
101
102
|
>
|
102
103
|
{sample.events && sample.events.length > 0 ? (
|
103
104
|
<TabPanel
|
105
|
+
key={kSampleTranscriptTabId}
|
104
106
|
id={kSampleTranscriptTabId}
|
105
107
|
className="sample-tab"
|
106
108
|
title="Transcript"
|
@@ -120,6 +122,7 @@ export const SampleDisplay: React.FC<SampleDisplayProps> = ({
|
|
120
122
|
</TabPanel>
|
121
123
|
) : null}
|
122
124
|
<TabPanel
|
125
|
+
key={kSampleMessagesTabId}
|
123
126
|
id={kSampleMessagesTabId}
|
124
127
|
className={clsx("sample-tab", styles.fullWidth)}
|
125
128
|
title="Messages"
|
@@ -138,6 +141,7 @@ export const SampleDisplay: React.FC<SampleDisplayProps> = ({
|
|
138
141
|
</TabPanel>
|
139
142
|
{scorerNames.length === 1 ? (
|
140
143
|
<TabPanel
|
144
|
+
key={kSampleScoringTabId}
|
141
145
|
id={kSampleScoringTabId}
|
142
146
|
className="sample-tab"
|
143
147
|
title="Scoring"
|
@@ -156,6 +160,7 @@ export const SampleDisplay: React.FC<SampleDisplayProps> = ({
|
|
156
160
|
const tabId = `score-${scorer}`;
|
157
161
|
return (
|
158
162
|
<TabPanel
|
163
|
+
key={tabId}
|
159
164
|
id={tabId}
|
160
165
|
className="sample-tab"
|
161
166
|
title={scorer}
|
@@ -217,11 +222,11 @@ export const SampleDisplay: React.FC<SampleDisplayProps> = ({
|
|
217
222
|
);
|
218
223
|
};
|
219
224
|
|
220
|
-
const metadataViewsForSample = (
|
225
|
+
const metadataViewsForSample = (id: string, sample: EvalSample) => {
|
221
226
|
const sampleMetadatas = [];
|
222
227
|
if (sample.model_usage && Object.keys(sample.model_usage).length > 0) {
|
223
228
|
sampleMetadatas.push(
|
224
|
-
<Card>
|
229
|
+
<Card key={`sample-usage-${id}`}>
|
225
230
|
<CardHeader label="Usage" />
|
226
231
|
<CardBody>
|
227
232
|
<ModelTokenTable
|
@@ -235,7 +240,7 @@ const metadataViewsForSample = (_id: string, sample: EvalSample) => {
|
|
235
240
|
|
236
241
|
if (Object.keys(sample?.metadata).length > 0) {
|
237
242
|
sampleMetadatas.push(
|
238
|
-
<Card>
|
243
|
+
<Card key={`sample-metadata-${id}`}>
|
239
244
|
<CardHeader label="Metadata" />
|
240
245
|
<CardBody>
|
241
246
|
<MetaDataView
|
@@ -250,7 +255,7 @@ const metadataViewsForSample = (_id: string, sample: EvalSample) => {
|
|
250
255
|
|
251
256
|
if (Object.keys(sample?.store).length > 0) {
|
252
257
|
sampleMetadatas.push(
|
253
|
-
<Card>
|
258
|
+
<Card key={`sample-store-${id}`}>
|
254
259
|
<CardHeader label="Store" />
|
255
260
|
<CardBody>
|
256
261
|
<MetaDataView
|
@@ -143,9 +143,10 @@ export const SampleSummaryView: React.FC<SampleSummaryViewProps> = ({
|
|
143
143
|
.join(" ")}`,
|
144
144
|
}}
|
145
145
|
>
|
146
|
-
{columns.map((col) => {
|
146
|
+
{columns.map((col, idx) => {
|
147
147
|
return (
|
148
148
|
<div
|
149
|
+
key={`sample-summ-lbl-${idx}`}
|
149
150
|
className={clsx(
|
150
151
|
"text-style-label",
|
151
152
|
"text-style-secondary",
|
@@ -157,9 +158,10 @@ export const SampleSummaryView: React.FC<SampleSummaryViewProps> = ({
|
|
157
158
|
</div>
|
158
159
|
);
|
159
160
|
})}
|
160
|
-
{columns.map((col) => {
|
161
|
+
{columns.map((col, idx) => {
|
161
162
|
return (
|
162
163
|
<div
|
164
|
+
key={`sample-summ-val-${idx}`}
|
163
165
|
className={clsx(
|
164
166
|
styles.wrap,
|
165
167
|
col.clamp ? "three-line-clamp" : undefined,
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import { Fragment } from "react/jsx-runtime";
|
1
2
|
import { ScoreFilter, ScoreLabel } from "../types";
|
2
3
|
import { SamplesDescriptor } from "./descriptor/samplesDescriptor";
|
3
4
|
import { EpochFilter } from "./sample-tools/EpochFilter";
|
@@ -32,29 +33,20 @@ export const SampleTools: React.FC<SampleToolsProps> = ({
|
|
32
33
|
scores,
|
33
34
|
sampleDescriptor,
|
34
35
|
}) => {
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
36
|
+
return (
|
37
|
+
<Fragment>
|
38
|
+
<SampleFilter
|
39
|
+
evalDescriptor={sampleDescriptor.evalDescriptor}
|
40
|
+
scoreFilter={scoreFilter}
|
41
|
+
setScoreFilter={setScoreFilter}
|
42
|
+
/>
|
43
|
+
{scores.length > 1 ? (
|
44
|
+
<SelectScorer scores={scores} score={score} setScore={setScore} />
|
45
|
+
) : undefined}
|
46
|
+
{epochs > 1 ? (
|
47
|
+
<EpochFilter epoch={epoch} setEpoch={setEpoch} epochs={epochs} />
|
48
|
+
) : undefined}
|
49
|
+
<SortFilter sort={sort} setSort={setSort} epochs={epochs} />
|
50
|
+
</Fragment>
|
43
51
|
);
|
44
|
-
|
45
|
-
if (scores.length > 1) {
|
46
|
-
tools.push(
|
47
|
-
<SelectScorer scores={scores} score={score} setScore={setScore} />,
|
48
|
-
);
|
49
|
-
}
|
50
|
-
|
51
|
-
if (epochs > 1) {
|
52
|
-
tools.push(
|
53
|
-
<EpochFilter epoch={epoch} setEpoch={setEpoch} epochs={epochs} />,
|
54
|
-
);
|
55
|
-
}
|
56
|
-
|
57
|
-
tools.push(<SortFilter sort={sort} setSort={setSort} epochs={epochs} />);
|
58
|
-
|
59
|
-
return tools;
|
60
52
|
};
|
@@ -42,7 +42,7 @@ export const ChatMessage: React.FC<ChatMessageProps> = ({
|
|
42
42
|
{message.role}
|
43
43
|
</div>
|
44
44
|
{message.role === "assistant" && message.reasoning ? (
|
45
|
-
<Fragment>
|
45
|
+
<Fragment key={`${id}-response-label`}>
|
46
46
|
<div className={clsx("text-style-label", "text-style-secondary")}>
|
47
47
|
Reasoning
|
48
48
|
</div>
|
@@ -42,6 +42,7 @@ export const MessageContent: React.FC<MessageContentProps> = ({ contents }) => {
|
|
42
42
|
return contents.map((content, index) => {
|
43
43
|
if (typeof content === "string") {
|
44
44
|
return messageRenderers["text"].render(
|
45
|
+
`text-content-${index}`,
|
45
46
|
{
|
46
47
|
type: "text",
|
47
48
|
text: content,
|
@@ -52,7 +53,11 @@ export const MessageContent: React.FC<MessageContentProps> = ({ contents }) => {
|
|
52
53
|
if (content) {
|
53
54
|
const renderer = messageRenderers[content.type];
|
54
55
|
if (renderer) {
|
55
|
-
return renderer.render(
|
56
|
+
return renderer.render(
|
57
|
+
`text-${content.type}-${index}`,
|
58
|
+
content,
|
59
|
+
index === contents.length - 1,
|
60
|
+
);
|
56
61
|
} else {
|
57
62
|
console.error(`Unknown message content type '${content.type}'`);
|
58
63
|
}
|
@@ -65,20 +70,29 @@ export const MessageContent: React.FC<MessageContentProps> = ({ contents }) => {
|
|
65
70
|
type: "text",
|
66
71
|
text: contents,
|
67
72
|
};
|
68
|
-
return messageRenderers["text"].render(
|
73
|
+
return messageRenderers["text"].render(
|
74
|
+
"text-message-content",
|
75
|
+
contentText,
|
76
|
+
true,
|
77
|
+
);
|
69
78
|
}
|
70
79
|
};
|
71
80
|
|
72
81
|
interface MessageRenderer {
|
73
|
-
render: (
|
82
|
+
render: (
|
83
|
+
key: string,
|
84
|
+
content: ContentType,
|
85
|
+
isLast: boolean,
|
86
|
+
) => React.ReactNode;
|
74
87
|
}
|
75
88
|
|
76
89
|
const messageRenderers: Record<string, MessageRenderer> = {
|
77
90
|
text: {
|
78
|
-
render: (content, isLast) => {
|
91
|
+
render: (key, content, isLast) => {
|
79
92
|
const c = content as ContentText;
|
80
93
|
return (
|
81
94
|
<MarkdownDiv
|
95
|
+
key={key}
|
82
96
|
markdown={c.text}
|
83
97
|
className={isLast ? "no-last-para-padding" : ""}
|
84
98
|
/>
|
@@ -86,39 +100,39 @@ const messageRenderers: Record<string, MessageRenderer> = {
|
|
86
100
|
},
|
87
101
|
},
|
88
102
|
image: {
|
89
|
-
render: (content) => {
|
103
|
+
render: (key, content) => {
|
90
104
|
const c = content as ContentImage;
|
91
105
|
if (c.image.startsWith("data:")) {
|
92
|
-
return <img src={c.image} className={styles.contentImage} />;
|
106
|
+
return <img src={c.image} className={styles.contentImage} key={key} />;
|
93
107
|
} else {
|
94
|
-
return <code>{c.image}</code>;
|
108
|
+
return <code key={key}>{c.image}</code>;
|
95
109
|
}
|
96
110
|
},
|
97
111
|
},
|
98
112
|
audio: {
|
99
|
-
render: (content) => {
|
113
|
+
render: (key, content) => {
|
100
114
|
const c = content as ContentAudio;
|
101
115
|
return (
|
102
|
-
<audio controls>
|
116
|
+
<audio controls key={key}>
|
103
117
|
<source src={c.audio} type={mimeTypeForFormat(c.format)} />
|
104
118
|
</audio>
|
105
119
|
);
|
106
120
|
},
|
107
121
|
},
|
108
122
|
video: {
|
109
|
-
render: (content) => {
|
123
|
+
render: (key, content) => {
|
110
124
|
const c = content as ContentVideo;
|
111
125
|
return (
|
112
|
-
<video width="500" height="375" controls>
|
126
|
+
<video width="500" height="375" controls key={key}>
|
113
127
|
<source src={c.video} type={mimeTypeForFormat(c.format)} />
|
114
128
|
</video>
|
115
129
|
);
|
116
130
|
},
|
117
131
|
},
|
118
132
|
tool: {
|
119
|
-
render: (content) => {
|
133
|
+
render: (key, content) => {
|
120
134
|
const c = content as ContentTool;
|
121
|
-
return <ToolOutput output={c.content} />;
|
135
|
+
return <ToolOutput output={c.content} key={key} />;
|
122
136
|
},
|
123
137
|
},
|
124
138
|
};
|
@@ -8,6 +8,7 @@ import { MessageContent } from "./MessageContent";
|
|
8
8
|
import { resolveToolInput } from "./tools/tool";
|
9
9
|
import { ToolCallView } from "./tools/ToolCallView";
|
10
10
|
|
11
|
+
import { Fragment } from "react";
|
11
12
|
import { ContentTool } from "../../types";
|
12
13
|
import styles from "./MessageContents.module.css";
|
13
14
|
|
@@ -27,20 +28,10 @@ export const MessageContents: React.FC<MessageContentsProps> = ({
|
|
27
28
|
message.tool_calls &&
|
28
29
|
message.tool_calls.length
|
29
30
|
) {
|
30
|
-
const result = [];
|
31
|
-
// If the message contains content, render that.
|
32
|
-
if (message.content) {
|
33
|
-
result.push(
|
34
|
-
<div className={styles.content}>
|
35
|
-
<MessageContent contents={message.content} />
|
36
|
-
</div>,
|
37
|
-
);
|
38
|
-
}
|
39
|
-
|
40
31
|
// Render the tool calls made by this message
|
41
32
|
const toolCalls = message.tool_calls.map((tool_call, idx) => {
|
42
33
|
// Extract tool input
|
43
|
-
const { input, functionCall,
|
34
|
+
const { input, functionCall, highlightLanguage } = resolveToolInput(
|
44
35
|
tool_call.function,
|
45
36
|
tool_call.arguments,
|
46
37
|
);
|
@@ -57,23 +48,34 @@ export const MessageContents: React.FC<MessageContentsProps> = ({
|
|
57
48
|
// Resolve the tool output
|
58
49
|
const resolvedToolOutput = resolveToolMessage(toolMessage);
|
59
50
|
if (toolCallStyle === "compact") {
|
60
|
-
return
|
51
|
+
return (
|
52
|
+
<div key={`tool-call-${idx}`}>
|
53
|
+
<code>tool: {functionCall}</code>
|
54
|
+
</div>
|
55
|
+
);
|
61
56
|
} else {
|
62
57
|
return (
|
63
58
|
<ToolCallView
|
59
|
+
key={`tool-call-${idx}`}
|
64
60
|
functionCall={functionCall}
|
65
61
|
input={input}
|
66
|
-
|
62
|
+
highlightLanguage={highlightLanguage}
|
67
63
|
output={resolvedToolOutput}
|
68
64
|
/>
|
69
65
|
);
|
70
66
|
}
|
71
67
|
});
|
72
68
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
69
|
+
return (
|
70
|
+
<Fragment>
|
71
|
+
<div className={styles.content}>
|
72
|
+
{message.content ? (
|
73
|
+
<MessageContent contents={message.content} />
|
74
|
+
) : undefined}
|
75
|
+
</div>
|
76
|
+
{toolCalls}
|
77
|
+
</Fragment>
|
78
|
+
);
|
77
79
|
} else {
|
78
80
|
return <MessageContent contents={message.content} />;
|
79
81
|
}
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import { useMemo } from "react";
|
1
2
|
import ExpandablePanel from "../../../components/ExpandablePanel";
|
2
3
|
import { ContentTool } from "../../../types";
|
3
4
|
import {
|
@@ -14,7 +15,7 @@ import { ToolTitle } from "./ToolTitle";
|
|
14
15
|
interface ToolCallViewProps {
|
15
16
|
functionCall: string;
|
16
17
|
input?: string;
|
17
|
-
|
18
|
+
highlightLanguage?: string;
|
18
19
|
view?: ToolCallContent;
|
19
20
|
output:
|
20
21
|
| string
|
@@ -41,7 +42,7 @@ interface ToolCallViewProps {
|
|
41
42
|
export const ToolCallView: React.FC<ToolCallViewProps> = ({
|
42
43
|
functionCall,
|
43
44
|
input,
|
44
|
-
|
45
|
+
highlightLanguage,
|
45
46
|
view,
|
46
47
|
output,
|
47
48
|
mode,
|
@@ -76,6 +77,7 @@ export const ToolCallView: React.FC<ToolCallViewProps> = ({
|
|
76
77
|
const collapse = Array.isArray(output)
|
77
78
|
? output.every((item) => !isContentImage(item))
|
78
79
|
: !isContentImage(output);
|
80
|
+
const normalizedContent = useMemo(() => normalizeContent(output), [output]);
|
79
81
|
|
80
82
|
return (
|
81
83
|
<div>
|
@@ -86,14 +88,14 @@ export const ToolCallView: React.FC<ToolCallViewProps> = ({
|
|
86
88
|
)}
|
87
89
|
<div>
|
88
90
|
<div>
|
89
|
-
<ToolInput
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
91
|
+
<ToolInput
|
92
|
+
highlightLanguage={highlightLanguage}
|
93
|
+
contents={input}
|
94
|
+
toolCallView={view}
|
95
|
+
/>
|
96
|
+
<ExpandablePanel collapse={collapse} border={true} lines={15}>
|
97
|
+
<MessageContent contents={normalizedContent} />
|
98
|
+
</ExpandablePanel>
|
97
99
|
</div>
|
98
100
|
</div>
|
99
101
|
</div>
|
@@ -1,86 +1,76 @@
|
|
1
1
|
import clsx from "clsx";
|
2
|
-
import
|
3
|
-
import {
|
4
|
-
import { useEffect, useRef } from "react";
|
2
|
+
import { highlightElement } from "prismjs";
|
3
|
+
import { memo, useEffect, useRef } from "react";
|
5
4
|
import { MarkdownDiv } from "../../../components/MarkdownDiv";
|
6
|
-
|
5
|
+
|
7
6
|
import styles from "./ToolInput.module.css";
|
8
7
|
|
8
|
+
export const useCodeHighlight = (language?: string) => {
|
9
|
+
const codeRef = useRef<HTMLElement>(null);
|
10
|
+
|
11
|
+
useEffect(() => {
|
12
|
+
if (codeRef.current && language) {
|
13
|
+
highlightElement(codeRef.current);
|
14
|
+
}
|
15
|
+
}, [language]);
|
16
|
+
|
17
|
+
return codeRef;
|
18
|
+
};
|
19
|
+
|
9
20
|
interface ToolInputProps {
|
10
|
-
|
11
|
-
contents?: string;
|
12
|
-
|
21
|
+
highlightLanguage?: string;
|
22
|
+
contents?: string | object;
|
23
|
+
toolCallView?: { content: string };
|
13
24
|
}
|
25
|
+
export const ToolInput: React.FC<ToolInputProps> = memo((props) => {
|
26
|
+
const { highlightLanguage, contents, toolCallView } = props;
|
14
27
|
|
15
|
-
|
16
|
-
* Renders the ToolInput component.
|
17
|
-
*/
|
18
|
-
export const ToolInput: React.FC<ToolInputProps> = ({
|
19
|
-
type,
|
20
|
-
contents,
|
21
|
-
view,
|
22
|
-
}) => {
|
23
|
-
if (!contents && !view?.content) {
|
24
|
-
return null;
|
25
|
-
}
|
28
|
+
const codeRef = useCodeHighlight(highlightLanguage);
|
26
29
|
|
27
|
-
if (
|
30
|
+
if (!contents && !toolCallView?.content) return null;
|
31
|
+
|
32
|
+
if (toolCallView) {
|
28
33
|
const toolViewRef = useRef<HTMLDivElement>(null);
|
34
|
+
|
29
35
|
useEffect(() => {
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
(className) => className.startsWith("language-"),
|
38
|
-
);
|
39
|
-
if (hasLanguageClass) {
|
40
|
-
child.classList.add("tool-output");
|
41
|
-
highlightElement(childChild as HTMLElement);
|
42
|
-
}
|
36
|
+
if (toolCallView?.content && toolViewRef.current) {
|
37
|
+
requestAnimationFrame(() => {
|
38
|
+
const codeBlocks = toolViewRef.current!.querySelectorAll("pre code");
|
39
|
+
codeBlocks.forEach((block) => {
|
40
|
+
if (block.className.includes("language-")) {
|
41
|
+
block.classList.add("sourceCode");
|
42
|
+
highlightElement(block as HTMLElement);
|
43
43
|
}
|
44
|
-
}
|
45
|
-
}
|
44
|
+
});
|
45
|
+
});
|
46
46
|
}
|
47
|
-
}, [
|
47
|
+
}, [toolCallView?.content]);
|
48
|
+
|
48
49
|
return (
|
49
50
|
<MarkdownDiv
|
50
|
-
markdown={
|
51
|
+
markdown={toolCallView.content}
|
51
52
|
ref={toolViewRef}
|
52
|
-
className={clsx(styles.bottomMargin)}
|
53
|
+
className={clsx(styles.bottomMargin, "text-size-small")}
|
53
54
|
/>
|
54
55
|
);
|
55
|
-
}
|
56
|
-
const toolInputRef = useRef(null);
|
57
|
-
useEffect(() => {
|
58
|
-
if (type) {
|
59
|
-
const tokens = languages[type];
|
60
|
-
if (toolInputRef.current && tokens) {
|
61
|
-
highlightElement(toolInputRef.current);
|
62
|
-
}
|
63
|
-
}
|
64
|
-
}, [contents, type, view]);
|
56
|
+
}
|
65
57
|
|
66
|
-
|
67
|
-
|
68
|
-
? JSON.stringify(contents)
|
69
|
-
: contents;
|
70
|
-
const key = murmurhash.v3(contents || "");
|
58
|
+
const formattedContent =
|
59
|
+
typeof contents === "object" ? JSON.stringify(contents) : contents;
|
71
60
|
|
72
|
-
|
73
|
-
|
74
|
-
|
61
|
+
return (
|
62
|
+
<pre className={clsx("tool-output", styles.outputPre, styles.bottomMargin)}>
|
63
|
+
<code
|
64
|
+
ref={codeRef}
|
65
|
+
className={clsx(
|
66
|
+
"source-code",
|
67
|
+
"sourceCode",
|
68
|
+
`language-${highlightLanguage}`,
|
69
|
+
styles.outputCode,
|
70
|
+
)}
|
75
71
|
>
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
{contents}
|
82
|
-
</code>
|
83
|
-
</pre>
|
84
|
-
);
|
85
|
-
}
|
86
|
-
};
|
72
|
+
{formattedContent}
|
73
|
+
</code>
|
74
|
+
</pre>
|
75
|
+
);
|
76
|
+
});
|
@@ -18,21 +18,28 @@ export const ToolOutput: React.FC<ToolOutputProps> = ({ output }) => {
|
|
18
18
|
// First process an array or object into a string
|
19
19
|
const outputs = [];
|
20
20
|
if (Array.isArray(output)) {
|
21
|
-
output.forEach((out) => {
|
21
|
+
output.forEach((out, idx) => {
|
22
|
+
const key = `tool-output-${idx}`;
|
22
23
|
if (out.type === "text") {
|
23
|
-
outputs.push(<ToolTextOutput text={out.text} />);
|
24
|
+
outputs.push(<ToolTextOutput text={out.text} key={key} />);
|
24
25
|
} else {
|
25
26
|
if (out.image.startsWith("data:")) {
|
26
27
|
outputs.push(
|
27
|
-
<img
|
28
|
+
<img
|
29
|
+
className={clsx(styles.toolImage)}
|
30
|
+
src={out.image}
|
31
|
+
key={key}
|
32
|
+
/>,
|
28
33
|
);
|
29
34
|
} else {
|
30
|
-
outputs.push(<ToolTextOutput text={String(out.image)} />);
|
35
|
+
outputs.push(<ToolTextOutput text={String(out.image)} key={key} />);
|
31
36
|
}
|
32
37
|
}
|
33
38
|
});
|
34
39
|
} else {
|
35
|
-
outputs.push(
|
40
|
+
outputs.push(
|
41
|
+
<ToolTextOutput text={String(output)} key={"tool-output-single"} />,
|
42
|
+
);
|
36
43
|
}
|
37
44
|
return <div className={clsx(styles.output)}>{outputs}</div>;
|
38
45
|
};
|