inspect-ai 0.3.93__py3-none-any.whl → 0.3.95__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.
Files changed (115) hide show
  1. inspect_ai/_display/textual/widgets/samples.py +3 -3
  2. inspect_ai/_display/textual/widgets/transcript.py +3 -29
  3. inspect_ai/_eval/loader.py +1 -1
  4. inspect_ai/_eval/task/run.py +21 -12
  5. inspect_ai/_util/answer.py +26 -0
  6. inspect_ai/_util/constants.py +0 -1
  7. inspect_ai/_util/exception.py +4 -0
  8. inspect_ai/_util/hash.py +39 -0
  9. inspect_ai/_util/local_server.py +51 -21
  10. inspect_ai/_util/path.py +22 -0
  11. inspect_ai/_util/trace.py +1 -1
  12. inspect_ai/_util/working.py +4 -0
  13. inspect_ai/_view/www/dist/assets/index.css +23 -22
  14. inspect_ai/_view/www/dist/assets/index.js +517 -204
  15. inspect_ai/_view/www/log-schema.json +375 -0
  16. inspect_ai/_view/www/package.json +1 -1
  17. inspect_ai/_view/www/src/@types/log.d.ts +90 -12
  18. inspect_ai/_view/www/src/app/log-view/navbar/SecondaryBar.tsx +2 -2
  19. inspect_ai/_view/www/src/app/log-view/tabs/SamplesTab.tsx +1 -4
  20. inspect_ai/_view/www/src/app/samples/SamplesTools.tsx +3 -13
  21. inspect_ai/_view/www/src/app/samples/sample-tools/SelectScorer.tsx +45 -48
  22. inspect_ai/_view/www/src/app/samples/sample-tools/filters.ts +16 -15
  23. inspect_ai/_view/www/src/app/samples/sample-tools/sample-filter/SampleFilter.tsx +47 -75
  24. inspect_ai/_view/www/src/app/samples/sample-tools/sample-filter/completions.ts +9 -9
  25. inspect_ai/_view/www/src/app/samples/transcript/SandboxEventView.module.css +2 -1
  26. inspect_ai/_view/www/src/app/samples/transcript/SpanEventView.tsx +174 -0
  27. inspect_ai/_view/www/src/app/samples/transcript/ToolEventView.tsx +8 -8
  28. inspect_ai/_view/www/src/app/samples/transcript/TranscriptView.tsx +12 -2
  29. inspect_ai/_view/www/src/app/samples/transcript/TranscriptVirtualListComponent.module.css +1 -1
  30. inspect_ai/_view/www/src/app/samples/transcript/event/EventPanel.tsx +0 -3
  31. inspect_ai/_view/www/src/app/samples/transcript/transform/fixups.ts +87 -25
  32. inspect_ai/_view/www/src/app/samples/transcript/transform/treeify.ts +229 -17
  33. inspect_ai/_view/www/src/app/samples/transcript/transform/utils.ts +11 -0
  34. inspect_ai/_view/www/src/app/samples/transcript/types.ts +5 -1
  35. inspect_ai/_view/www/src/app/types.ts +12 -2
  36. inspect_ai/_view/www/src/components/ExpandablePanel.module.css +1 -1
  37. inspect_ai/_view/www/src/components/ExpandablePanel.tsx +5 -5
  38. inspect_ai/_view/www/src/state/hooks.ts +19 -3
  39. inspect_ai/_view/www/src/state/logSlice.ts +23 -5
  40. inspect_ai/_view/www/yarn.lock +9 -9
  41. inspect_ai/agent/_as_solver.py +3 -1
  42. inspect_ai/agent/_as_tool.py +6 -4
  43. inspect_ai/agent/_bridge/patch.py +1 -3
  44. inspect_ai/agent/_handoff.py +5 -1
  45. inspect_ai/agent/_react.py +4 -3
  46. inspect_ai/agent/_run.py +6 -1
  47. inspect_ai/agent/_types.py +9 -0
  48. inspect_ai/analysis/__init__.py +0 -0
  49. inspect_ai/analysis/beta/__init__.py +57 -0
  50. inspect_ai/analysis/beta/_dataframe/__init__.py +0 -0
  51. inspect_ai/analysis/beta/_dataframe/columns.py +145 -0
  52. inspect_ai/analysis/beta/_dataframe/evals/__init__.py +0 -0
  53. inspect_ai/analysis/beta/_dataframe/evals/columns.py +132 -0
  54. inspect_ai/analysis/beta/_dataframe/evals/extract.py +23 -0
  55. inspect_ai/analysis/beta/_dataframe/evals/table.py +140 -0
  56. inspect_ai/analysis/beta/_dataframe/events/__init__.py +0 -0
  57. inspect_ai/analysis/beta/_dataframe/events/columns.py +37 -0
  58. inspect_ai/analysis/beta/_dataframe/events/table.py +14 -0
  59. inspect_ai/analysis/beta/_dataframe/extract.py +54 -0
  60. inspect_ai/analysis/beta/_dataframe/messages/__init__.py +0 -0
  61. inspect_ai/analysis/beta/_dataframe/messages/columns.py +60 -0
  62. inspect_ai/analysis/beta/_dataframe/messages/extract.py +21 -0
  63. inspect_ai/analysis/beta/_dataframe/messages/table.py +87 -0
  64. inspect_ai/analysis/beta/_dataframe/record.py +377 -0
  65. inspect_ai/analysis/beta/_dataframe/samples/__init__.py +0 -0
  66. inspect_ai/analysis/beta/_dataframe/samples/columns.py +73 -0
  67. inspect_ai/analysis/beta/_dataframe/samples/extract.py +82 -0
  68. inspect_ai/analysis/beta/_dataframe/samples/table.py +329 -0
  69. inspect_ai/analysis/beta/_dataframe/util.py +157 -0
  70. inspect_ai/analysis/beta/_dataframe/validate.py +171 -0
  71. inspect_ai/dataset/_dataset.py +6 -3
  72. inspect_ai/log/__init__.py +10 -0
  73. inspect_ai/log/_convert.py +4 -9
  74. inspect_ai/log/_file.py +1 -1
  75. inspect_ai/log/_log.py +21 -1
  76. inspect_ai/log/_samples.py +14 -17
  77. inspect_ai/log/_transcript.py +77 -35
  78. inspect_ai/log/_tree.py +118 -0
  79. inspect_ai/model/_call_tools.py +44 -35
  80. inspect_ai/model/_model.py +51 -44
  81. inspect_ai/model/_openai_responses.py +17 -18
  82. inspect_ai/model/_providers/anthropic.py +30 -5
  83. inspect_ai/model/_providers/hf.py +27 -1
  84. inspect_ai/model/_providers/providers.py +1 -1
  85. inspect_ai/model/_providers/sglang.py +8 -2
  86. inspect_ai/model/_providers/vllm.py +6 -2
  87. inspect_ai/scorer/_choice.py +1 -2
  88. inspect_ai/solver/_chain.py +1 -1
  89. inspect_ai/solver/_fork.py +1 -1
  90. inspect_ai/solver/_multiple_choice.py +9 -23
  91. inspect_ai/solver/_plan.py +2 -2
  92. inspect_ai/solver/_task_state.py +7 -3
  93. inspect_ai/solver/_transcript.py +6 -7
  94. inspect_ai/tool/_mcp/_context.py +3 -5
  95. inspect_ai/tool/_mcp/_mcp.py +6 -5
  96. inspect_ai/tool/_mcp/server.py +1 -1
  97. inspect_ai/tool/_tools/_execute.py +4 -1
  98. inspect_ai/tool/_tools/_think.py +1 -1
  99. inspect_ai/tool/_tools/_web_search/__init__.py +3 -0
  100. inspect_ai/tool/_tools/{_web_search.py → _web_search/_google.py} +56 -103
  101. inspect_ai/tool/_tools/_web_search/_tavily.py +77 -0
  102. inspect_ai/tool/_tools/_web_search/_web_search.py +85 -0
  103. inspect_ai/util/__init__.py +4 -0
  104. inspect_ai/util/_anyio.py +11 -0
  105. inspect_ai/util/_collect.py +50 -0
  106. inspect_ai/util/_sandbox/events.py +3 -2
  107. inspect_ai/util/_span.py +58 -0
  108. inspect_ai/util/_subtask.py +27 -42
  109. {inspect_ai-0.3.93.dist-info → inspect_ai-0.3.95.dist-info}/METADATA +8 -1
  110. {inspect_ai-0.3.93.dist-info → inspect_ai-0.3.95.dist-info}/RECORD +114 -82
  111. {inspect_ai-0.3.93.dist-info → inspect_ai-0.3.95.dist-info}/WHEEL +1 -1
  112. inspect_ai/_display/core/group.py +0 -79
  113. {inspect_ai-0.3.93.dist-info → inspect_ai-0.3.95.dist-info}/entry_points.txt +0 -0
  114. {inspect_ai-0.3.93.dist-info → inspect_ai-0.3.95.dist-info}/licenses/LICENSE +0 -0
  115. {inspect_ai-0.3.93.dist-info → inspect_ai-0.3.95.dist-info}/top_level.txt +0 -0
@@ -14,28 +14,18 @@ import {
14
14
  import { tags } from "@lezer/highlight";
15
15
  import clsx from "clsx";
16
16
  import { EditorView, minimalSetup } from "codemirror";
17
- import { FC, useEffect, useMemo, useRef, useState } from "react";
17
+ import { FC, useCallback, useEffect, useMemo, useRef } from "react";
18
18
 
19
- import { ScoreFilter } from "../../../../app/types";
20
- import { SampleSummary } from "../../../../client/api/types";
21
19
  import { useEvalDescriptor } from "../../../../state/hooks";
22
- import { EvalDescriptor } from "../../descriptor/types";
23
- import { FilterError, filterSamples, scoreFilterItems } from "../filters";
20
+ import { useStore } from "../../../../state/store";
21
+ import { debounce } from "../../../../utils/sync";
22
+ import { FilterError } from "../../../types";
23
+ import { sampleFilterItems } from "../filters";
24
24
  import { getCompletions } from "./completions";
25
25
  import styles from "./SampleFilter.module.css";
26
26
  import { language } from "./tokenize";
27
27
 
28
- // Types
29
- interface FilteringResult {
30
- numSamples: number;
31
- error?: FilterError;
32
- }
33
-
34
- interface SampleFilterProps {
35
- samples: SampleSummary[];
36
- scoreFilter: ScoreFilter;
37
- setScoreFilter: (filter: ScoreFilter) => void;
38
- }
28
+ interface SampleFilterProps {}
39
29
 
40
30
  // Constants
41
31
  const FILTER_TOOLTIP = `
@@ -105,20 +95,6 @@ const editorTheme = EditorView.theme({
105
95
  },
106
96
  });
107
97
 
108
- // Helper functions
109
- const getFilteringResult = (
110
- evalDescriptor: EvalDescriptor,
111
- sampleSummaries: SampleSummary[],
112
- filterValue: string,
113
- ): FilteringResult => {
114
- const { result, error } = filterSamples(
115
- evalDescriptor,
116
- sampleSummaries,
117
- filterValue,
118
- );
119
- return { numSamples: result.length, error };
120
- };
121
-
122
98
  const ensureOneLine = (tr: Transaction): TransactionSpec => {
123
99
  const newDoc = tr.newDoc.toString();
124
100
  if (!newDoc.includes("\n")) return tr;
@@ -154,11 +130,7 @@ const getLints = (
154
130
  };
155
131
 
156
132
  // Main component
157
- export const SampleFilter: FC<SampleFilterProps> = ({
158
- samples,
159
- scoreFilter,
160
- setScoreFilter,
161
- }) => {
133
+ export const SampleFilter: FC<SampleFilterProps> = () => {
162
134
  const editorRef = useRef<HTMLDivElement>(null);
163
135
  const editorViewRef = useRef<EditorView>(null);
164
136
  const linterCompartment = useRef<Compartment>(new Compartment());
@@ -167,43 +139,51 @@ export const SampleFilter: FC<SampleFilterProps> = ({
167
139
  const evalDescriptor = useEvalDescriptor();
168
140
 
169
141
  const filterItems = useMemo(
170
- () => (evalDescriptor ? scoreFilterItems(evalDescriptor) : []),
142
+ () => (evalDescriptor ? sampleFilterItems(evalDescriptor) : []),
171
143
  [evalDescriptor],
172
144
  );
173
145
 
174
- const [filteringResultInstant, setFilteringResultInstant] =
175
- useState<FilteringResult | null>(null);
146
+ const filter = useStore((state) => state.log.filter);
147
+ const filterError = useStore((state) => state.log.filterError);
148
+ const setFilter = useStore((state) => state.logActions.setFilter);
176
149
 
177
- const handleFocus = (event: FocusEvent, view: EditorView) => {
150
+ const handleFocus = useCallback((event: FocusEvent, view: EditorView) => {
178
151
  if (event.isTrusted && view.state.doc.toString() === "") {
179
152
  setTimeout(() => startCompletion(view), 0);
180
153
  }
181
- };
154
+ }, []);
182
155
 
183
- const makeAutocompletion = () =>
184
- autocompletion({
185
- override: [(context) => getCompletions(context, filterItems)],
186
- activateOnCompletion: (c) => c.label.endsWith(" "),
187
- });
156
+ const makeAutocompletion = useCallback(
157
+ () =>
158
+ autocompletion({
159
+ override: [(context) => getCompletions(context, filterItems)],
160
+ activateOnCompletion: (c) => c.label.endsWith(" "),
161
+ }),
162
+ [],
163
+ );
188
164
 
189
- const makeLinter = () =>
190
- linter((view) => getLints(view, filteringResultInstant?.error));
165
+ const makeLinter = useCallback(
166
+ () => linter((view) => getLints(view, filterError)),
167
+ [filterError],
168
+ );
191
169
 
192
- const makeUpdateListener = () =>
193
- EditorView.updateListener.of((update) => {
194
- if (update.docChanged && evalDescriptor) {
195
- const newValue = update.state.doc.toString();
196
- const filteringResult = getFilteringResult(
197
- evalDescriptor,
198
- samples,
199
- newValue,
200
- );
201
- if (!filteringResult.error) {
202
- setScoreFilter({ value: newValue });
170
+ const debounceSetFilter = useCallback(
171
+ debounce((value: string) => {
172
+ setFilter(value);
173
+ }, 200),
174
+ [setFilter],
175
+ );
176
+
177
+ const makeUpdateListener = useCallback(
178
+ () =>
179
+ EditorView.updateListener.of((update) => {
180
+ if (update.docChanged && evalDescriptor) {
181
+ const newValue = update.state.doc.toString();
182
+ debounceSetFilter(newValue);
203
183
  }
204
- setFilteringResultInstant(filteringResult);
205
- }
206
- });
184
+ }),
185
+ [setFilter],
186
+ );
207
187
 
208
188
  // Initialize editor
209
189
  useEffect(() => {
@@ -212,7 +192,7 @@ export const SampleFilter: FC<SampleFilterProps> = ({
212
192
  editorViewRef.current = new EditorView({
213
193
  parent: editorRef.current ?? undefined,
214
194
  state: EditorState.create({
215
- doc: scoreFilter.value || "",
195
+ doc: filter || "",
216
196
  extensions: [
217
197
  minimalSetup,
218
198
  bracketMatching(),
@@ -236,21 +216,16 @@ export const SampleFilter: FC<SampleFilterProps> = ({
236
216
  if (!editorViewRef.current) return;
237
217
 
238
218
  const currentValue = editorViewRef.current.state.doc.toString();
239
- if (scoreFilter.value === currentValue) return;
219
+ if (filter === currentValue) return;
240
220
 
241
- if (evalDescriptor) {
242
- setFilteringResultInstant(
243
- getFilteringResult(evalDescriptor, samples, scoreFilter.value || ""),
244
- );
245
- }
246
221
  editorViewRef.current.dispatch({
247
222
  changes: {
248
223
  from: 0,
249
224
  to: currentValue.length,
250
- insert: scoreFilter.value || "",
225
+ insert: filter || "",
251
226
  },
252
227
  });
253
- }, [evalDescriptor, scoreFilter.value]);
228
+ }, [filter]);
254
229
 
255
230
  // Update compartments when dependencies change
256
231
  useEffect(() => {
@@ -271,7 +246,7 @@ export const SampleFilter: FC<SampleFilterProps> = ({
271
246
  editorViewRef.current?.dispatch({
272
247
  effects: linterCompartment.current.reconfigure(makeLinter()),
273
248
  });
274
- }, [filteringResultInstant?.error]);
249
+ }, [filterError]);
275
250
 
276
251
  return (
277
252
  <div style={{ display: "flex" }}>
@@ -288,10 +263,7 @@ export const SampleFilter: FC<SampleFilterProps> = ({
288
263
  </span>
289
264
  <div
290
265
  ref={editorRef}
291
- className={clsx(
292
- filteringResultInstant?.error && "filter-pending",
293
- styles.input,
294
- )}
266
+ className={clsx(filterError && "filter-pending", styles.input)}
295
267
  />
296
268
  <span
297
269
  className={clsx("bi", "bi-question-circle", styles.help)}
@@ -12,7 +12,7 @@ import {
12
12
  kScoreTypeOther,
13
13
  kScoreTypePassFail,
14
14
  } from "../../../../constants";
15
- import { ScoreFilterItem } from "../filters";
15
+ import { SampleFilterItem } from "../filters";
16
16
  import {
17
17
  KEYWORDS,
18
18
  MATH_FUNCTIONS,
@@ -29,7 +29,7 @@ interface CompletionOptions {
29
29
  }
30
30
 
31
31
  interface CanonicalNameCompletionProps {
32
- autoSpaceIf?: (item: ScoreFilterItem) => boolean;
32
+ autoSpaceIf?: (item: SampleFilterItem) => boolean;
33
33
  }
34
34
 
35
35
  const isLiteral = (token: Token): boolean =>
@@ -98,7 +98,7 @@ const makeLiteralCompletion = (k: string): Completion => ({
98
98
  });
99
99
 
100
100
  const makeCanonicalNameCompletion = (
101
- item: ScoreFilterItem,
101
+ item: SampleFilterItem,
102
102
  { autoSpaceIf = () => false }: CanonicalNameCompletionProps = {},
103
103
  ): Completion => ({
104
104
  label: item.canonicalName + (autoSpaceIf(item) ? " " : ""),
@@ -107,7 +107,7 @@ const makeCanonicalNameCompletion = (
107
107
  boost: 30,
108
108
  });
109
109
 
110
- const makeMemberAccessCompletion = (item: ScoreFilterItem): Completion => ({
110
+ const makeMemberAccessCompletion = (item: SampleFilterItem): Completion => ({
111
111
  label: item.qualifiedName?.split(".")[1] || "",
112
112
  type: "variable",
113
113
  info: item.tooltip,
@@ -115,9 +115,9 @@ const makeMemberAccessCompletion = (item: ScoreFilterItem): Completion => ({
115
115
  });
116
116
 
117
117
  const getMemberScoreItems = (
118
- filterItems: ScoreFilterItem[],
118
+ filterItems: SampleFilterItem[],
119
119
  scorer: string,
120
- ): ScoreFilterItem[] =>
120
+ ): SampleFilterItem[] =>
121
121
  filterItems.filter((item) => item?.qualifiedName?.startsWith(`${scorer}.`));
122
122
 
123
123
  /**
@@ -136,7 +136,7 @@ const getMemberScoreItems = (
136
136
  */
137
137
  export function getCompletions(
138
138
  context: CompletionContext,
139
- filterItems: ScoreFilterItem[],
139
+ filterItems: SampleFilterItem[],
140
140
  ): CompletionResult | null {
141
141
  const keywordCompletionItems = KEYWORDS.map(makeKeywordCompletion);
142
142
  const mathFunctionCompletionItems = MATH_FUNCTIONS.map(
@@ -177,7 +177,7 @@ export function getCompletions(
177
177
  const completionStart = currentToken ? currentToken.from : context.pos;
178
178
  const completingAtEnd = context.pos === doc.length;
179
179
 
180
- const findFilterItem = (endIndex: number): ScoreFilterItem | undefined => {
180
+ const findFilterItem = (endIndex: number): SampleFilterItem | undefined => {
181
181
  if (prevToken(endIndex)?.type !== "variable") return undefined;
182
182
 
183
183
  let name = prevToken(endIndex).text;
@@ -267,7 +267,7 @@ export function getCompletions(
267
267
 
268
268
  const variableCompletions = () => makeCompletions(variableCompletionItems);
269
269
 
270
- const memberAccessCompletions = (items: ScoreFilterItem[]) =>
270
+ const memberAccessCompletions = (items: SampleFilterItem[]) =>
271
271
  makeCompletions(items.map(makeMemberAccessCompletion), {
272
272
  autocompleteInTheMiddle: true,
273
273
  includeDefault: false,
@@ -13,7 +13,7 @@
13
13
  }
14
14
 
15
15
  .exec {
16
- margin-top: 0.5em;
16
+ margin-top: 0;
17
17
  }
18
18
 
19
19
  .result {
@@ -29,4 +29,5 @@
29
29
  white-space: pre-wrap;
30
30
  word-wrap: break-word;
31
31
  overflow-wrap: break-word;
32
+ margin-bottom: 0;
32
33
  }
@@ -0,0 +1,174 @@
1
+ import clsx from "clsx";
2
+ import { FC } from "react";
3
+ import { SpanBeginEvent } from "../../../@types/log";
4
+ import { formatDateTime } from "../../../utils/format";
5
+ import { EventPanel } from "./event/EventPanel";
6
+ import { TranscriptComponent } from "./TranscriptView";
7
+ import { kSandboxSignalName } from "./transform/fixups";
8
+ import { EventNode } from "./types";
9
+
10
+ interface SpanEventViewProps {
11
+ id: string;
12
+ event: SpanBeginEvent;
13
+ children: EventNode[];
14
+ className?: string | string[];
15
+ }
16
+
17
+ /**
18
+ * Renders the SpanEventView component.
19
+ */
20
+ export const SpanEventView: FC<SpanEventViewProps> = ({
21
+ id,
22
+ event,
23
+ children,
24
+ className,
25
+ }) => {
26
+ const descriptor = spanDescriptor(event);
27
+ const title =
28
+ descriptor.name ||
29
+ `${event.type ? event.type + ": " : "Step: "}${event.name}`;
30
+ const text = summarize(children);
31
+
32
+ return (
33
+ <EventPanel
34
+ id={`span-${event.name}-${id}`}
35
+ className={clsx("transcript-span", className)}
36
+ title={title}
37
+ subTitle={formatDateTime(new Date(event.timestamp))}
38
+ text={text}
39
+ collapse={descriptor.collapse}
40
+ icon={descriptor.icon}
41
+ >
42
+ <TranscriptComponent
43
+ id={`span|${event.name}|${id}`}
44
+ eventNodes={children}
45
+ />
46
+ </EventPanel>
47
+ );
48
+ };
49
+
50
+ const summarize = (children: EventNode[]) => {
51
+ if (children.length === 0) {
52
+ return "(no events)";
53
+ }
54
+
55
+ const formatEvent = (event: string, count: number) => {
56
+ if (count === 1) {
57
+ return `${count} ${event} event`;
58
+ } else {
59
+ return `${count} ${event} events`;
60
+ }
61
+ };
62
+
63
+ // Count the types
64
+ const typeCount: Record<string, number> = {};
65
+ children.forEach((child) => {
66
+ const currentCount = typeCount[child.event.event] || 0;
67
+ typeCount[child.event.event] = currentCount + 1;
68
+ });
69
+
70
+ // Try to summarize event types
71
+ const numberOfTypes = Object.keys(typeCount).length;
72
+ if (numberOfTypes < 3) {
73
+ return Object.keys(typeCount)
74
+ .map((key) => {
75
+ return formatEvent(key, typeCount[key]);
76
+ })
77
+ .join(", ");
78
+ }
79
+
80
+ // To many types, just return the number of events
81
+ if (children.length === 1) {
82
+ return "1 event";
83
+ } else {
84
+ return `${children.length} events`;
85
+ }
86
+ };
87
+
88
+ /**
89
+ * Returns a descriptor object containing icon and style based on the event type and name.
90
+ */
91
+ const spanDescriptor = (
92
+ event: SpanBeginEvent,
93
+ ): { icon?: string; name?: string; endSpace?: boolean; collapse?: boolean } => {
94
+ const rootStepDescriptor = {
95
+ endSpace: true,
96
+ };
97
+
98
+ if (event.type === "solver") {
99
+ switch (event.name) {
100
+ case "chain_of_thought":
101
+ return {
102
+ ...rootStepDescriptor,
103
+ collapse: false,
104
+ };
105
+ case "generate":
106
+ return {
107
+ ...rootStepDescriptor,
108
+ collapse: false,
109
+ };
110
+ case "self_critique":
111
+ return {
112
+ ...rootStepDescriptor,
113
+ collapse: false,
114
+ };
115
+ case "system_message":
116
+ return {
117
+ ...rootStepDescriptor,
118
+ collapse: true,
119
+ };
120
+ case "use_tools":
121
+ return {
122
+ ...rootStepDescriptor,
123
+ collapse: false,
124
+ };
125
+ case "multiple_choice":
126
+ return {
127
+ ...rootStepDescriptor,
128
+ collapse: false,
129
+ };
130
+ default:
131
+ return {
132
+ ...rootStepDescriptor,
133
+ collapse: false,
134
+ };
135
+ }
136
+ } else if (event.type === "scorer") {
137
+ return {
138
+ ...rootStepDescriptor,
139
+ collapse: false,
140
+ };
141
+ } else if (event.event === "span_begin") {
142
+ if (event.span_id === kSandboxSignalName) {
143
+ return {
144
+ ...rootStepDescriptor,
145
+ name: "Sandbox Events",
146
+ collapse: true,
147
+ };
148
+ } else if (event.name === "init") {
149
+ return {
150
+ ...rootStepDescriptor,
151
+ name: "Init",
152
+ collapse: true,
153
+ };
154
+ } else {
155
+ return {
156
+ ...rootStepDescriptor,
157
+ collapse: false,
158
+ };
159
+ }
160
+ } else {
161
+ switch (event.name) {
162
+ case "sample_init":
163
+ return {
164
+ ...rootStepDescriptor,
165
+ name: "Sample Init",
166
+ collapse: true,
167
+ };
168
+ default:
169
+ return {
170
+ endSpace: false,
171
+ };
172
+ }
173
+ }
174
+ };
@@ -4,7 +4,7 @@ import { resolveToolInput } from "../chat/tools/tool";
4
4
  import { ToolCallView } from "../chat/tools/ToolCallView";
5
5
  import { ApprovalEventView } from "./ApprovalEventView";
6
6
  import { EventPanel } from "./event/EventPanel";
7
- import { TranscriptView } from "./TranscriptView";
7
+ import { TranscriptComponent } from "./TranscriptView";
8
8
 
9
9
  import clsx from "clsx";
10
10
  import { FC, useMemo } from "react";
@@ -12,11 +12,12 @@ import { PulsingDots } from "../../../components/PulsingDots";
12
12
  import { ChatView } from "../chat/ChatView";
13
13
  import { formatTiming, formatTitle } from "./event/utils";
14
14
  import styles from "./ToolEventView.module.css";
15
+ import { EventNode } from "./types";
15
16
 
16
17
  interface ToolEventViewProps {
17
18
  id: string;
18
19
  event: ToolEvent;
19
- depth: number;
20
+ children: EventNode[];
20
21
  className?: string | string[];
21
22
  }
22
23
 
@@ -26,7 +27,7 @@ interface ToolEventViewProps {
26
27
  export const ToolEventView: FC<ToolEventViewProps> = ({
27
28
  id,
28
29
  event,
29
- depth,
30
+ children,
30
31
  className,
31
32
  }) => {
32
33
  // Extract tool input
@@ -92,13 +93,12 @@ export const ToolEventView: FC<ToolEventViewProps> = ({
92
93
  </div>
93
94
  ) : undefined}
94
95
  </div>
95
- {event.events.length > 0 ? (
96
- <TranscriptView
97
- id={`${id}-subtask`}
96
+ {children.length > 0 ? (
97
+ <TranscriptComponent
98
98
  data-name="Transcript"
99
+ id={`${id}-subtask`}
100
+ eventNodes={children}
99
101
  data-default={event.failed || event.agent ? true : null}
100
- events={event.events}
101
- depth={depth + 1}
102
102
  />
103
103
  ) : (
104
104
  ""
@@ -17,6 +17,7 @@ import { ToolEventView } from "./ToolEventView";
17
17
  import { EventNode } from "./types";
18
18
 
19
19
  import clsx from "clsx";
20
+ import { SpanEventView } from "./SpanEventView";
20
21
  import styles from "./TranscriptView.module.css";
21
22
  import { TranscriptVirtualListComponent } from "./TranscriptVirtualListComponent";
22
23
  import { fixupEventStream } from "./transform/fixups";
@@ -64,7 +65,6 @@ export const TranscriptVirtualList: FC<TranscriptVirtualListProps> = memo(
64
65
  const eventNodes = useMemo(() => {
65
66
  const resolvedEvents = fixupEventStream(events, !running);
66
67
  const eventNodes = treeifyEvents(resolvedEvents, depth || 0);
67
-
68
68
  return eventNodes;
69
69
  }, [events, depth]);
70
70
 
@@ -201,6 +201,16 @@ export const RenderedEventNode: FC<RenderedEventNodeProps> = memo(
201
201
  <StateEventView id={id} event={node.event} className={className} />
202
202
  );
203
203
 
204
+ case "span_begin":
205
+ return (
206
+ <SpanEventView
207
+ id={id}
208
+ event={node.event}
209
+ children={node.children}
210
+ className={className}
211
+ />
212
+ );
213
+
204
214
  case "step":
205
215
  return (
206
216
  <StepEventView
@@ -237,7 +247,7 @@ export const RenderedEventNode: FC<RenderedEventNodeProps> = memo(
237
247
  id={id}
238
248
  event={node.event}
239
249
  className={className}
240
- depth={node.depth}
250
+ children={node.children}
241
251
  />
242
252
  );
243
253
 
@@ -8,7 +8,7 @@
8
8
 
9
9
  .node {
10
10
  padding-top: 0.7rem;
11
- padding-bottom: 0em;
11
+ padding-bottom: 1px;
12
12
  }
13
13
 
14
14
  .attached {
@@ -9,7 +9,6 @@ import {
9
9
  import { ApplicationIcons } from "../../../appearance/icons";
10
10
  import { EventNavs } from "./EventNavs";
11
11
 
12
- import { ProgressBar } from "../../../../components/ProgressBar";
13
12
  import { useProperty } from "../../../../state/hooks";
14
13
  import styles from "./EventPanel.module.css";
15
14
 
@@ -41,7 +40,6 @@ export const EventPanel: FC<EventPanelProps> = ({
41
40
  icon,
42
41
  collapse,
43
42
  children,
44
- running,
45
43
  }) => {
46
44
  const [isCollapsed, setCollapsed] = useProperty(id, "collapsed", {
47
45
  defaultValue: !!collapse,
@@ -191,7 +189,6 @@ export const EventPanel: FC<EventPanelProps> = ({
191
189
  })}
192
190
  </div>
193
191
  </div>
194
- <ProgressBar animating={!!running} />
195
192
  </>
196
193
  );
197
194
  return card;