inspect-ai 0.3.96__py3-none-any.whl → 0.3.97__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 (133) hide show
  1. inspect_ai/_eval/eval.py +10 -2
  2. inspect_ai/_eval/task/util.py +32 -3
  3. inspect_ai/_util/registry.py +7 -0
  4. inspect_ai/_util/timer.py +13 -0
  5. inspect_ai/_view/www/dist/assets/index.css +275 -195
  6. inspect_ai/_view/www/dist/assets/index.js +8568 -7376
  7. inspect_ai/_view/www/src/app/App.css +1 -0
  8. inspect_ai/_view/www/src/app/App.tsx +27 -10
  9. inspect_ai/_view/www/src/app/appearance/icons.ts +5 -0
  10. inspect_ai/_view/www/src/app/content/RecordTree.module.css +22 -0
  11. inspect_ai/_view/www/src/app/content/RecordTree.tsx +370 -0
  12. inspect_ai/_view/www/src/app/content/RenderedContent.module.css +5 -0
  13. inspect_ai/_view/www/src/app/content/RenderedContent.tsx +32 -19
  14. inspect_ai/_view/www/src/app/content/record_processors/store.ts +101 -0
  15. inspect_ai/_view/www/src/app/content/record_processors/types.ts +3 -0
  16. inspect_ai/_view/www/src/app/content/types.ts +5 -0
  17. inspect_ai/_view/www/src/app/log-view/LogView.tsx +1 -0
  18. inspect_ai/_view/www/src/app/log-view/LogViewContainer.tsx +35 -28
  19. inspect_ai/_view/www/src/app/log-view/LogViewLayout.tsx +1 -8
  20. inspect_ai/_view/www/src/app/log-view/navbar/PrimaryBar.tsx +2 -4
  21. inspect_ai/_view/www/src/app/log-view/navbar/ResultsPanel.tsx +13 -3
  22. inspect_ai/_view/www/src/app/log-view/navbar/ScoreGrid.module.css +15 -0
  23. inspect_ai/_view/www/src/app/log-view/navbar/ScoreGrid.tsx +14 -10
  24. inspect_ai/_view/www/src/app/log-view/tabs/InfoTab.tsx +9 -3
  25. inspect_ai/_view/www/src/app/log-view/tabs/JsonTab.tsx +1 -3
  26. inspect_ai/_view/www/src/app/log-view/tabs/SamplesTab.tsx +8 -2
  27. inspect_ai/_view/www/src/app/log-view/types.ts +1 -0
  28. inspect_ai/_view/www/src/app/plan/ModelCard.module.css +7 -0
  29. inspect_ai/_view/www/src/app/plan/ModelCard.tsx +5 -2
  30. inspect_ai/_view/www/src/app/plan/PlanCard.tsx +13 -8
  31. inspect_ai/_view/www/src/app/routing/navigationHooks.ts +63 -8
  32. inspect_ai/_view/www/src/app/routing/url.ts +45 -0
  33. inspect_ai/_view/www/src/app/samples/InlineSampleDisplay.module.css +2 -1
  34. inspect_ai/_view/www/src/app/samples/InlineSampleDisplay.tsx +15 -8
  35. inspect_ai/_view/www/src/app/samples/SampleDialog.module.css +3 -0
  36. inspect_ai/_view/www/src/app/samples/SampleDialog.tsx +16 -5
  37. inspect_ai/_view/www/src/app/samples/SampleDisplay.module.css +9 -1
  38. inspect_ai/_view/www/src/app/samples/SampleDisplay.tsx +68 -31
  39. inspect_ai/_view/www/src/app/samples/chat/ChatMessage.module.css +12 -7
  40. inspect_ai/_view/www/src/app/samples/chat/ChatMessage.tsx +17 -5
  41. inspect_ai/_view/www/src/app/samples/chat/ChatMessageRow.module.css +9 -0
  42. inspect_ai/_view/www/src/app/samples/chat/ChatMessageRow.tsx +48 -18
  43. inspect_ai/_view/www/src/app/samples/chat/ChatView.tsx +0 -1
  44. inspect_ai/_view/www/src/app/samples/chat/ChatViewVirtualList.module.css +4 -0
  45. inspect_ai/_view/www/src/app/samples/chat/ChatViewVirtualList.tsx +41 -1
  46. inspect_ai/_view/www/src/app/samples/chat/messages.ts +7 -0
  47. inspect_ai/_view/www/src/app/samples/chat/tools/ToolCallView.module.css +0 -3
  48. inspect_ai/_view/www/src/app/samples/chat/tools/ToolCallView.tsx +1 -1
  49. inspect_ai/_view/www/src/app/samples/chat/tools/ToolInput.module.css +1 -1
  50. inspect_ai/_view/www/src/app/samples/chat/tools/ToolOutput.module.css +1 -1
  51. inspect_ai/_view/www/src/app/samples/descriptor/score/NumericScoreDescriptor.tsx +5 -1
  52. inspect_ai/_view/www/src/app/samples/descriptor/score/PassFailScoreDescriptor.tsx +11 -6
  53. inspect_ai/_view/www/src/app/samples/list/SampleList.tsx +7 -0
  54. inspect_ai/_view/www/src/app/samples/list/SampleRow.tsx +5 -18
  55. inspect_ai/_view/www/src/app/samples/sample-tools/SortFilter.tsx +1 -1
  56. inspect_ai/_view/www/src/app/samples/scores/SampleScoresGrid.tsx +18 -5
  57. inspect_ai/_view/www/src/app/samples/scores/SampleScoresView.module.css +0 -6
  58. inspect_ai/_view/www/src/app/samples/scores/SampleScoresView.tsx +4 -1
  59. inspect_ai/_view/www/src/app/samples/transcript/ApprovalEventView.tsx +4 -2
  60. inspect_ai/_view/www/src/app/samples/transcript/ErrorEventView.tsx +6 -4
  61. inspect_ai/_view/www/src/app/samples/transcript/InfoEventView.module.css +1 -1
  62. inspect_ai/_view/www/src/app/samples/transcript/InfoEventView.tsx +13 -6
  63. inspect_ai/_view/www/src/app/samples/transcript/InputEventView.tsx +6 -4
  64. inspect_ai/_view/www/src/app/samples/transcript/LoggerEventView.tsx +4 -2
  65. inspect_ai/_view/www/src/app/samples/transcript/ModelEventView.tsx +11 -8
  66. inspect_ai/_view/www/src/app/samples/transcript/SampleInitEventView.tsx +14 -8
  67. inspect_ai/_view/www/src/app/samples/transcript/SampleLimitEventView.tsx +13 -8
  68. inspect_ai/_view/www/src/app/samples/transcript/SandboxEventView.tsx +25 -16
  69. inspect_ai/_view/www/src/app/samples/transcript/ScoreEventView.tsx +7 -5
  70. inspect_ai/_view/www/src/app/samples/transcript/SpanEventView.tsx +11 -28
  71. inspect_ai/_view/www/src/app/samples/transcript/StepEventView.tsx +12 -20
  72. inspect_ai/_view/www/src/app/samples/transcript/SubtaskEventView.tsx +12 -31
  73. inspect_ai/_view/www/src/app/samples/transcript/ToolEventView.tsx +25 -29
  74. inspect_ai/_view/www/src/app/samples/transcript/TranscriptVirtualList.tsx +297 -0
  75. inspect_ai/_view/www/src/app/samples/transcript/TranscriptVirtualListComponent.module.css +0 -8
  76. inspect_ai/_view/www/src/app/samples/transcript/TranscriptVirtualListComponent.tsx +43 -25
  77. inspect_ai/_view/www/src/app/samples/transcript/event/EventPanel.module.css +43 -0
  78. inspect_ai/_view/www/src/app/samples/transcript/event/EventPanel.tsx +109 -43
  79. inspect_ai/_view/www/src/app/samples/transcript/state/StateEventView.tsx +19 -8
  80. inspect_ai/_view/www/src/app/samples/transcript/transform/treeify.ts +128 -60
  81. inspect_ai/_view/www/src/app/samples/transcript/transform/utils.ts +14 -4
  82. inspect_ai/_view/www/src/app/samples/transcript/types.ts +6 -4
  83. inspect_ai/_view/www/src/app/types.ts +12 -1
  84. inspect_ai/_view/www/src/components/Card.css +6 -3
  85. inspect_ai/_view/www/src/components/Card.tsx +15 -2
  86. inspect_ai/_view/www/src/components/CopyButton.tsx +4 -6
  87. inspect_ai/_view/www/src/components/ExpandablePanel.module.css +20 -14
  88. inspect_ai/_view/www/src/components/ExpandablePanel.tsx +17 -22
  89. inspect_ai/_view/www/src/components/LargeModal.tsx +5 -1
  90. inspect_ai/_view/www/src/components/LiveVirtualList.tsx +25 -1
  91. inspect_ai/_view/www/src/components/MarkdownDiv.css +4 -0
  92. inspect_ai/_view/www/src/components/MarkdownDiv.tsx +2 -2
  93. inspect_ai/_view/www/src/components/TabSet.module.css +6 -1
  94. inspect_ai/_view/www/src/components/TabSet.tsx +8 -2
  95. inspect_ai/_view/www/src/state/hooks.ts +83 -13
  96. inspect_ai/_view/www/src/state/logPolling.ts +2 -2
  97. inspect_ai/_view/www/src/state/logSlice.ts +1 -2
  98. inspect_ai/_view/www/src/state/logsSlice.ts +9 -9
  99. inspect_ai/_view/www/src/state/samplePolling.ts +1 -1
  100. inspect_ai/_view/www/src/state/sampleSlice.ts +134 -7
  101. inspect_ai/_view/www/src/state/scoring.ts +1 -1
  102. inspect_ai/_view/www/src/state/scrolling.ts +39 -6
  103. inspect_ai/_view/www/src/state/store.ts +5 -0
  104. inspect_ai/_view/www/src/state/store_filter.ts +47 -44
  105. inspect_ai/_view/www/src/utils/debugging.ts +95 -0
  106. inspect_ai/_view/www/src/utils/format.ts +2 -2
  107. inspect_ai/_view/www/src/utils/json.ts +29 -0
  108. inspect_ai/agent/__init__.py +2 -1
  109. inspect_ai/agent/_agent.py +12 -0
  110. inspect_ai/agent/_react.py +184 -48
  111. inspect_ai/agent/_types.py +14 -1
  112. inspect_ai/analysis/beta/__init__.py +0 -2
  113. inspect_ai/analysis/beta/_dataframe/columns.py +11 -16
  114. inspect_ai/analysis/beta/_dataframe/evals/table.py +65 -40
  115. inspect_ai/analysis/beta/_dataframe/events/table.py +24 -36
  116. inspect_ai/analysis/beta/_dataframe/messages/table.py +24 -15
  117. inspect_ai/analysis/beta/_dataframe/progress.py +35 -5
  118. inspect_ai/analysis/beta/_dataframe/record.py +13 -9
  119. inspect_ai/analysis/beta/_dataframe/samples/columns.py +1 -1
  120. inspect_ai/analysis/beta/_dataframe/samples/table.py +156 -46
  121. inspect_ai/analysis/beta/_dataframe/util.py +14 -12
  122. inspect_ai/model/_call_tools.py +1 -1
  123. inspect_ai/model/_providers/anthropic.py +18 -5
  124. inspect_ai/model/_providers/azureai.py +7 -2
  125. inspect_ai/model/_providers/util/llama31.py +3 -3
  126. {inspect_ai-0.3.96.dist-info → inspect_ai-0.3.97.dist-info}/METADATA +1 -1
  127. {inspect_ai-0.3.96.dist-info → inspect_ai-0.3.97.dist-info}/RECORD +131 -126
  128. {inspect_ai-0.3.96.dist-info → inspect_ai-0.3.97.dist-info}/WHEEL +1 -1
  129. inspect_ai/_view/www/src/app/samples/transcript/TranscriptView.module.css +0 -48
  130. inspect_ai/_view/www/src/app/samples/transcript/TranscriptView.tsx +0 -276
  131. {inspect_ai-0.3.96.dist-info → inspect_ai-0.3.97.dist-info}/entry_points.txt +0 -0
  132. {inspect_ai-0.3.96.dist-info → inspect_ai-0.3.97.dist-info}/licenses/LICENSE +0 -0
  133. {inspect_ai-0.3.96.dist-info → inspect_ai-0.3.97.dist-info}/top_level.txt +0 -0
@@ -1,10 +1,9 @@
1
- import { ToolEvent } from "../../../@types/log";
1
+ import { ApprovalEvent, ModelEvent, ToolEvent } from "../../../@types/log";
2
2
  import { ApplicationIcons } from "../../appearance/icons";
3
3
  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 { TranscriptComponent } from "./TranscriptView";
8
7
 
9
8
  import clsx from "clsx";
10
9
  import { FC, useMemo } from "react";
@@ -12,12 +11,11 @@ import { PulsingDots } from "../../../components/PulsingDots";
12
11
  import { ChatView } from "../chat/ChatView";
13
12
  import { formatTiming, formatTitle } from "./event/utils";
14
13
  import styles from "./ToolEventView.module.css";
15
- import { EventNode } from "./types";
14
+ import { EventNode, EventType } from "./types";
16
15
 
17
16
  interface ToolEventViewProps {
18
- id: string;
19
- event: ToolEvent;
20
- children: EventNode[];
17
+ eventNode: EventNode<ToolEvent>;
18
+ children: EventNode<EventType>[];
21
19
  className?: string | string[];
22
20
  }
23
21
 
@@ -25,39 +23,47 @@ interface ToolEventViewProps {
25
23
  * Renders the ToolEventView component.
26
24
  */
27
25
  export const ToolEventView: FC<ToolEventViewProps> = ({
28
- id,
29
- event,
26
+ eventNode,
30
27
  children,
31
28
  className,
32
29
  }) => {
30
+ const event = eventNode.event;
31
+ const id = eventNode.id;
32
+
33
33
  // Extract tool input
34
34
  const { input, functionCall, highlightLanguage } = useMemo(
35
35
  () => resolveToolInput(event.function, event.arguments),
36
36
  [event.function, event.arguments],
37
37
  );
38
38
 
39
- const { approvalEvent, lastModelEvent } = useMemo(() => {
40
- // Find an approval if there is one
41
- const approvalEvent = event.events.find((e) => {
42
- return e.event === "approval";
39
+ const { approvalNode, lastModelNode } = useMemo(() => {
40
+ const approvalNode = children.find((e) => {
41
+ return e.event.event === "approval";
43
42
  });
44
43
 
45
44
  // Find a model message to render, if there is one
46
- const lastModelEvent = [...event.events].reverse().find((e) => {
47
- return e.event === "model";
45
+
46
+ const lastModelNode = children.findLast((e) => {
47
+ return e.event.event === "model";
48
48
  });
49
49
 
50
- return { approvalEvent, lastModelEvent };
50
+ return {
51
+ approvalNode: approvalNode as EventNode<ApprovalEvent> | undefined,
52
+ lastModelNode: lastModelNode as EventNode<ModelEvent> | undefined,
53
+ };
51
54
  }, [event.events]);
52
55
 
53
56
  const title = `Tool: ${event.view?.title || event.function}`;
54
57
  return (
55
58
  <EventPanel
56
59
  id={id}
60
+ depth={eventNode.depth}
57
61
  title={formatTitle(title, undefined, event.working_time)}
58
62
  className={className}
59
63
  subTitle={formatTiming(event.timestamp, event.working_start)}
60
64
  icon={ApplicationIcons.solvers.use_tools}
65
+ childIds={children.map((child) => child.id)}
66
+ collapseControl="bottom"
61
67
  >
62
68
  <div data-name="Summary" className={styles.summary}>
63
69
  <ToolCallView
@@ -70,18 +76,18 @@ export const ToolEventView: FC<ToolEventViewProps> = ({
70
76
  view={event.view ? event.view : undefined}
71
77
  />
72
78
 
73
- {lastModelEvent && lastModelEvent.event === "model" ? (
79
+ {lastModelNode ? (
74
80
  <ChatView
75
81
  id={`${id}-toolcall-chatmessage`}
76
- messages={lastModelEvent.output.choices.map((m) => m.message)}
82
+ messages={lastModelNode.event.output.choices.map((m) => m.message)}
77
83
  numbered={false}
78
84
  toolCallStyle="compact"
79
85
  />
80
86
  ) : undefined}
81
87
 
82
- {approvalEvent ? (
88
+ {approvalNode ? (
83
89
  <ApprovalEventView
84
- event={approvalEvent}
90
+ eventNode={approvalNode}
85
91
  className={styles.approval}
86
92
  />
87
93
  ) : (
@@ -93,16 +99,6 @@ export const ToolEventView: FC<ToolEventViewProps> = ({
93
99
  </div>
94
100
  ) : undefined}
95
101
  </div>
96
- {children.length > 0 ? (
97
- <TranscriptComponent
98
- data-name="Transcript"
99
- id={`${id}-subtask`}
100
- eventNodes={children}
101
- data-default={event.failed || event.agent ? true : null}
102
- />
103
- ) : (
104
- ""
105
- )}
106
102
  </EventPanel>
107
103
  );
108
104
  };
@@ -0,0 +1,297 @@
1
+ import { FC, memo, RefObject, useEffect, useMemo } from "react";
2
+ import {
3
+ ApprovalEvent,
4
+ ErrorEvent,
5
+ Events,
6
+ InfoEvent,
7
+ InputEvent,
8
+ LoggerEvent,
9
+ ModelEvent,
10
+ SampleInitEvent,
11
+ SampleLimitEvent,
12
+ SandboxEvent,
13
+ ScoreEvent,
14
+ SpanBeginEvent,
15
+ StateEvent,
16
+ StepEvent,
17
+ StoreEvent,
18
+ SubtaskEvent,
19
+ ToolEvent,
20
+ } from "../../../@types/log";
21
+ import { ApprovalEventView } from "./ApprovalEventView";
22
+ import { ErrorEventView } from "./ErrorEventView";
23
+ import { InfoEventView } from "./InfoEventView";
24
+ import { InputEventView } from "./InputEventView";
25
+ import { LoggerEventView } from "./LoggerEventView";
26
+ import { ModelEventView } from "./ModelEventView";
27
+ import { SampleInitEventView } from "./SampleInitEventView";
28
+ import { SampleLimitEventView } from "./SampleLimitEventView";
29
+ import { SandboxEventView } from "./SandboxEventView";
30
+ import { ScoreEventView } from "./ScoreEventView";
31
+ import { StateEventView } from "./state/StateEventView";
32
+ import { StepEventView } from "./StepEventView";
33
+ import { SubtaskEventView } from "./SubtaskEventView";
34
+ import { ToolEventView } from "./ToolEventView";
35
+ import { EventNode } from "./types";
36
+
37
+ import { useStore } from "../../../state/store";
38
+ import { SpanEventView } from "./SpanEventView";
39
+ import { TranscriptVirtualListComponent } from "./TranscriptVirtualListComponent";
40
+ import { fixupEventStream, kSandboxSignalName } from "./transform/fixups";
41
+ import { flatTree, treeifyEvents } from "./transform/treeify";
42
+
43
+ interface TranscriptVirtualListProps {
44
+ id: string;
45
+ events: Events;
46
+ initialEventId: string | null;
47
+ scrollRef: RefObject<HTMLDivElement | null>;
48
+ running?: boolean;
49
+ }
50
+
51
+ /**
52
+ * Renders the Transcript Virtual List.
53
+ */
54
+ export const TranscriptVirtualList: FC<TranscriptVirtualListProps> = memo(
55
+ (props) => {
56
+ let { id, scrollRef, events, running, initialEventId } = props;
57
+
58
+ // The list of events that have been collapsed
59
+ const collapsedEvents = useStore((state) => state.sample.collapsedEvents);
60
+ const setCollapsedEvents = useStore(
61
+ (state) => state.sampleActions.setCollapsedEvents,
62
+ );
63
+
64
+ // Normalize Events in a flattened filtered list
65
+ const { eventNodes, defaultCollapsedIds } = useMemo(() => {
66
+ // Apply fixups to the event string
67
+ const resolvedEvents = fixupEventStream(events, !running);
68
+
69
+ // Build the event tree
70
+ const eventTree = treeifyEvents(resolvedEvents, 0);
71
+
72
+ // Apply collapse filters to the event tree
73
+ const defaultCollapsedIds: Record<string, true> = {};
74
+ const findCollapsibleEvents = (nodes: EventNode[]) => {
75
+ for (const node of nodes) {
76
+ if (
77
+ (node.event.event === "step" ||
78
+ node.event.event === "span_begin" ||
79
+ node.event.event === "tool" ||
80
+ node.event.event === "subtask") &&
81
+ collapseFilters.some((filter) =>
82
+ filter(
83
+ node.event as
84
+ | StepEvent
85
+ | SpanBeginEvent
86
+ | ToolEvent
87
+ | SubtaskEvent,
88
+ ),
89
+ )
90
+ ) {
91
+ defaultCollapsedIds[node.id] = true;
92
+ }
93
+
94
+ // Recursively check children
95
+ findCollapsibleEvents(node.children);
96
+ }
97
+ };
98
+ findCollapsibleEvents(eventTree);
99
+
100
+ // flattten the event tree
101
+ const eventNodes = flatTree(
102
+ eventTree,
103
+ collapsedEvents || defaultCollapsedIds,
104
+ );
105
+
106
+ return { eventNodes, defaultCollapsedIds };
107
+ }, [events, running, collapsedEvents]);
108
+
109
+ // Update the collapsed events when the default collapsed IDs change
110
+ // This effect only depends on defaultCollapsedIds, not eventNodes
111
+ useEffect(() => {
112
+ // Only initialize collapsedEvents if it's empty
113
+ if (!collapsedEvents && Object.keys(defaultCollapsedIds).length > 0) {
114
+ setCollapsedEvents(defaultCollapsedIds);
115
+ }
116
+ }, [defaultCollapsedIds, collapsedEvents, setCollapsedEvents]);
117
+
118
+ return (
119
+ <TranscriptVirtualListComponent
120
+ id={id}
121
+ eventNodes={eventNodes}
122
+ initialEventId={initialEventId}
123
+ scrollRef={scrollRef}
124
+ running={running}
125
+ />
126
+ );
127
+ },
128
+ );
129
+
130
+ const collapseFilters: Array<
131
+ (event: StepEvent | SpanBeginEvent | ToolEvent | SubtaskEvent) => boolean
132
+ > = [
133
+ (event: StepEvent | SpanBeginEvent | ToolEvent | SubtaskEvent) =>
134
+ event.type === "solver" && event.name === "system_message",
135
+ (event: StepEvent | SpanBeginEvent | ToolEvent | SubtaskEvent) => {
136
+ if (event.event === "step" || event.event === "span_begin") {
137
+ return (
138
+ event.name === kSandboxSignalName ||
139
+ event.name === "init" ||
140
+ event.name === "sample_init"
141
+ );
142
+ }
143
+ return false;
144
+ },
145
+ (event: StepEvent | SpanBeginEvent | ToolEvent | SubtaskEvent) =>
146
+ event.event === "tool" && !event.agent && !event.failed,
147
+ (event: StepEvent | SpanBeginEvent | ToolEvent | SubtaskEvent) =>
148
+ event.event === "subtask",
149
+ ];
150
+
151
+ interface RenderedEventNodeProps {
152
+ node: EventNode;
153
+ className?: string | string[];
154
+ }
155
+ /**
156
+ * Renders the event based on its type.
157
+ */
158
+ export const RenderedEventNode: FC<RenderedEventNodeProps> = memo(
159
+ ({ node, className }) => {
160
+ switch (node.event.event) {
161
+ case "sample_init":
162
+ return (
163
+ <SampleInitEventView
164
+ eventNode={node as EventNode<SampleInitEvent>}
165
+ className={className}
166
+ />
167
+ );
168
+
169
+ case "sample_limit":
170
+ return (
171
+ <SampleLimitEventView
172
+ eventNode={node as EventNode<SampleLimitEvent>}
173
+ className={className}
174
+ />
175
+ );
176
+
177
+ case "info":
178
+ return (
179
+ <InfoEventView
180
+ eventNode={node as EventNode<InfoEvent>}
181
+ className={className}
182
+ />
183
+ );
184
+
185
+ case "logger":
186
+ return (
187
+ <LoggerEventView
188
+ eventNode={node as EventNode<LoggerEvent>}
189
+ className={className}
190
+ />
191
+ );
192
+
193
+ case "model":
194
+ return (
195
+ <ModelEventView
196
+ eventNode={node as EventNode<ModelEvent>}
197
+ className={className}
198
+ />
199
+ );
200
+
201
+ case "score":
202
+ return (
203
+ <ScoreEventView
204
+ eventNode={node as EventNode<ScoreEvent>}
205
+ className={className}
206
+ />
207
+ );
208
+
209
+ case "state":
210
+ return (
211
+ <StateEventView
212
+ eventNode={node as EventNode<StateEvent>}
213
+ className={className}
214
+ />
215
+ );
216
+
217
+ case "span_begin":
218
+ return (
219
+ <SpanEventView
220
+ eventNode={node as EventNode<SpanBeginEvent>}
221
+ children={node.children}
222
+ className={className}
223
+ />
224
+ );
225
+
226
+ case "step":
227
+ return (
228
+ <StepEventView
229
+ eventNode={node as EventNode<StepEvent>}
230
+ children={node.children}
231
+ className={className}
232
+ />
233
+ );
234
+
235
+ case "store":
236
+ return (
237
+ <StateEventView
238
+ eventNode={node as EventNode<StoreEvent>}
239
+ className={className}
240
+ />
241
+ );
242
+
243
+ case "subtask":
244
+ return (
245
+ <SubtaskEventView
246
+ eventNode={node as EventNode<SubtaskEvent>}
247
+ className={className}
248
+ children={node.children}
249
+ />
250
+ );
251
+
252
+ case "tool":
253
+ return (
254
+ <ToolEventView
255
+ eventNode={node as EventNode<ToolEvent>}
256
+ className={className}
257
+ children={node.children}
258
+ />
259
+ );
260
+
261
+ case "input":
262
+ return (
263
+ <InputEventView
264
+ eventNode={node as EventNode<InputEvent>}
265
+ className={className}
266
+ />
267
+ );
268
+
269
+ case "error":
270
+ return (
271
+ <ErrorEventView
272
+ eventNode={node as EventNode<ErrorEvent>}
273
+ className={className}
274
+ />
275
+ );
276
+
277
+ case "approval":
278
+ return (
279
+ <ApprovalEventView
280
+ eventNode={node as EventNode<ApprovalEvent>}
281
+ className={className}
282
+ />
283
+ );
284
+
285
+ case "sandbox":
286
+ return (
287
+ <SandboxEventView
288
+ eventNode={node as EventNode<SandboxEvent>}
289
+ className={className}
290
+ />
291
+ );
292
+
293
+ default:
294
+ return null;
295
+ }
296
+ },
297
+ );
@@ -1,11 +1,3 @@
1
- .darkenedBg {
2
- background-color: var(--bs-light-bg-subtle);
3
- }
4
-
5
- .normalBg {
6
- background-color: var(--bs-body-bg);
7
- }
8
-
9
1
  .node {
10
2
  padding-top: 0.7rem;
11
3
  padding-bottom: 1px;
@@ -1,6 +1,6 @@
1
1
  import clsx from "clsx";
2
- import { FC, RefObject, useCallback } from "react";
3
- import { RenderedEventNode } from "./TranscriptView";
2
+ import { FC, RefObject, useCallback, useMemo } from "react";
3
+ import { RenderedEventNode } from "./TranscriptVirtualList";
4
4
  import { EventNode } from "./types";
5
5
 
6
6
  import { LiveVirtualList } from "../../../components/LiveVirtualList";
@@ -9,6 +9,7 @@ import styles from "./TranscriptVirtualListComponent.module.css";
9
9
  interface TranscriptVirtualListComponentProps {
10
10
  id: string;
11
11
  eventNodes: EventNode[];
12
+ initialEventId?: string | null;
12
13
  scrollRef?: RefObject<HTMLDivElement | null>;
13
14
  running?: boolean;
14
15
  }
@@ -18,37 +19,54 @@ interface TranscriptVirtualListComponentProps {
18
19
  */
19
20
  export const TranscriptVirtualListComponent: FC<
20
21
  TranscriptVirtualListComponentProps
21
- > = ({ id, eventNodes, scrollRef, running }) => {
22
- const renderRow = useCallback((index: number, item: EventNode) => {
23
- const bgClass = item.depth % 2 == 0 ? styles.darkenedBg : styles.normalBg;
24
- const paddingClass = index === 0 ? styles.first : undefined;
22
+ > = ({ id, eventNodes, scrollRef, running, initialEventId }) => {
23
+ const initialEventIndex = useMemo(() => {
24
+ if (initialEventId === null || initialEventId === undefined) {
25
+ return undefined;
26
+ }
27
+ const result = eventNodes.findIndex((event) => {
28
+ return event.id === initialEventId;
29
+ });
30
+ return result === -1 ? undefined : result;
31
+ }, [initialEventId, eventNodes]);
25
32
 
26
- const eventId = `${id}-event-${index}`;
27
- const previousIndex = index - 1;
28
- const previous =
29
- previousIndex > 0 && previousIndex <= eventNodes.length
30
- ? eventNodes[previousIndex]
31
- : undefined;
32
- const attached =
33
- item.event.event === "tool" &&
34
- (previous?.event.event === "tool" || previous?.event.event === "model");
35
- const attachedClass = attached ? styles.attached : undefined;
33
+ const renderRow = useCallback(
34
+ (index: number, item: EventNode) => {
35
+ const paddingClass = index === 0 ? styles.first : undefined;
36
36
 
37
- return (
38
- <div
39
- key={eventId}
40
- className={clsx(styles.node, paddingClass, attachedClass)}
41
- >
42
- <RenderedEventNode id={eventId} node={item} className={clsx(bgClass)} />
43
- </div>
44
- );
45
- }, []);
37
+ const previousIndex = index - 1;
38
+ const previous =
39
+ previousIndex > 0 && previousIndex <= eventNodes.length
40
+ ? eventNodes[previousIndex]
41
+ : undefined;
42
+ const attached =
43
+ item.event.event === "tool" &&
44
+ (previous?.event.event === "tool" || previous?.event.event === "model");
45
+ const attachedClass = attached ? styles.attached : undefined;
46
+
47
+ return (
48
+ <div
49
+ id={item.id}
50
+ key={item.id}
51
+ className={clsx(styles.node, paddingClass, attachedClass)}
52
+ style={{
53
+ paddingLeft: `${item.depth <= 1 ? item.depth * 0.7 : (0.7 + item.depth - 1) * 1}em`,
54
+ paddingRight: `${item.depth === 0 ? undefined : ".7em"} `,
55
+ }}
56
+ >
57
+ <RenderedEventNode node={item} />
58
+ </div>
59
+ );
60
+ },
61
+ [eventNodes],
62
+ );
46
63
 
47
64
  return (
48
65
  <LiveVirtualList<EventNode>
49
66
  id={id}
50
67
  scrollRef={scrollRef}
51
68
  data={eventNodes}
69
+ initialTopMostItemIndex={initialEventIndex}
52
70
  renderRow={renderRow}
53
71
  live={running}
54
72
  />
@@ -10,6 +10,8 @@
10
10
  }
11
11
 
12
12
  .card {
13
+ position: relative;
14
+ background-color: var(--bs-body-bg);
13
15
  padding: 0.625rem;
14
16
  border: solid 1px var(--bs-light-border-subtle);
15
17
  border-radius: var(--bs-border-radius);
@@ -23,3 +25,44 @@
23
25
  .cardContent.hidden {
24
26
  display: none;
25
27
  }
28
+
29
+ .hidden {
30
+ display: none;
31
+ }
32
+
33
+ .copyLink {
34
+ font-size: 1.2em;
35
+ opacity: 0;
36
+ padding-left: 0.2em;
37
+ padding-right: 2em;
38
+ }
39
+
40
+ .hover .copyLink {
41
+ opacity: 1;
42
+ }
43
+
44
+ .root {
45
+ background-color: var(--bs-light-bg-subtle);
46
+ border-radius: unset;
47
+ }
48
+
49
+ .bottomDongle {
50
+ display: block;
51
+ position: absolute;
52
+ margin: 0 auto;
53
+ width: fit-content;
54
+ bottom: -10px;
55
+ left: 50%;
56
+ transform: translateX(-50%);
57
+ background-color: var(--bs-body-bg);
58
+ border: solid 1px var(--bs-light-border-subtle);
59
+ color: var(--bs-secondary);
60
+
61
+ border-radius: var(--bs-border-radius);
62
+ padding: 0em 0.4em;
63
+ cursor: pointer;
64
+ }
65
+
66
+ .dongleIcon {
67
+ padding-right: 0.3em;
68
+ }