inspect-ai 0.3.99__py3-none-any.whl → 0.3.100__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 (120) hide show
  1. inspect_ai/_display/core/config.py +11 -5
  2. inspect_ai/_display/core/panel.py +66 -2
  3. inspect_ai/_display/core/textual.py +5 -2
  4. inspect_ai/_display/plain/display.py +1 -0
  5. inspect_ai/_display/rich/display.py +2 -2
  6. inspect_ai/_display/textual/widgets/transcript.py +37 -9
  7. inspect_ai/_eval/score.py +2 -4
  8. inspect_ai/_eval/task/run.py +59 -81
  9. inspect_ai/_util/content.py +11 -6
  10. inspect_ai/_util/interrupt.py +2 -2
  11. inspect_ai/_util/text.py +7 -0
  12. inspect_ai/_util/working.py +8 -37
  13. inspect_ai/_view/__init__.py +0 -0
  14. inspect_ai/_view/schema.py +2 -1
  15. inspect_ai/_view/www/CLAUDE.md +15 -0
  16. inspect_ai/_view/www/dist/assets/index.css +263 -159
  17. inspect_ai/_view/www/dist/assets/index.js +22153 -19093
  18. inspect_ai/_view/www/log-schema.json +77 -3
  19. inspect_ai/_view/www/package.json +5 -1
  20. inspect_ai/_view/www/src/@types/log.d.ts +9 -0
  21. inspect_ai/_view/www/src/app/App.tsx +1 -15
  22. inspect_ai/_view/www/src/app/appearance/icons.ts +4 -1
  23. inspect_ai/_view/www/src/app/content/MetaDataGrid.tsx +24 -6
  24. inspect_ai/_view/www/src/app/content/MetadataGrid.module.css +0 -5
  25. inspect_ai/_view/www/src/app/content/RenderedContent.tsx +220 -205
  26. inspect_ai/_view/www/src/app/log-view/LogViewContainer.tsx +2 -1
  27. inspect_ai/_view/www/src/app/log-view/tabs/SamplesTab.tsx +5 -0
  28. inspect_ai/_view/www/src/app/routing/url.ts +84 -4
  29. inspect_ai/_view/www/src/app/samples/InlineSampleDisplay.module.css +0 -5
  30. inspect_ai/_view/www/src/app/samples/SampleDialog.module.css +1 -1
  31. inspect_ai/_view/www/src/app/samples/SampleDisplay.module.css +7 -0
  32. inspect_ai/_view/www/src/app/samples/SampleDisplay.tsx +24 -17
  33. inspect_ai/_view/www/src/app/samples/SampleSummaryView.module.css +1 -2
  34. inspect_ai/_view/www/src/app/samples/chat/ChatMessage.tsx +8 -6
  35. inspect_ai/_view/www/src/app/samples/chat/ChatMessageRow.tsx +0 -4
  36. inspect_ai/_view/www/src/app/samples/chat/ChatViewVirtualList.tsx +3 -2
  37. inspect_ai/_view/www/src/app/samples/chat/MessageContent.tsx +2 -0
  38. inspect_ai/_view/www/src/app/samples/chat/MessageContents.tsx +2 -0
  39. inspect_ai/_view/www/src/app/samples/chat/messages.ts +1 -0
  40. inspect_ai/_view/www/src/app/samples/chat/tools/ToolCallView.tsx +1 -0
  41. inspect_ai/_view/www/src/app/samples/list/SampleRow.tsx +1 -1
  42. inspect_ai/_view/www/src/app/samples/transcript/ErrorEventView.tsx +1 -2
  43. inspect_ai/_view/www/src/app/samples/transcript/InfoEventView.tsx +1 -1
  44. inspect_ai/_view/www/src/app/samples/transcript/InputEventView.tsx +1 -2
  45. inspect_ai/_view/www/src/app/samples/transcript/ModelEventView.module.css +1 -1
  46. inspect_ai/_view/www/src/app/samples/transcript/ModelEventView.tsx +1 -1
  47. inspect_ai/_view/www/src/app/samples/transcript/SampleInitEventView.tsx +1 -1
  48. inspect_ai/_view/www/src/app/samples/transcript/SampleLimitEventView.tsx +3 -2
  49. inspect_ai/_view/www/src/app/samples/transcript/SandboxEventView.tsx +4 -5
  50. inspect_ai/_view/www/src/app/samples/transcript/ScoreEventView.tsx +1 -1
  51. inspect_ai/_view/www/src/app/samples/transcript/SpanEventView.tsx +1 -2
  52. inspect_ai/_view/www/src/app/samples/transcript/StepEventView.tsx +1 -3
  53. inspect_ai/_view/www/src/app/samples/transcript/SubtaskEventView.tsx +1 -2
  54. inspect_ai/_view/www/src/app/samples/transcript/ToolEventView.tsx +3 -4
  55. inspect_ai/_view/www/src/app/samples/transcript/TranscriptPanel.module.css +42 -0
  56. inspect_ai/_view/www/src/app/samples/transcript/TranscriptPanel.tsx +77 -0
  57. inspect_ai/_view/www/src/app/samples/transcript/TranscriptVirtualList.tsx +27 -71
  58. inspect_ai/_view/www/src/app/samples/transcript/TranscriptVirtualListComponent.module.css +13 -3
  59. inspect_ai/_view/www/src/app/samples/transcript/TranscriptVirtualListComponent.tsx +27 -2
  60. inspect_ai/_view/www/src/app/samples/transcript/event/EventPanel.module.css +1 -0
  61. inspect_ai/_view/www/src/app/samples/transcript/event/EventPanel.tsx +21 -22
  62. inspect_ai/_view/www/src/app/samples/transcript/outline/OutlineRow.module.css +45 -0
  63. inspect_ai/_view/www/src/app/samples/transcript/outline/OutlineRow.tsx +223 -0
  64. inspect_ai/_view/www/src/app/samples/transcript/outline/TranscriptOutline.module.css +10 -0
  65. inspect_ai/_view/www/src/app/samples/transcript/outline/TranscriptOutline.tsx +258 -0
  66. inspect_ai/_view/www/src/app/samples/transcript/outline/tree-visitors.ts +187 -0
  67. inspect_ai/_view/www/src/app/samples/transcript/state/StateEventRenderers.tsx +8 -1
  68. inspect_ai/_view/www/src/app/samples/transcript/state/StateEventView.tsx +3 -4
  69. inspect_ai/_view/www/src/app/samples/transcript/transform/hooks.ts +78 -0
  70. inspect_ai/_view/www/src/app/samples/transcript/transform/treeify.ts +340 -135
  71. inspect_ai/_view/www/src/app/samples/transcript/transform/utils.ts +3 -0
  72. inspect_ai/_view/www/src/app/samples/transcript/types.ts +2 -0
  73. inspect_ai/_view/www/src/app/types.ts +5 -1
  74. inspect_ai/_view/www/src/client/api/api-browser.ts +2 -2
  75. inspect_ai/_view/www/src/components/LiveVirtualList.tsx +6 -1
  76. inspect_ai/_view/www/src/components/MarkdownDiv.tsx +1 -1
  77. inspect_ai/_view/www/src/components/PopOver.tsx +422 -0
  78. inspect_ai/_view/www/src/components/PulsingDots.module.css +9 -9
  79. inspect_ai/_view/www/src/components/PulsingDots.tsx +4 -1
  80. inspect_ai/_view/www/src/components/StickyScroll.tsx +183 -0
  81. inspect_ai/_view/www/src/components/TabSet.tsx +4 -0
  82. inspect_ai/_view/www/src/state/hooks.ts +52 -2
  83. inspect_ai/_view/www/src/state/logSlice.ts +4 -3
  84. inspect_ai/_view/www/src/state/samplePolling.ts +8 -0
  85. inspect_ai/_view/www/src/state/sampleSlice.ts +53 -9
  86. inspect_ai/_view/www/src/state/scrolling.ts +152 -0
  87. inspect_ai/_view/www/src/utils/attachments.ts +7 -0
  88. inspect_ai/_view/www/src/utils/python.ts +18 -0
  89. inspect_ai/_view/www/yarn.lock +269 -6
  90. inspect_ai/agent/_react.py +12 -7
  91. inspect_ai/agent/_run.py +2 -3
  92. inspect_ai/analysis/beta/_dataframe/samples/table.py +19 -18
  93. inspect_ai/log/_log.py +1 -1
  94. inspect_ai/log/_recorders/file.py +2 -9
  95. inspect_ai/log/_transcript.py +1 -1
  96. inspect_ai/model/_call_tools.py +6 -2
  97. inspect_ai/model/_openai.py +1 -1
  98. inspect_ai/model/_openai_responses.py +78 -39
  99. inspect_ai/model/_openai_web_search.py +31 -0
  100. inspect_ai/model/_providers/azureai.py +72 -3
  101. inspect_ai/model/_providers/openai.py +2 -1
  102. inspect_ai/scorer/_metric.py +1 -2
  103. inspect_ai/solver/_task_state.py +2 -2
  104. inspect_ai/tool/_tool.py +6 -2
  105. inspect_ai/tool/_tool_def.py +27 -4
  106. inspect_ai/tool/_tool_info.py +2 -0
  107. inspect_ai/tool/_tools/_web_search/_google.py +15 -4
  108. inspect_ai/tool/_tools/_web_search/_tavily.py +35 -12
  109. inspect_ai/tool/_tools/_web_search/_web_search.py +214 -45
  110. inspect_ai/util/__init__.py +4 -0
  111. inspect_ai/util/_json.py +3 -0
  112. inspect_ai/util/_limit.py +230 -20
  113. inspect_ai/util/_sandbox/docker/compose.py +20 -11
  114. inspect_ai/util/_span.py +1 -1
  115. {inspect_ai-0.3.99.dist-info → inspect_ai-0.3.100.dist-info}/METADATA +3 -3
  116. {inspect_ai-0.3.99.dist-info → inspect_ai-0.3.100.dist-info}/RECORD +120 -106
  117. {inspect_ai-0.3.99.dist-info → inspect_ai-0.3.100.dist-info}/WHEEL +1 -1
  118. {inspect_ai-0.3.99.dist-info → inspect_ai-0.3.100.dist-info}/entry_points.txt +0 -0
  119. {inspect_ai-0.3.99.dist-info → inspect_ai-0.3.100.dist-info}/licenses/LICENSE +0 -0
  120. {inspect_ai-0.3.99.dist-info → inspect_ai-0.3.100.dist-info}/top_level.txt +0 -0
@@ -15,6 +15,7 @@ import {
15
15
  RefObject,
16
16
  useCallback,
17
17
  useMemo,
18
+ useRef,
18
19
  } from "react";
19
20
  import { useNavigate, useParams } from "react-router-dom";
20
21
  import { EvalSample, Events } from "../../@types/log";
@@ -37,19 +38,14 @@ import { estimateSize } from "../../utils/json";
37
38
  import { printHeadingHtml, printHtml } from "../../utils/print";
38
39
  import { RecordTree } from "../content/RecordTree";
39
40
  import { useSampleDetailNavigation } from "../routing/navigationHooks";
40
- import {
41
- sampleMessageUrl,
42
- sampleUrl,
43
- supportsLinking,
44
- toFullUrl,
45
- } from "../routing/url";
41
+ import { sampleUrl } from "../routing/url";
46
42
  import { ModelTokenTable } from "../usage/ModelTokenTable";
47
43
  import { ChatViewVirtualList } from "./chat/ChatViewVirtualList";
48
44
  import { messagesFromEvents } from "./chat/messages";
49
45
  import styles from "./SampleDisplay.module.css";
50
46
  import { SampleSummaryView } from "./SampleSummaryView";
51
47
  import { SampleScoresView } from "./scores/SampleScoresView";
52
- import { TranscriptVirtualList } from "./transcript/TranscriptVirtualList";
48
+ import { TranscriptPanel } from "./transcript/TranscriptPanel";
53
49
 
54
50
  interface SampleDisplayProps {
55
51
  id: string;
@@ -87,7 +83,19 @@ export const SampleDisplay: FC<SampleDisplayProps> = ({ id, scrollRef }) => {
87
83
  // Navigation hook for URL updates
88
84
  const navigate = useNavigate();
89
85
 
90
- const sampleSummary = filteredSamples[selectedSampleIndex];
86
+ // Ref for samples tabs (used to meaure for offset)
87
+ const tabsRef: RefObject<HTMLUListElement | null> = useRef(null);
88
+ const tabsHeight = useMemo(() => {
89
+ if (tabsRef.current) {
90
+ const height = tabsRef.current.getBoundingClientRect().height;
91
+ return height;
92
+ }
93
+ return -1;
94
+ }, [tabsRef.current]);
95
+
96
+ const sampleSummary = useMemo(() => {
97
+ return filteredSamples[selectedSampleIndex];
98
+ }, [filteredSamples, selectedSampleIndex]);
91
99
 
92
100
  // Consolidate the events and messages into the proper list
93
101
  // whether running or not
@@ -115,12 +123,6 @@ export const SampleDisplay: FC<SampleDisplayProps> = ({ id, scrollRef }) => {
115
123
  epoch?: string;
116
124
  }>();
117
125
 
118
- const getMessageUrl = (id: string) => {
119
- return id && urlLogPath && supportsLinking()
120
- ? toFullUrl(sampleMessageUrl(id, urlLogPath, urlSampleId, urlEpoch))
121
- : undefined;
122
- };
123
-
124
126
  // Tab selection
125
127
  const onSelectedTab = useCallback(
126
128
  (e: MouseEvent<HTMLElement>) => {
@@ -171,7 +173,9 @@ export const SampleDisplay: FC<SampleDisplayProps> = ({ id, scrollRef }) => {
171
173
  }
172
174
 
173
175
  // Is the sample running?
174
- const running = isRunning(sampleSummary, runningSampleData);
176
+ const running = useMemo(() => {
177
+ return isRunning(sampleSummary, runningSampleData);
178
+ }, [sampleSummary, runningSampleData]);
175
179
 
176
180
  const sampleDetailNavigation = useSampleDetailNavigation();
177
181
 
@@ -182,6 +186,8 @@ export const SampleDisplay: FC<SampleDisplayProps> = ({ id, scrollRef }) => {
182
186
  ) : undefined}
183
187
  <TabSet
184
188
  id={tabsetId}
189
+ tabsRef={tabsRef}
190
+ className={clsx(styles.tabControls)}
185
191
  tabControlsClassName={clsx("text-size-base")}
186
192
  tabPanelsClassName={clsx(styles.tabPanel)}
187
193
  tools={tools}
@@ -198,11 +204,12 @@ export const SampleDisplay: FC<SampleDisplayProps> = ({ id, scrollRef }) => {
198
204
  }
199
205
  scrollable={false}
200
206
  >
201
- <TranscriptVirtualList
207
+ <TranscriptPanel
202
208
  key={`${baseId}-transcript-display-${id}`}
203
209
  id={`${baseId}-transcript-display-${id}`}
204
210
  events={sampleEvents || []}
205
211
  initialEventId={sampleDetailNavigation.event}
212
+ topOffset={tabsHeight}
206
213
  running={running}
207
214
  scrollRef={scrollRef}
208
215
  />
@@ -221,11 +228,11 @@ export const SampleDisplay: FC<SampleDisplayProps> = ({ id, scrollRef }) => {
221
228
  id={`${baseId}-chat-${id}`}
222
229
  messages={sampleMessages}
223
230
  initialMessageId={sampleDetailNavigation.message}
231
+ topOffset={tabsHeight}
224
232
  indented={true}
225
233
  scrollRef={scrollRef}
226
234
  toolCallStyle="complete"
227
235
  running={running}
228
- getMessageUrl={getMessageUrl}
229
236
  />
230
237
  </TabPanel>
231
238
  <TabPanel
@@ -10,8 +10,7 @@
10
10
  display: grid;
11
11
  grid-column-gap: 1em;
12
12
  border-bottom: solid var(--bs-border-color) 1px;
13
- margin-bottom: 1em;
14
- padding: 0em 1em 1em 1em;
13
+ padding: 1em 1em 1em 1em;
15
14
  }
16
15
 
17
16
  .centerLabel {
@@ -9,6 +9,11 @@ import {
9
9
  import { CopyButton } from "../../../components/CopyButton";
10
10
  import ExpandablePanel from "../../../components/ExpandablePanel";
11
11
  import { ApplicationIcons } from "../../appearance/icons";
12
+ import {
13
+ supportsLinking,
14
+ toFullUrl,
15
+ useSampleMessageUrl,
16
+ } from "../../routing/url";
12
17
  import styles from "./ChatMessage.module.css";
13
18
  import { MessageContents } from "./MessageContents";
14
19
  import { ChatViewToolCallStyle } from "./types";
@@ -19,7 +24,6 @@ interface ChatMessageProps {
19
24
  toolMessages: ChatMessageTool[];
20
25
  indented?: boolean;
21
26
  toolCallStyle: ChatViewToolCallStyle;
22
- getMessageUrl?: (id: string) => string | undefined;
23
27
  }
24
28
 
25
29
  export const ChatMessage: FC<ChatMessageProps> = ({
@@ -28,10 +32,8 @@ export const ChatMessage: FC<ChatMessageProps> = ({
28
32
  toolMessages,
29
33
  indented,
30
34
  toolCallStyle,
31
- getMessageUrl,
32
35
  }) => {
33
- const messageUrl =
34
- message.id && getMessageUrl ? getMessageUrl(message.id) : undefined;
36
+ const messageUrl = useSampleMessageUrl(message.id);
35
37
 
36
38
  const collapse = message.role === "system" || message.role === "user";
37
39
  return (
@@ -46,10 +48,10 @@ export const ChatMessage: FC<ChatMessageProps> = ({
46
48
  >
47
49
  <div className={clsx(styles.messageGrid, "text-style-label")}>
48
50
  {message.role}
49
- {messageUrl ? (
51
+ {supportsLinking() && messageUrl ? (
50
52
  <CopyButton
51
53
  icon={ApplicationIcons.link}
52
- value={messageUrl}
54
+ value={toFullUrl(messageUrl)}
53
55
  className={clsx(styles.copyLink)}
54
56
  />
55
57
  ) : (
@@ -13,7 +13,6 @@ interface ChatMessageRowProps {
13
13
  toolCallStyle: ChatViewToolCallStyle;
14
14
  indented?: boolean;
15
15
  padded?: boolean;
16
- getMessageUrl?: (id: string) => string | undefined;
17
16
  highlightUserMessage?: boolean;
18
17
  }
19
18
 
@@ -26,7 +25,6 @@ export const ChatMessageRow: FC<ChatMessageRowProps> = ({
26
25
  resolvedMessage,
27
26
  toolCallStyle,
28
27
  indented,
29
- getMessageUrl,
30
28
  highlightUserMessage,
31
29
  }) => {
32
30
  if (number) {
@@ -56,7 +54,6 @@ export const ChatMessageRow: FC<ChatMessageRowProps> = ({
56
54
  toolMessages={resolvedMessage.toolMessages}
57
55
  indented={indented}
58
56
  toolCallStyle={toolCallStyle}
59
- getMessageUrl={getMessageUrl}
60
57
  />
61
58
  </div>
62
59
 
@@ -82,7 +79,6 @@ export const ChatMessageRow: FC<ChatMessageRowProps> = ({
82
79
  toolMessages={resolvedMessage.toolMessages}
83
80
  indented={indented}
84
81
  toolCallStyle={toolCallStyle}
85
- getMessageUrl={getMessageUrl}
86
82
  />
87
83
  {resolvedMessage.message.role === "user" ? (
88
84
  <div style={{ height: "10px" }}></div>
@@ -16,6 +16,7 @@ interface ChatViewVirtualListProps {
16
16
  className?: string | string[];
17
17
  messages: Messages;
18
18
  initialMessageId?: string | null;
19
+ topOffset?: number;
19
20
  toolCallStyle: ChatViewToolCallStyle;
20
21
  indented: boolean;
21
22
  numbered?: boolean;
@@ -32,13 +33,13 @@ export const ChatViewVirtualList: FC<ChatViewVirtualListProps> = memo(
32
33
  id,
33
34
  messages,
34
35
  initialMessageId,
36
+ topOffset,
35
37
  className,
36
38
  toolCallStyle,
37
39
  indented,
38
40
  numbered = true,
39
41
  scrollRef,
40
42
  running,
41
- getMessageUrl,
42
43
  }) => {
43
44
  const collapsedMessages = useMemo(() => {
44
45
  return resolveMessages(messages);
@@ -66,7 +67,6 @@ export const ChatViewVirtualList: FC<ChatViewVirtualListProps> = memo(
66
67
  resolvedMessage={item}
67
68
  indented={indented}
68
69
  toolCallStyle={toolCallStyle}
69
- getMessageUrl={getMessageUrl}
70
70
  highlightUserMessage={true}
71
71
  />
72
72
  );
@@ -98,6 +98,7 @@ export const ChatViewVirtualList: FC<ChatViewVirtualListProps> = memo(
98
98
  data={collapsedMessages}
99
99
  renderRow={renderRow}
100
100
  initialTopMostItemIndex={initialMessageIndex}
101
+ offsetTop={topOffset}
101
102
  live={running}
102
103
  showProgress={running}
103
104
  components={{ Item }}
@@ -54,6 +54,7 @@ export const MessageContent: FC<MessageContentProps> = ({ contents }) => {
54
54
  type: "text",
55
55
  text: content,
56
56
  refusal: null,
57
+ internal: null,
57
58
  },
58
59
  index === contents.length - 1,
59
60
  );
@@ -78,6 +79,7 @@ export const MessageContent: FC<MessageContentProps> = ({ contents }) => {
78
79
  type: "text",
79
80
  text: contents,
80
81
  refusal: null,
82
+ internal: null,
81
83
  };
82
84
  return messageRenderers["text"].render(
83
85
  "text-message-content",
@@ -108,6 +108,7 @@ const resolveToolMessage = (toolMessage?: ChatMessageTool): ContentTool[] => {
108
108
  type: "text",
109
109
  text: content,
110
110
  refusal: null,
111
+ internal: null,
111
112
  },
112
113
  ],
113
114
  },
@@ -123,6 +124,7 @@ const resolveToolMessage = (toolMessage?: ChatMessageTool): ContentTool[] => {
123
124
  type: "text",
124
125
  text: con,
125
126
  refusal: null,
127
+ internal: null,
126
128
  },
127
129
  ],
128
130
  } as ContentTool;
@@ -129,6 +129,7 @@ const normalizeContent = (
129
129
  type: "text",
130
130
  text: content,
131
131
  refusal: null,
132
+ internal: null,
132
133
  };
133
134
  } else {
134
135
  return content;
@@ -175,6 +175,7 @@ const normalizeContent = (
175
175
  type: "text",
176
176
  text: String(output),
177
177
  refusal: null,
178
+ internal: null,
178
179
  },
179
180
  ],
180
181
  },
@@ -115,7 +115,7 @@ export const SampleRow: FC<SampleRowProps> = ({
115
115
  ) : completed ? (
116
116
  scoreRendered
117
117
  ) : (
118
- <PulsingDots />
118
+ <PulsingDots subtle={false} />
119
119
  )}
120
120
  </div>
121
121
  </div>
@@ -19,10 +19,9 @@ export const ErrorEventView: FC<ErrorEventViewProps> = ({
19
19
  className,
20
20
  }) => {
21
21
  const event = eventNode.event;
22
- const id = eventNode.id;
23
22
  return (
24
23
  <EventPanel
25
- id={id}
24
+ eventNodeId={eventNode.id}
26
25
  depth={eventNode.depth}
27
26
  title="Error"
28
27
  className={className}
@@ -36,7 +36,7 @@ export const InfoEventView: FC<InfoEventViewProps> = ({
36
36
 
37
37
  return (
38
38
  <EventPanel
39
- id={eventNode.id}
39
+ eventNodeId={eventNode.id}
40
40
  depth={eventNode.depth}
41
41
  title={"Info" + (event.source ? ": " + event.source : "")}
42
42
  className={className}
@@ -19,10 +19,9 @@ export const InputEventView: FC<InputEventViewProps> = ({
19
19
  className,
20
20
  }) => {
21
21
  const event = eventNode.event;
22
- const id = eventNode.id;
23
22
  return (
24
23
  <EventPanel
25
- id={id}
24
+ eventNodeId={eventNode.id}
26
25
  depth={eventNode.depth}
27
26
  title="Input"
28
27
  className={className}
@@ -32,7 +32,7 @@
32
32
  }
33
33
 
34
34
  .progress {
35
- margin-left: 2em;
35
+ margin-left: 0.5em;
36
36
  }
37
37
 
38
38
  .toolConfig {
@@ -69,7 +69,7 @@ export const ModelEventView: FC<ModelEventViewProps> = ({
69
69
 
70
70
  return (
71
71
  <EventPanel
72
- id={eventNode.id}
72
+ eventNodeId={eventNode.id}
73
73
  depth={eventNode.depth}
74
74
  className={className}
75
75
  title={formatTitle(panelTitle, totalUsage, callTime)}
@@ -56,7 +56,7 @@ export const SampleInitEventView: FC<SampleInitEventViewProps> = ({
56
56
 
57
57
  return (
58
58
  <EventPanel
59
- id={eventNode.id}
59
+ eventNodeId={eventNode.id}
60
60
  depth={eventNode.depth}
61
61
  className={className}
62
62
  title="Sample"
@@ -1,3 +1,4 @@
1
+ import clsx from "clsx";
1
2
  import { FC } from "react";
2
3
  import { SampleLimitEvent, Type10 } from "../../../@types/log";
3
4
  import { ApplicationIcons } from "../../appearance/icons";
@@ -55,13 +56,13 @@ export const SampleLimitEventView: FC<SampleLimitEventViewProps> = ({
55
56
 
56
57
  return (
57
58
  <EventPanel
58
- id={eventNode.id}
59
+ eventNodeId={eventNode.id}
59
60
  depth={eventNode.depth}
60
61
  title={title}
61
62
  icon={icon}
62
63
  className={className}
63
64
  >
64
- {eventNode.event.message}
65
+ <div className={clsx("text-size-smaller")}>{eventNode.event.message}</div>
65
66
  </EventPanel>
66
67
  );
67
68
  };
@@ -25,10 +25,9 @@ export const SandboxEventView: FC<SandboxEventViewProps> = ({
25
25
  className,
26
26
  }) => {
27
27
  const event = eventNode.event;
28
- const id = eventNode.id;
29
28
  return (
30
29
  <EventPanel
31
- id={id}
30
+ eventNodeId={eventNode.id}
32
31
  depth={eventNode.depth}
33
32
  className={className}
34
33
  title={`Sandbox: ${event.action}`}
@@ -36,11 +35,11 @@ export const SandboxEventView: FC<SandboxEventViewProps> = ({
36
35
  subTitle={formatTiming(event.timestamp, event.working_start)}
37
36
  >
38
37
  {event.action === "exec" ? (
39
- <ExecView id={`${id}-exec`} event={event} />
38
+ <ExecView id={`${eventNode.id}-exec`} event={event} />
40
39
  ) : event.action === "read_file" ? (
41
- <ReadFileView id={`${id}-read-file`} event={event} />
40
+ <ReadFileView id={`${eventNode.id}-read-file`} event={event} />
42
41
  ) : (
43
- <WriteFileView id={`${id}-write-file`} event={event} />
42
+ <WriteFileView id={`${eventNode.id}-write-file`} event={event} />
44
43
  )}
45
44
  </EventPanel>
46
45
  );
@@ -31,7 +31,7 @@ export const ScoreEventView: FC<ScoreEventViewProps> = ({
31
31
 
32
32
  return (
33
33
  <EventPanel
34
- id={eventNode.id}
34
+ eventNodeId={eventNode.id}
35
35
  depth={eventNode.depth}
36
36
  title={(event.intermediate ? "Intermediate " : "") + "Score"}
37
37
  className={clsx(className, "text-size-small")}
@@ -21,7 +21,6 @@ export const SpanEventView: FC<SpanEventViewProps> = ({
21
21
  className,
22
22
  }) => {
23
23
  const event = eventNode.event;
24
- const id = eventNode.id;
25
24
  const descriptor = spanDescriptor(event);
26
25
  const title =
27
26
  descriptor.name ||
@@ -30,7 +29,7 @@ export const SpanEventView: FC<SpanEventViewProps> = ({
30
29
 
31
30
  return (
32
31
  <EventPanel
33
- id={id}
32
+ eventNodeId={eventNode.id}
34
33
  depth={eventNode.depth}
35
34
  childIds={children.map((child) => child.id)}
36
35
  className={clsx("transcript-span", className)}
@@ -21,8 +21,6 @@ export const StepEventView: FC<StepEventViewProps> = ({
21
21
  className,
22
22
  }) => {
23
23
  const event = eventNode.event;
24
- const id = eventNode.id;
25
-
26
24
  const descriptor = stepDescriptor(event);
27
25
  const title =
28
26
  descriptor.name ||
@@ -31,7 +29,7 @@ export const StepEventView: FC<StepEventViewProps> = ({
31
29
 
32
30
  return (
33
31
  <EventPanel
34
- id={id}
32
+ eventNodeId={eventNode.id}
35
33
  depth={eventNode.depth}
36
34
  childIds={children.map((child) => child.id)}
37
35
  className={clsx("transcript-step", className)}
@@ -23,7 +23,6 @@ export const SubtaskEventView: FC<SubtaskEventViewProps> = ({
23
23
  className,
24
24
  }) => {
25
25
  const event = eventNode.event;
26
- const id = eventNode.id;
27
26
  const body: ReactNode[] = [];
28
27
  if (event.type === "fork") {
29
28
  body.push(
@@ -48,7 +47,7 @@ export const SubtaskEventView: FC<SubtaskEventViewProps> = ({
48
47
  const type = event.type === "fork" ? "Fork" : "Subtask";
49
48
  return (
50
49
  <EventPanel
51
- id={id}
50
+ eventNodeId={eventNode.id}
52
51
  depth={eventNode.depth}
53
52
  className={className}
54
53
  title={formatTitle(
@@ -28,7 +28,6 @@ export const ToolEventView: FC<ToolEventViewProps> = ({
28
28
  className,
29
29
  }) => {
30
30
  const event = eventNode.event;
31
- const id = eventNode.id;
32
31
 
33
32
  // Extract tool input
34
33
  const { input, functionCall, highlightLanguage } = useMemo(
@@ -56,7 +55,7 @@ export const ToolEventView: FC<ToolEventViewProps> = ({
56
55
  const title = `Tool: ${event.view?.title || event.function}`;
57
56
  return (
58
57
  <EventPanel
59
- id={id}
58
+ eventNodeId={eventNode.id}
60
59
  depth={eventNode.depth}
61
60
  title={formatTitle(title, undefined, event.working_time)}
62
61
  className={className}
@@ -67,7 +66,7 @@ export const ToolEventView: FC<ToolEventViewProps> = ({
67
66
  >
68
67
  <div data-name="Summary" className={styles.summary}>
69
68
  <ToolCallView
70
- id={`${id}-tool-call`}
69
+ id={`${eventNode.id}-tool-call`}
71
70
  functionCall={functionCall}
72
71
  input={input}
73
72
  highlightLanguage={highlightLanguage}
@@ -78,7 +77,7 @@ export const ToolEventView: FC<ToolEventViewProps> = ({
78
77
 
79
78
  {lastModelNode ? (
80
79
  <ChatView
81
- id={`${id}-toolcall-chatmessage`}
80
+ id={`${eventNode.id}-toolcall-chatmessage`}
82
81
  messages={lastModelNode.event.output.choices.map((m) => m.message)}
83
82
  numbered={false}
84
83
  toolCallStyle="compact"
@@ -0,0 +1,42 @@
1
+ .container {
2
+ display: grid;
3
+ width: 100%;
4
+ grid-template-columns: 180px 1fr;
5
+ min-height: 100vh;
6
+ transition: grid-template-columns 0.3s ease;
7
+ }
8
+
9
+ .container.collapsed {
10
+ grid-template-columns: 1.5em 1fr;
11
+ }
12
+
13
+ .treeContainer {
14
+ padding: 0.5em;
15
+ border-right: solid 1px var(--bs-light-border-subtle);
16
+ width: 100%;
17
+ height: 100%;
18
+ }
19
+
20
+ .collapsed .treeContainer {
21
+ border-top: solid 1px var(--bs-light-border-subtle);
22
+ }
23
+
24
+ .listContainer {
25
+ background-color: var(--bs-body-bg);
26
+ }
27
+
28
+ .outline {
29
+ margin-bottom: 1em;
30
+ }
31
+
32
+ .outlineToggle {
33
+ cursor: pointer;
34
+ font-size: 0.8em;
35
+ position: absolute;
36
+ top: 0.5em;
37
+ right: 0.5em;
38
+ }
39
+
40
+ .collapsed .outline {
41
+ display: none;
42
+ }
@@ -0,0 +1,77 @@
1
+ import clsx from "clsx";
2
+ import { FC, memo, RefObject } from "react";
3
+ import { useParams } from "react-router-dom";
4
+ import { Events } from "../../../@types/log";
5
+ import { StickyScroll } from "../../../components/StickyScroll";
6
+ import { useCollapsedState } from "../../../state/hooks";
7
+ import { ApplicationIcons } from "../../appearance/icons";
8
+ import { TranscriptOutline } from "./outline/TranscriptOutline";
9
+ import styles from "./TranscriptPanel.module.css";
10
+ import { TranscriptVirtualList } from "./TranscriptVirtualList";
11
+ import { useEventNodes } from "./transform/hooks";
12
+
13
+ interface TranscriptPanelProps {
14
+ id: string;
15
+ events: Events;
16
+ scrollRef: RefObject<HTMLDivElement | null>;
17
+ running?: boolean;
18
+ initialEventId?: string | null;
19
+ topOffset?: number;
20
+ }
21
+
22
+ /**
23
+ * Renders the Transcript Virtual List.
24
+ */
25
+ export const TranscriptPanel: FC<TranscriptPanelProps> = memo((props) => {
26
+ let { id, scrollRef, events, running, initialEventId, topOffset } = props;
27
+
28
+ const { eventNodes, defaultCollapsedIds } = useEventNodes(
29
+ events,
30
+ running === true,
31
+ );
32
+ const { logPath } = useParams<{ logPath: string }>();
33
+
34
+ const [collapsed, setCollapsed] = useCollapsedState(
35
+ `transcript-panel-${logPath || "na"}`,
36
+ false,
37
+ );
38
+
39
+ return (
40
+ <div
41
+ className={clsx(
42
+ styles.container,
43
+ collapsed ? styles.collapsed : undefined,
44
+ )}
45
+ >
46
+ <StickyScroll
47
+ scrollRef={scrollRef}
48
+ className={styles.treeContainer}
49
+ offsetTop={topOffset}
50
+ >
51
+ <TranscriptOutline
52
+ className={clsx(styles.outline)}
53
+ eventNodes={eventNodes}
54
+ running={running}
55
+ defaultCollapsedIds={defaultCollapsedIds}
56
+ scrollRef={scrollRef}
57
+ />
58
+ <div
59
+ className={styles.outlineToggle}
60
+ onClick={() => setCollapsed(!collapsed)}
61
+ >
62
+ <i className={ApplicationIcons.sidebar} />
63
+ </div>
64
+ </StickyScroll>
65
+ <TranscriptVirtualList
66
+ id={id}
67
+ eventNodes={eventNodes}
68
+ defaultCollapsedIds={defaultCollapsedIds}
69
+ scrollRef={scrollRef}
70
+ running={running}
71
+ initialEventId={initialEventId === undefined ? null : initialEventId}
72
+ offsetTop={topOffset}
73
+ className={styles.listContainer}
74
+ />
75
+ </div>
76
+ );
77
+ });