inspect-ai 0.3.99__py3-none-any.whl → 0.3.101__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 (138) hide show
  1. inspect_ai/_cli/eval.py +2 -1
  2. inspect_ai/_display/core/config.py +11 -5
  3. inspect_ai/_display/core/panel.py +66 -2
  4. inspect_ai/_display/core/textual.py +5 -2
  5. inspect_ai/_display/plain/display.py +1 -0
  6. inspect_ai/_display/rich/display.py +2 -2
  7. inspect_ai/_display/textual/widgets/transcript.py +37 -9
  8. inspect_ai/_eval/eval.py +13 -1
  9. inspect_ai/_eval/evalset.py +3 -2
  10. inspect_ai/_eval/run.py +2 -0
  11. inspect_ai/_eval/score.py +2 -4
  12. inspect_ai/_eval/task/log.py +3 -1
  13. inspect_ai/_eval/task/run.py +59 -81
  14. inspect_ai/_util/content.py +11 -6
  15. inspect_ai/_util/interrupt.py +2 -2
  16. inspect_ai/_util/text.py +7 -0
  17. inspect_ai/_util/working.py +8 -37
  18. inspect_ai/_view/__init__.py +0 -0
  19. inspect_ai/_view/schema.py +2 -1
  20. inspect_ai/_view/www/CLAUDE.md +15 -0
  21. inspect_ai/_view/www/dist/assets/index.css +307 -171
  22. inspect_ai/_view/www/dist/assets/index.js +24733 -21641
  23. inspect_ai/_view/www/log-schema.json +77 -3
  24. inspect_ai/_view/www/package.json +9 -5
  25. inspect_ai/_view/www/src/@types/log.d.ts +9 -0
  26. inspect_ai/_view/www/src/app/App.tsx +1 -15
  27. inspect_ai/_view/www/src/app/appearance/icons.ts +4 -1
  28. inspect_ai/_view/www/src/app/content/MetaDataGrid.tsx +24 -6
  29. inspect_ai/_view/www/src/app/content/MetadataGrid.module.css +0 -5
  30. inspect_ai/_view/www/src/app/content/RenderedContent.tsx +220 -205
  31. inspect_ai/_view/www/src/app/log-view/LogViewContainer.tsx +2 -1
  32. inspect_ai/_view/www/src/app/log-view/tabs/SamplesTab.tsx +5 -0
  33. inspect_ai/_view/www/src/app/log-view/tabs/grouping.ts +4 -4
  34. inspect_ai/_view/www/src/app/routing/navigationHooks.ts +22 -25
  35. inspect_ai/_view/www/src/app/routing/url.ts +84 -4
  36. inspect_ai/_view/www/src/app/samples/InlineSampleDisplay.module.css +0 -5
  37. inspect_ai/_view/www/src/app/samples/SampleDialog.module.css +1 -1
  38. inspect_ai/_view/www/src/app/samples/SampleDisplay.module.css +7 -0
  39. inspect_ai/_view/www/src/app/samples/SampleDisplay.tsx +24 -17
  40. inspect_ai/_view/www/src/app/samples/SampleSummaryView.module.css +1 -2
  41. inspect_ai/_view/www/src/app/samples/chat/ChatMessage.tsx +8 -6
  42. inspect_ai/_view/www/src/app/samples/chat/ChatMessageRow.tsx +0 -4
  43. inspect_ai/_view/www/src/app/samples/chat/ChatViewVirtualList.tsx +3 -2
  44. inspect_ai/_view/www/src/app/samples/chat/MessageContent.tsx +2 -0
  45. inspect_ai/_view/www/src/app/samples/chat/MessageContents.tsx +2 -0
  46. inspect_ai/_view/www/src/app/samples/chat/messages.ts +1 -0
  47. inspect_ai/_view/www/src/app/samples/chat/tools/ToolCallView.tsx +1 -0
  48. inspect_ai/_view/www/src/app/samples/list/SampleList.tsx +17 -5
  49. inspect_ai/_view/www/src/app/samples/list/SampleRow.tsx +1 -1
  50. inspect_ai/_view/www/src/app/samples/transcript/ErrorEventView.tsx +1 -2
  51. inspect_ai/_view/www/src/app/samples/transcript/InfoEventView.tsx +1 -1
  52. inspect_ai/_view/www/src/app/samples/transcript/InputEventView.tsx +1 -2
  53. inspect_ai/_view/www/src/app/samples/transcript/ModelEventView.module.css +1 -1
  54. inspect_ai/_view/www/src/app/samples/transcript/ModelEventView.tsx +1 -1
  55. inspect_ai/_view/www/src/app/samples/transcript/SampleInitEventView.tsx +1 -1
  56. inspect_ai/_view/www/src/app/samples/transcript/SampleLimitEventView.tsx +3 -2
  57. inspect_ai/_view/www/src/app/samples/transcript/SandboxEventView.tsx +4 -5
  58. inspect_ai/_view/www/src/app/samples/transcript/ScoreEventView.tsx +1 -1
  59. inspect_ai/_view/www/src/app/samples/transcript/SpanEventView.tsx +1 -2
  60. inspect_ai/_view/www/src/app/samples/transcript/StepEventView.tsx +1 -3
  61. inspect_ai/_view/www/src/app/samples/transcript/SubtaskEventView.tsx +1 -2
  62. inspect_ai/_view/www/src/app/samples/transcript/ToolEventView.tsx +3 -4
  63. inspect_ai/_view/www/src/app/samples/transcript/TranscriptPanel.module.css +42 -0
  64. inspect_ai/_view/www/src/app/samples/transcript/TranscriptPanel.tsx +77 -0
  65. inspect_ai/_view/www/src/app/samples/transcript/TranscriptVirtualList.tsx +27 -71
  66. inspect_ai/_view/www/src/app/samples/transcript/TranscriptVirtualListComponent.module.css +13 -3
  67. inspect_ai/_view/www/src/app/samples/transcript/TranscriptVirtualListComponent.tsx +27 -2
  68. inspect_ai/_view/www/src/app/samples/transcript/event/EventPanel.module.css +1 -0
  69. inspect_ai/_view/www/src/app/samples/transcript/event/EventPanel.tsx +21 -22
  70. inspect_ai/_view/www/src/app/samples/transcript/outline/OutlineRow.module.css +45 -0
  71. inspect_ai/_view/www/src/app/samples/transcript/outline/OutlineRow.tsx +223 -0
  72. inspect_ai/_view/www/src/app/samples/transcript/outline/TranscriptOutline.module.css +10 -0
  73. inspect_ai/_view/www/src/app/samples/transcript/outline/TranscriptOutline.tsx +258 -0
  74. inspect_ai/_view/www/src/app/samples/transcript/outline/tree-visitors.ts +187 -0
  75. inspect_ai/_view/www/src/app/samples/transcript/state/StateEventRenderers.tsx +8 -1
  76. inspect_ai/_view/www/src/app/samples/transcript/state/StateEventView.tsx +3 -4
  77. inspect_ai/_view/www/src/app/samples/transcript/transform/hooks.ts +78 -0
  78. inspect_ai/_view/www/src/app/samples/transcript/transform/treeify.ts +340 -135
  79. inspect_ai/_view/www/src/app/samples/transcript/transform/utils.ts +3 -0
  80. inspect_ai/_view/www/src/app/samples/transcript/types.ts +2 -0
  81. inspect_ai/_view/www/src/app/types.ts +5 -1
  82. inspect_ai/_view/www/src/client/api/api-browser.ts +2 -2
  83. inspect_ai/_view/www/src/components/LiveVirtualList.tsx +6 -1
  84. inspect_ai/_view/www/src/components/MarkdownDiv.tsx +1 -1
  85. inspect_ai/_view/www/src/components/PopOver.tsx +422 -0
  86. inspect_ai/_view/www/src/components/PulsingDots.module.css +9 -9
  87. inspect_ai/_view/www/src/components/PulsingDots.tsx +4 -1
  88. inspect_ai/_view/www/src/components/StickyScroll.tsx +183 -0
  89. inspect_ai/_view/www/src/components/TabSet.tsx +4 -0
  90. inspect_ai/_view/www/src/state/hooks.ts +52 -2
  91. inspect_ai/_view/www/src/state/logSlice.ts +4 -3
  92. inspect_ai/_view/www/src/state/samplePolling.ts +8 -0
  93. inspect_ai/_view/www/src/state/sampleSlice.ts +53 -9
  94. inspect_ai/_view/www/src/state/scrolling.ts +152 -0
  95. inspect_ai/_view/www/src/utils/attachments.ts +7 -0
  96. inspect_ai/_view/www/src/utils/python.ts +18 -0
  97. inspect_ai/_view/www/yarn.lock +290 -33
  98. inspect_ai/agent/_react.py +12 -7
  99. inspect_ai/agent/_run.py +2 -3
  100. inspect_ai/analysis/beta/__init__.py +2 -0
  101. inspect_ai/analysis/beta/_dataframe/samples/table.py +19 -18
  102. inspect_ai/dataset/_sources/csv.py +2 -6
  103. inspect_ai/dataset/_sources/hf.py +2 -6
  104. inspect_ai/dataset/_sources/json.py +2 -6
  105. inspect_ai/dataset/_util.py +23 -0
  106. inspect_ai/log/_log.py +1 -1
  107. inspect_ai/log/_recorders/eval.py +4 -3
  108. inspect_ai/log/_recorders/file.py +2 -9
  109. inspect_ai/log/_recorders/json.py +1 -0
  110. inspect_ai/log/_recorders/recorder.py +1 -0
  111. inspect_ai/log/_transcript.py +1 -1
  112. inspect_ai/model/_call_tools.py +6 -2
  113. inspect_ai/model/_openai.py +1 -1
  114. inspect_ai/model/_openai_responses.py +85 -41
  115. inspect_ai/model/_openai_web_search.py +38 -0
  116. inspect_ai/model/_providers/azureai.py +72 -3
  117. inspect_ai/model/_providers/openai.py +4 -1
  118. inspect_ai/model/_providers/openai_responses.py +5 -1
  119. inspect_ai/scorer/_metric.py +1 -2
  120. inspect_ai/scorer/_reducer/reducer.py +1 -1
  121. inspect_ai/solver/_task_state.py +2 -2
  122. inspect_ai/tool/_tool.py +6 -2
  123. inspect_ai/tool/_tool_def.py +27 -4
  124. inspect_ai/tool/_tool_info.py +2 -0
  125. inspect_ai/tool/_tools/_web_search/_google.py +43 -15
  126. inspect_ai/tool/_tools/_web_search/_tavily.py +46 -13
  127. inspect_ai/tool/_tools/_web_search/_web_search.py +214 -45
  128. inspect_ai/util/__init__.py +4 -0
  129. inspect_ai/util/_json.py +3 -0
  130. inspect_ai/util/_limit.py +230 -20
  131. inspect_ai/util/_sandbox/docker/compose.py +20 -11
  132. inspect_ai/util/_span.py +1 -1
  133. {inspect_ai-0.3.99.dist-info → inspect_ai-0.3.101.dist-info}/METADATA +3 -3
  134. {inspect_ai-0.3.99.dist-info → inspect_ai-0.3.101.dist-info}/RECORD +138 -124
  135. {inspect_ai-0.3.99.dist-info → inspect_ai-0.3.101.dist-info}/WHEEL +1 -1
  136. {inspect_ai-0.3.99.dist-info → inspect_ai-0.3.101.dist-info}/entry_points.txt +0 -0
  137. {inspect_ai-0.3.99.dist-info → inspect_ai-0.3.101.dist-info}/licenses/LICENSE +0 -0
  138. {inspect_ai-0.3.99.dist-info → inspect_ai-0.3.101.dist-info}/top_level.txt +0 -0
@@ -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
+ });
@@ -2,7 +2,6 @@ import { FC, memo, RefObject, useEffect, useMemo } from "react";
2
2
  import {
3
3
  ApprovalEvent,
4
4
  ErrorEvent,
5
- Events,
6
5
  InfoEvent,
7
6
  InputEvent,
8
7
  LoggerEvent,
@@ -32,20 +31,22 @@ import { StateEventView } from "./state/StateEventView";
32
31
  import { StepEventView } from "./StepEventView";
33
32
  import { SubtaskEventView } from "./SubtaskEventView";
34
33
  import { ToolEventView } from "./ToolEventView";
35
- import { EventNode } from "./types";
34
+ import { EventNode, kTranscriptCollapseScope } from "./types";
36
35
 
37
36
  import { useStore } from "../../../state/store";
38
37
  import { SpanEventView } from "./SpanEventView";
39
38
  import { TranscriptVirtualListComponent } from "./TranscriptVirtualListComponent";
40
- import { fixupEventStream, kSandboxSignalName } from "./transform/fixups";
41
- import { flatTree, treeifyEvents } from "./transform/treeify";
39
+ import { flatTree } from "./transform/treeify";
42
40
 
43
41
  interface TranscriptVirtualListProps {
44
42
  id: string;
45
- events: Events;
43
+ eventNodes: EventNode[];
44
+ defaultCollapsedIds: Record<string, boolean>;
46
45
  initialEventId: string | null;
46
+ offsetTop?: number;
47
47
  scrollRef: RefObject<HTMLDivElement | null>;
48
48
  running?: boolean;
49
+ className?: string | string[];
49
50
  }
50
51
 
51
52
  /**
@@ -53,7 +54,16 @@ interface TranscriptVirtualListProps {
53
54
  */
54
55
  export const TranscriptVirtualList: FC<TranscriptVirtualListProps> = memo(
55
56
  (props) => {
56
- let { id, scrollRef, events, running, initialEventId } = props;
57
+ let {
58
+ id,
59
+ scrollRef,
60
+ eventNodes,
61
+ defaultCollapsedIds,
62
+ running,
63
+ initialEventId,
64
+ offsetTop,
65
+ className,
66
+ } = props;
57
67
 
58
68
  // The list of events that have been collapsed
59
69
  const collapsedEvents = useStore((state) => state.sample.collapsedEvents);
@@ -61,93 +71,39 @@ export const TranscriptVirtualList: FC<TranscriptVirtualListProps> = memo(
61
71
  (state) => state.sampleActions.setCollapsedEvents,
62
72
  );
63
73
 
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
-
74
+ const flattenedNodes = useMemo(() => {
100
75
  // flattten the event tree
101
- const eventNodes = flatTree(
102
- eventTree,
103
- collapsedEvents || defaultCollapsedIds,
76
+ return flatTree(
77
+ eventNodes,
78
+ (collapsedEvents
79
+ ? collapsedEvents[kTranscriptCollapseScope]
80
+ : undefined) || defaultCollapsedIds,
104
81
  );
105
-
106
- return { eventNodes, defaultCollapsedIds };
107
- }, [events, running, collapsedEvents]);
82
+ }, [eventNodes, collapsedEvents, defaultCollapsedIds]);
108
83
 
109
84
  // Update the collapsed events when the default collapsed IDs change
110
85
  // This effect only depends on defaultCollapsedIds, not eventNodes
111
86
  useEffect(() => {
112
87
  // Only initialize collapsedEvents if it's empty
113
88
  if (!collapsedEvents && Object.keys(defaultCollapsedIds).length > 0) {
114
- setCollapsedEvents(defaultCollapsedIds);
89
+ setCollapsedEvents(kTranscriptCollapseScope, defaultCollapsedIds);
115
90
  }
116
91
  }, [defaultCollapsedIds, collapsedEvents, setCollapsedEvents]);
117
92
 
118
93
  return (
119
94
  <TranscriptVirtualListComponent
120
95
  id={id}
121
- eventNodes={eventNodes}
96
+ eventNodes={flattenedNodes}
122
97
  initialEventId={initialEventId}
98
+ offsetTop={offsetTop}
123
99
  scrollRef={scrollRef}
124
100
  running={running}
101
+ className={className}
125
102
  />
126
103
  );
127
104
  },
128
105
  );
129
106
 
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
107
  interface RenderedEventNodeProps {
152
108
  node: EventNode;
153
109
  className?: string | string[];
@@ -1,9 +1,19 @@
1
1
  .node {
2
- padding-top: 0.7rem;
3
- padding-bottom: 1px;
2
+ padding-top: 0.8rem;
4
3
  }
5
4
 
6
5
  .attached {
7
6
  padding-top: 0rem;
8
- margin-top: -8px;
7
+ }
8
+
9
+ .attachedParent {
10
+ padding-bottom: 0px;
11
+ border-bottom-left-radius: 0;
12
+ border-bottom-right-radius: 0;
13
+ border-bottom: none;
14
+ }
15
+
16
+ .attachedChild {
17
+ border-top-left-radius: 0;
18
+ border-top-right-radius: 0;
9
19
  }
@@ -10,8 +10,10 @@ interface TranscriptVirtualListComponentProps {
10
10
  id: string;
11
11
  eventNodes: EventNode[];
12
12
  initialEventId?: string | null;
13
+ offsetTop?: number;
13
14
  scrollRef?: RefObject<HTMLDivElement | null>;
14
15
  running?: boolean;
16
+ className?: string | string[];
15
17
  }
16
18
 
17
19
  /**
@@ -19,7 +21,15 @@ interface TranscriptVirtualListComponentProps {
19
21
  */
20
22
  export const TranscriptVirtualListComponent: FC<
21
23
  TranscriptVirtualListComponentProps
22
- > = ({ id, eventNodes, scrollRef, running, initialEventId }) => {
24
+ > = ({
25
+ id,
26
+ eventNodes,
27
+ scrollRef,
28
+ running,
29
+ initialEventId,
30
+ offsetTop,
31
+ className,
32
+ }) => {
23
33
  const initialEventIndex = useMemo(() => {
24
34
  if (initialEventId === null || initialEventId === undefined) {
25
35
  return undefined;
@@ -35,14 +45,24 @@ export const TranscriptVirtualListComponent: FC<
35
45
  const paddingClass = index === 0 ? styles.first : undefined;
36
46
 
37
47
  const previousIndex = index - 1;
48
+ const nextIndex = index + 1;
38
49
  const previous =
39
50
  previousIndex > 0 && previousIndex <= eventNodes.length
40
51
  ? eventNodes[previousIndex]
41
52
  : undefined;
53
+ const next =
54
+ nextIndex < eventNodes.length ? eventNodes[nextIndex] : undefined;
42
55
  const attached =
43
56
  item.event.event === "tool" &&
44
57
  (previous?.event.event === "tool" || previous?.event.event === "model");
58
+
59
+ const attachedParent =
60
+ item.event.event === "model" && next?.event.event === "tool";
45
61
  const attachedClass = attached ? styles.attached : undefined;
62
+ const attachedChildClass = attached ? styles.attachedChild : undefined;
63
+ const attachedParentClass = attachedParent
64
+ ? styles.attachedParent
65
+ : undefined;
46
66
 
47
67
  return (
48
68
  <div
@@ -54,7 +74,10 @@ export const TranscriptVirtualListComponent: FC<
54
74
  paddingRight: `${item.depth === 0 ? undefined : ".7em"} `,
55
75
  }}
56
76
  >
57
- <RenderedEventNode node={item} />
77
+ <RenderedEventNode
78
+ node={item}
79
+ className={clsx(attachedParentClass, attachedChildClass)}
80
+ />
58
81
  </div>
59
82
  );
60
83
  },
@@ -63,10 +86,12 @@ export const TranscriptVirtualListComponent: FC<
63
86
 
64
87
  return (
65
88
  <LiveVirtualList<EventNode>
89
+ className={className}
66
90
  id={id}
67
91
  scrollRef={scrollRef}
68
92
  data={eventNodes}
69
93
  initialTopMostItemIndex={initialEventIndex}
94
+ offsetTop={offsetTop}
70
95
  renderRow={renderRow}
71
96
  live={running}
72
97
  />
@@ -32,6 +32,7 @@
32
32
 
33
33
  .copyLink {
34
34
  font-size: 1.2em;
35
+ height: 1em;
35
36
  opacity: 0;
36
37
  padding-left: 0.2em;
37
38
  padding-right: 2em;
@@ -10,18 +10,18 @@ import {
10
10
  import { ApplicationIcons } from "../../../appearance/icons";
11
11
  import { EventNavs } from "./EventNavs";
12
12
 
13
- import { useParams } from "react-router-dom";
14
13
  import { CopyButton } from "../../../../components/CopyButton";
15
14
  import { useCollapseSampleEvent, useProperty } from "../../../../state/hooks";
16
15
  import {
17
- sampleEventUrl,
18
16
  supportsLinking,
19
17
  toFullUrl,
18
+ useSampleEventUrl,
20
19
  } from "../../../routing/url";
20
+ import { kTranscriptCollapseScope } from "../types";
21
21
  import styles from "./EventPanel.module.css";
22
22
 
23
23
  interface EventPanelProps {
24
- id: string;
24
+ eventNodeId: string;
25
25
  depth: number;
26
26
  className?: string | string[];
27
27
  title?: string;
@@ -42,7 +42,7 @@ interface ChildProps {
42
42
  * Renders the StateEventView component.
43
43
  */
44
44
  export const EventPanel: FC<EventPanelProps> = ({
45
- id,
45
+ eventNodeId,
46
46
  depth,
47
47
  className,
48
48
  title,
@@ -54,26 +54,21 @@ export const EventPanel: FC<EventPanelProps> = ({
54
54
  collapsibleContent,
55
55
  collapseControl = "top",
56
56
  }) => {
57
- const [collapsed, setCollapsed] = useCollapseSampleEvent(id);
57
+ const [collapsed, setCollapsed] = useCollapseSampleEvent(
58
+ kTranscriptCollapseScope,
59
+ eventNodeId,
60
+ );
58
61
  const isCollapsible = (childIds || []).length > 0 || collapsibleContent;
59
62
  const useBottomDongle = isCollapsible && collapseControl === "bottom";
60
63
 
61
- // Get all URL parameters at component level
62
- const { logPath, sampleId, epoch } = useParams<{
63
- logPath?: string;
64
- tabId?: string;
65
- sampleId?: string;
66
- epoch?: string;
67
- }>();
68
-
64
+ const sampleEventUrl = useSampleEventUrl(eventNodeId);
69
65
  const url =
70
- logPath && supportsLinking()
71
- ? toFullUrl(sampleEventUrl(id, logPath, sampleId, epoch))
72
- : undefined;
66
+ supportsLinking() && sampleEventUrl ? toFullUrl(sampleEventUrl) : undefined;
73
67
 
74
68
  const pillId = (index: number) => {
75
- return `${id}-nav-pill-${index}`;
69
+ return `${eventNodeId}-nav-pill-${index}`;
76
70
  };
71
+
77
72
  const filteredArrChildren = (
78
73
  Array.isArray(children) ? children : [children]
79
74
  ).filter((child) => !!child);
@@ -83,9 +78,13 @@ export const EventPanel: FC<EventPanelProps> = ({
83
78
  });
84
79
  const defaultPillId = defaultPill !== -1 ? pillId(defaultPill) : pillId(0);
85
80
 
86
- const [selectedNav, setSelectedNav] = useProperty(id, "selectedNav", {
87
- defaultValue: defaultPillId,
88
- });
81
+ const [selectedNav, setSelectedNav] = useProperty(
82
+ eventNodeId,
83
+ "selectedNav",
84
+ {
85
+ defaultValue: defaultPillId,
86
+ },
87
+ );
89
88
 
90
89
  const gridColumns = [];
91
90
 
@@ -186,7 +185,7 @@ export const EventPanel: FC<EventPanelProps> = ({
186
185
  ? (child.props as ChildProps)["data-name"] || defaultTitle
187
186
  : defaultTitle;
188
187
  return {
189
- id: `eventpanel-${id}-${index}`,
188
+ id: `eventpanel-${eventNodeId}-${index}`,
190
189
  title: title,
191
190
  target: pillId(index),
192
191
  };
@@ -205,7 +204,7 @@ export const EventPanel: FC<EventPanelProps> = ({
205
204
 
206
205
  const card = (
207
206
  <div
208
- id={id}
207
+ id={`event-panel-${eventNodeId}`}
209
208
  className={clsx(
210
209
  className,
211
210
  styles.card,
@@ -0,0 +1,45 @@
1
+ .eventRow {
2
+ display: grid;
3
+ grid-template-columns: 10px 1fr;
4
+ column-gap: 3px;
5
+ cursor: pointer;
6
+ }
7
+
8
+ .eventRow.selected {
9
+ font-weight: 800;
10
+ }
11
+
12
+ .eventRow .toggle {
13
+ font-size: 0.7em;
14
+ margin-top: 4px;
15
+ }
16
+
17
+ .eventLink {
18
+ color: var(--bs-body);
19
+ text-decoration: none;
20
+ cursor: pointer;
21
+ }
22
+
23
+ .eventLink:hover {
24
+ text-decoration: underline;
25
+ color: var(--bs-link-hover-color);
26
+ }
27
+
28
+ .label {
29
+ white-space: nowrap;
30
+ overflow: hidden;
31
+ text-overflow: ellipsis;
32
+ }
33
+
34
+ .icon {
35
+ margin-right: 3px;
36
+ }
37
+
38
+ .progress {
39
+ margin-left: 0.3em !important;
40
+ }
41
+
42
+ .popover {
43
+ min-width: 300px;
44
+ max-width: 80%;
45
+ }