inspect-ai 0.3.70__py3-none-any.whl → 0.3.72__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 (219) hide show
  1. inspect_ai/_cli/eval.py +14 -8
  2. inspect_ai/_display/core/display.py +2 -0
  3. inspect_ai/_display/core/footer.py +13 -3
  4. inspect_ai/_display/plain/display.py +6 -2
  5. inspect_ai/_display/rich/display.py +19 -6
  6. inspect_ai/_display/textual/app.py +6 -1
  7. inspect_ai/_display/textual/display.py +4 -0
  8. inspect_ai/_display/textual/widgets/transcript.py +10 -6
  9. inspect_ai/_eval/task/run.py +5 -8
  10. inspect_ai/_util/content.py +20 -1
  11. inspect_ai/_util/transcript.py +10 -4
  12. inspect_ai/_util/working.py +4 -0
  13. inspect_ai/_view/www/App.css +6 -0
  14. inspect_ai/_view/www/dist/assets/index.css +115 -87
  15. inspect_ai/_view/www/dist/assets/index.js +5324 -2276
  16. inspect_ai/_view/www/eslint.config.mjs +24 -1
  17. inspect_ai/_view/www/log-schema.json +283 -20
  18. inspect_ai/_view/www/package.json +8 -3
  19. inspect_ai/_view/www/src/App.tsx +2 -2
  20. inspect_ai/_view/www/src/components/AnsiDisplay.tsx +4 -3
  21. inspect_ai/_view/www/src/components/Card.tsx +9 -8
  22. inspect_ai/_view/www/src/components/DownloadButton.tsx +2 -1
  23. inspect_ai/_view/www/src/components/EmptyPanel.tsx +2 -2
  24. inspect_ai/_view/www/src/components/ErrorPanel.tsx +4 -3
  25. inspect_ai/_view/www/src/components/ExpandablePanel.tsx +13 -5
  26. inspect_ai/_view/www/src/components/FindBand.tsx +3 -3
  27. inspect_ai/_view/www/src/components/HumanBaselineView.tsx +3 -3
  28. inspect_ai/_view/www/src/components/LabeledValue.tsx +5 -4
  29. inspect_ai/_view/www/src/components/LargeModal.tsx +18 -13
  30. inspect_ai/_view/www/src/components/{LightboxCarousel.css → LightboxCarousel.module.css} +22 -18
  31. inspect_ai/_view/www/src/components/LightboxCarousel.tsx +36 -27
  32. inspect_ai/_view/www/src/components/MessageBand.tsx +2 -1
  33. inspect_ai/_view/www/src/components/NavPills.tsx +9 -8
  34. inspect_ai/_view/www/src/components/ProgressBar.tsx +2 -1
  35. inspect_ai/_view/www/src/components/TabSet.tsx +21 -15
  36. inspect_ai/_view/www/src/index.tsx +2 -2
  37. inspect_ai/_view/www/src/metadata/MetaDataGrid.tsx +11 -9
  38. inspect_ai/_view/www/src/metadata/MetaDataView.tsx +3 -2
  39. inspect_ai/_view/www/src/metadata/MetadataGrid.module.css +1 -0
  40. inspect_ai/_view/www/src/metadata/RenderedContent.tsx +16 -0
  41. inspect_ai/_view/www/src/plan/DatasetDetailView.tsx +3 -2
  42. inspect_ai/_view/www/src/plan/DetailStep.tsx +2 -1
  43. inspect_ai/_view/www/src/plan/PlanCard.tsx +2 -5
  44. inspect_ai/_view/www/src/plan/PlanDetailView.tsx +6 -9
  45. inspect_ai/_view/www/src/plan/ScorerDetailView.tsx +2 -1
  46. inspect_ai/_view/www/src/plan/SolverDetailView.tsx +3 -3
  47. inspect_ai/_view/www/src/samples/InlineSampleDisplay.tsx +2 -2
  48. inspect_ai/_view/www/src/samples/SampleDialog.tsx +3 -3
  49. inspect_ai/_view/www/src/samples/SampleDisplay.tsx +2 -2
  50. inspect_ai/_view/www/src/samples/SampleSummaryView.tsx +2 -2
  51. inspect_ai/_view/www/src/samples/SamplesTools.tsx +2 -1
  52. inspect_ai/_view/www/src/samples/chat/ChatMessage.tsx +3 -19
  53. inspect_ai/_view/www/src/samples/chat/ChatMessageRenderer.tsx +2 -1
  54. inspect_ai/_view/www/src/samples/chat/ChatMessageRow.tsx +2 -1
  55. inspect_ai/_view/www/src/samples/chat/ChatView.tsx +2 -1
  56. inspect_ai/_view/www/src/samples/chat/ChatViewVirtualList.tsx +22 -7
  57. inspect_ai/_view/www/src/samples/chat/MessageContent.tsx +35 -6
  58. inspect_ai/_view/www/src/samples/chat/MessageContents.tsx +2 -2
  59. inspect_ai/_view/www/src/samples/chat/messages.ts +15 -2
  60. inspect_ai/_view/www/src/samples/chat/tools/ToolCallView.tsx +13 -4
  61. inspect_ai/_view/www/src/samples/chat/tools/ToolInput.module.css +2 -2
  62. inspect_ai/_view/www/src/samples/chat/tools/ToolInput.tsx +18 -19
  63. inspect_ai/_view/www/src/samples/chat/tools/ToolOutput.module.css +1 -1
  64. inspect_ai/_view/www/src/samples/chat/tools/ToolOutput.tsx +4 -3
  65. inspect_ai/_view/www/src/samples/chat/tools/ToolTitle.tsx +2 -2
  66. inspect_ai/_view/www/src/samples/error/FlatSampleErrorView.tsx +2 -3
  67. inspect_ai/_view/www/src/samples/error/SampleErrorView.tsx +3 -2
  68. inspect_ai/_view/www/src/samples/list/SampleFooter.tsx +2 -1
  69. inspect_ai/_view/www/src/samples/list/SampleHeader.tsx +2 -1
  70. inspect_ai/_view/www/src/samples/list/SampleList.tsx +57 -45
  71. inspect_ai/_view/www/src/samples/list/SampleRow.tsx +2 -1
  72. inspect_ai/_view/www/src/samples/list/SampleSeparator.tsx +2 -1
  73. inspect_ai/_view/www/src/samples/sample-tools/EpochFilter.tsx +2 -2
  74. inspect_ai/_view/www/src/samples/sample-tools/SelectScorer.tsx +4 -3
  75. inspect_ai/_view/www/src/samples/sample-tools/SortFilter.tsx +2 -5
  76. inspect_ai/_view/www/src/samples/sample-tools/sample-filter/SampleFilter.tsx +2 -2
  77. inspect_ai/_view/www/src/samples/scores/SampleScoreView.tsx +2 -1
  78. inspect_ai/_view/www/src/samples/scores/SampleScores.tsx +2 -2
  79. inspect_ai/_view/www/src/samples/transcript/ApprovalEventView.tsx +2 -1
  80. inspect_ai/_view/www/src/samples/transcript/ErrorEventView.tsx +2 -1
  81. inspect_ai/_view/www/src/samples/transcript/InfoEventView.tsx +2 -1
  82. inspect_ai/_view/www/src/samples/transcript/InputEventView.tsx +2 -1
  83. inspect_ai/_view/www/src/samples/transcript/LoggerEventView.module.css +4 -0
  84. inspect_ai/_view/www/src/samples/transcript/LoggerEventView.tsx +12 -2
  85. inspect_ai/_view/www/src/samples/transcript/ModelEventView.module.css +1 -1
  86. inspect_ai/_view/www/src/samples/transcript/ModelEventView.tsx +25 -28
  87. inspect_ai/_view/www/src/samples/transcript/SampleInitEventView.tsx +2 -1
  88. inspect_ai/_view/www/src/samples/transcript/SampleLimitEventView.tsx +5 -4
  89. inspect_ai/_view/www/src/samples/transcript/SampleTranscript.tsx +2 -2
  90. inspect_ai/_view/www/src/samples/transcript/SandboxEventView.tsx +8 -7
  91. inspect_ai/_view/www/src/samples/transcript/ScoreEventView.tsx +2 -2
  92. inspect_ai/_view/www/src/samples/transcript/StepEventView.tsx +3 -3
  93. inspect_ai/_view/www/src/samples/transcript/SubtaskEventView.tsx +18 -14
  94. inspect_ai/_view/www/src/samples/transcript/ToolEventView.tsx +5 -5
  95. inspect_ai/_view/www/src/samples/transcript/TranscriptView.tsx +34 -15
  96. inspect_ai/_view/www/src/samples/transcript/event/EventNav.tsx +2 -1
  97. inspect_ai/_view/www/src/samples/transcript/event/EventNavs.tsx +2 -1
  98. inspect_ai/_view/www/src/samples/transcript/event/EventRow.tsx +3 -2
  99. inspect_ai/_view/www/src/samples/transcript/event/EventSection.tsx +2 -2
  100. inspect_ai/_view/www/src/samples/transcript/event/EventTimingPanel.module.css +28 -0
  101. inspect_ai/_view/www/src/samples/transcript/event/EventTimingPanel.tsx +115 -0
  102. inspect_ai/_view/www/src/samples/transcript/event/utils.ts +29 -0
  103. inspect_ai/_view/www/src/samples/transcript/state/StateDiffView.tsx +2 -1
  104. inspect_ai/_view/www/src/samples/transcript/state/StateEventRenderers.tsx +3 -3
  105. inspect_ai/_view/www/src/samples/transcript/state/StateEventView.tsx +11 -8
  106. inspect_ai/_view/www/src/types/log.d.ts +129 -34
  107. inspect_ai/_view/www/src/usage/ModelTokenTable.tsx +6 -10
  108. inspect_ai/_view/www/src/usage/ModelUsagePanel.module.css +4 -0
  109. inspect_ai/_view/www/src/usage/ModelUsagePanel.tsx +32 -9
  110. inspect_ai/_view/www/src/usage/TokenTable.tsx +4 -6
  111. inspect_ai/_view/www/src/usage/UsageCard.tsx +2 -1
  112. inspect_ai/_view/www/src/utils/format.ts +1 -1
  113. inspect_ai/_view/www/src/utils/json.ts +24 -0
  114. inspect_ai/_view/www/src/workspace/WorkSpace.tsx +6 -5
  115. inspect_ai/_view/www/src/workspace/WorkSpaceView.tsx +9 -2
  116. inspect_ai/_view/www/src/workspace/error/TaskErrorPanel.tsx +2 -1
  117. inspect_ai/_view/www/src/workspace/navbar/Navbar.tsx +2 -1
  118. inspect_ai/_view/www/src/workspace/navbar/PrimaryBar.tsx +3 -3
  119. inspect_ai/_view/www/src/workspace/navbar/ResultsPanel.tsx +4 -3
  120. inspect_ai/_view/www/src/workspace/navbar/SecondaryBar.tsx +5 -4
  121. inspect_ai/_view/www/src/workspace/navbar/StatusPanel.tsx +5 -8
  122. inspect_ai/_view/www/src/workspace/sidebar/EvalStatus.tsx +5 -4
  123. inspect_ai/_view/www/src/workspace/sidebar/LogDirectoryTitleView.tsx +2 -1
  124. inspect_ai/_view/www/src/workspace/sidebar/Sidebar.tsx +2 -1
  125. inspect_ai/_view/www/src/workspace/sidebar/SidebarLogEntry.tsx +2 -2
  126. inspect_ai/_view/www/src/workspace/sidebar/SidebarScoreView.tsx +2 -1
  127. inspect_ai/_view/www/src/workspace/sidebar/SidebarScoresView.tsx +2 -2
  128. inspect_ai/_view/www/src/workspace/tabs/InfoTab.tsx +2 -2
  129. inspect_ai/_view/www/src/workspace/tabs/JsonTab.tsx +2 -5
  130. inspect_ai/_view/www/src/workspace/tabs/SamplesTab.tsx +12 -11
  131. inspect_ai/_view/www/yarn.lock +241 -5
  132. inspect_ai/log/_condense.py +3 -0
  133. inspect_ai/log/_recorders/eval.py +6 -1
  134. inspect_ai/log/_transcript.py +58 -1
  135. inspect_ai/model/__init__.py +2 -0
  136. inspect_ai/model/_call_tools.py +7 -0
  137. inspect_ai/model/_chat_message.py +22 -7
  138. inspect_ai/model/_conversation.py +10 -8
  139. inspect_ai/model/_generate_config.py +25 -4
  140. inspect_ai/model/_model.py +133 -57
  141. inspect_ai/model/_model_output.py +3 -0
  142. inspect_ai/model/_openai.py +106 -40
  143. inspect_ai/model/_providers/anthropic.py +281 -153
  144. inspect_ai/model/_providers/google.py +27 -8
  145. inspect_ai/model/_providers/groq.py +9 -4
  146. inspect_ai/model/_providers/openai.py +57 -4
  147. inspect_ai/model/_providers/openai_o1.py +10 -0
  148. inspect_ai/model/_providers/providers.py +1 -1
  149. inspect_ai/model/_reasoning.py +15 -2
  150. inspect_ai/scorer/_model.py +23 -19
  151. inspect_ai/solver/_human_agent/agent.py +14 -10
  152. inspect_ai/solver/_human_agent/commands/__init__.py +7 -3
  153. inspect_ai/solver/_human_agent/commands/submit.py +76 -30
  154. inspect_ai/tool/__init__.py +2 -0
  155. inspect_ai/tool/_tool.py +3 -1
  156. inspect_ai/tool/_tools/_computer/_common.py +117 -58
  157. inspect_ai/tool/_tools/_computer/_computer.py +80 -57
  158. inspect_ai/tool/_tools/_computer/_resources/image_home_dir/.config/Code/User/settings.json +7 -1
  159. inspect_ai/tool/_tools/_computer/_resources/image_home_dir/.config/xfce4/xfconf/xfce-perchannel-xml/xfwm4.xml +91 -0
  160. inspect_ai/tool/_tools/_computer/_resources/tool/.pylintrc +8 -0
  161. inspect_ai/tool/_tools/_computer/_resources/tool/.vscode/settings.json +12 -0
  162. inspect_ai/tool/_tools/_computer/_resources/tool/_args.py +78 -0
  163. inspect_ai/tool/_tools/_computer/_resources/tool/_constants.py +20 -0
  164. inspect_ai/tool/_tools/_computer/_resources/tool/_run.py +1 -1
  165. inspect_ai/tool/_tools/_computer/_resources/tool/_x11_client.py +175 -113
  166. inspect_ai/tool/_tools/_computer/_resources/tool/computer_tool.py +76 -20
  167. inspect_ai/tool/_tools/_computer/_resources/tool/pyproject.toml +65 -0
  168. inspect_ai/tool/_tools/_computer/test_args.py +151 -0
  169. inspect_ai/tool/_tools/_web_browser/_resources/.pylintrc +8 -0
  170. inspect_ai/tool/_tools/_web_browser/_resources/.vscode/launch.json +24 -0
  171. inspect_ai/tool/_tools/_web_browser/_resources/.vscode/settings.json +25 -0
  172. inspect_ai/tool/_tools/_web_browser/_resources/Dockerfile +5 -6
  173. inspect_ai/tool/_tools/_web_browser/_resources/README.md +10 -11
  174. inspect_ai/tool/_tools/_web_browser/_resources/accessibility_tree.py +71 -0
  175. inspect_ai/tool/_tools/_web_browser/_resources/accessibility_tree_node.py +323 -0
  176. inspect_ai/tool/_tools/_web_browser/_resources/cdp/__init__.py +5 -0
  177. inspect_ai/tool/_tools/_web_browser/_resources/cdp/a11y.py +279 -0
  178. inspect_ai/tool/_tools/_web_browser/_resources/cdp/dom.py +9 -0
  179. inspect_ai/tool/_tools/_web_browser/_resources/cdp/dom_snapshot.py +293 -0
  180. inspect_ai/tool/_tools/_web_browser/_resources/cdp/page.py +94 -0
  181. inspect_ai/tool/_tools/_web_browser/_resources/constants.py +2 -0
  182. inspect_ai/tool/_tools/_web_browser/_resources/images/usage_diagram.svg +2 -0
  183. inspect_ai/tool/_tools/_web_browser/_resources/playwright_browser.py +50 -0
  184. inspect_ai/tool/_tools/_web_browser/_resources/playwright_crawler.py +31 -359
  185. inspect_ai/tool/_tools/_web_browser/_resources/playwright_page_crawler.py +280 -0
  186. inspect_ai/tool/_tools/_web_browser/_resources/pyproject.toml +65 -0
  187. inspect_ai/tool/_tools/_web_browser/_resources/rectangle.py +64 -0
  188. inspect_ai/tool/_tools/_web_browser/_resources/rpc_client_helpers.py +146 -0
  189. inspect_ai/tool/_tools/_web_browser/_resources/scale_factor.py +64 -0
  190. inspect_ai/tool/_tools/_web_browser/_resources/test_accessibility_tree_node.py +180 -0
  191. inspect_ai/tool/_tools/_web_browser/_resources/test_playwright_crawler.py +15 -9
  192. inspect_ai/tool/_tools/_web_browser/_resources/test_rectangle.py +15 -0
  193. inspect_ai/tool/_tools/_web_browser/_resources/test_web_client.py +44 -0
  194. inspect_ai/tool/_tools/_web_browser/_resources/web_browser_rpc_types.py +39 -0
  195. inspect_ai/tool/_tools/_web_browser/_resources/web_client.py +198 -48
  196. inspect_ai/tool/_tools/_web_browser/_resources/web_client_new_session.py +26 -25
  197. inspect_ai/tool/_tools/_web_browser/_resources/web_server.py +178 -39
  198. inspect_ai/tool/_tools/_web_browser/_web_browser.py +38 -19
  199. inspect_ai/util/__init__.py +2 -1
  200. inspect_ai/util/_display.py +12 -0
  201. inspect_ai/util/_sandbox/events.py +55 -21
  202. inspect_ai/util/_sandbox/self_check.py +131 -43
  203. inspect_ai/util/_subtask.py +11 -0
  204. {inspect_ai-0.3.70.dist-info → inspect_ai-0.3.72.dist-info}/METADATA +1 -1
  205. {inspect_ai-0.3.70.dist-info → inspect_ai-0.3.72.dist-info}/RECORD +209 -186
  206. {inspect_ai-0.3.70.dist-info → inspect_ai-0.3.72.dist-info}/WHEEL +1 -1
  207. inspect_ai/_view/www/src/components/VirtualList.module.css +0 -19
  208. inspect_ai/_view/www/src/components/VirtualList.tsx +0 -292
  209. inspect_ai/tool/_tools/_computer/_computer_split.py +0 -198
  210. inspect_ai/tool/_tools/_web_browser/_resources/accessibility_node.py +0 -312
  211. inspect_ai/tool/_tools/_web_browser/_resources/dm_env_servicer.py +0 -275
  212. inspect_ai/tool/_tools/_web_browser/_resources/images/usage_diagram.png +0 -0
  213. inspect_ai/tool/_tools/_web_browser/_resources/test_accessibility_node.py +0 -176
  214. inspect_ai/tool/_tools/_web_browser/_resources/test_dm_env_servicer.py +0 -135
  215. inspect_ai/tool/_tools/_web_browser/_resources/test_web_environment.py +0 -71
  216. inspect_ai/tool/_tools/_web_browser/_resources/web_environment.py +0 -184
  217. {inspect_ai-0.3.70.dist-info → inspect_ai-0.3.72.dist-info}/LICENSE +0 -0
  218. {inspect_ai-0.3.70.dist-info → inspect_ai-0.3.72.dist-info}/entry_points.txt +0 -0
  219. {inspect_ai-0.3.70.dist-info → inspect_ai-0.3.72.dist-info}/top_level.txt +0 -0
@@ -1,12 +1,13 @@
1
- import { RefObject } from "react";
2
- import { VirtualList } from "../../components/VirtualList";
1
+ import { FC, RefObject, useState } from "react";
3
2
  import { Messages } from "../../types/log";
4
3
 
5
4
  import clsx from "clsx";
5
+ import { Virtuoso } from "react-virtuoso";
6
6
  import { ChatMessageRow } from "./ChatMessageRow";
7
- import styles from "./ChatViewVirtualList.module.css";
8
7
  import { ResolvedMessage, resolveMessages } from "./messages";
9
8
 
9
+ import styles from "./ChatViewVirtualList.module.css";
10
+
10
11
  interface ChatViewVirtualListProps {
11
12
  id?: string;
12
13
  messages: Messages;
@@ -20,7 +21,7 @@ interface ChatViewVirtualListProps {
20
21
  /**
21
22
  * Renders the ChatViewVirtualList component.
22
23
  */
23
- export const ChatViewVirtualList: React.FC<ChatViewVirtualListProps> = ({
24
+ export const ChatViewVirtualList: FC<ChatViewVirtualListProps> = ({
24
25
  id,
25
26
  messages,
26
27
  toolCallStyle,
@@ -30,6 +31,7 @@ export const ChatViewVirtualList: React.FC<ChatViewVirtualListProps> = ({
30
31
  scrollRef,
31
32
  }) => {
32
33
  const collapsedMessages = resolveMessages(messages);
34
+ const [followOutput, setFollowOutput] = useState(false);
33
35
 
34
36
  const renderRow = (item: ResolvedMessage, index: number) => {
35
37
  const number =
@@ -46,10 +48,23 @@ export const ChatViewVirtualList: React.FC<ChatViewVirtualListProps> = ({
46
48
  };
47
49
 
48
50
  const result = (
49
- <VirtualList
51
+ <Virtuoso
52
+ customScrollParent={scrollRef?.current ? scrollRef.current : undefined}
53
+ style={{ height: "100%", width: "100%" }}
50
54
  data={collapsedMessages}
51
- renderRow={renderRow}
52
- scrollRef={scrollRef}
55
+ itemContent={(index: number, data: ResolvedMessage) => {
56
+ return renderRow(data, index);
57
+ }}
58
+ increaseViewportBy={{ top: 1000, bottom: 1000 }}
59
+ overscan={{
60
+ main: 10,
61
+ reverse: 10,
62
+ }}
63
+ followOutput={followOutput}
64
+ atBottomStateChange={(atBottom: boolean) => {
65
+ setFollowOutput(atBottom);
66
+ }}
67
+ skipAnimationFrameInResizeObserver={true}
53
68
  className={clsx(styles.list, className)}
54
69
  />
55
70
  );
@@ -1,8 +1,12 @@
1
+ import clsx from "clsx";
2
+ import { FC, Fragment, ReactNode } from "react";
3
+ import ExpandablePanel from "../../components/ExpandablePanel";
1
4
  import { MarkdownDiv } from "../../components/MarkdownDiv";
2
5
  import { ContentTool } from "../../types";
3
6
  import {
4
7
  ContentAudio,
5
8
  ContentImage,
9
+ ContentReasoning,
6
10
  ContentText,
7
11
  ContentVideo,
8
12
  Format,
@@ -15,6 +19,7 @@ type ContentType =
15
19
  | string
16
20
  | string[]
17
21
  | ContentText
22
+ | ContentReasoning
18
23
  | ContentImage
19
24
  | ContentAudio
20
25
  | ContentVideo
@@ -26,6 +31,7 @@ interface MessageContentProps {
26
31
  | string[]
27
32
  | (
28
33
  | ContentText
34
+ | ContentReasoning
29
35
  | ContentImage
30
36
  | ContentAudio
31
37
  | ContentVideo
@@ -37,7 +43,7 @@ interface MessageContentProps {
37
43
  * Renders message content based on its type.
38
44
  * Supports rendering strings, images, and tools using specific renderers.
39
45
  */
40
- export const MessageContent: React.FC<MessageContentProps> = ({ contents }) => {
46
+ export const MessageContent: FC<MessageContentProps> = ({ contents }) => {
41
47
  if (Array.isArray(contents)) {
42
48
  return contents.map((content, index) => {
43
49
  if (typeof content === "string") {
@@ -79,11 +85,7 @@ export const MessageContent: React.FC<MessageContentProps> = ({ contents }) => {
79
85
  };
80
86
 
81
87
  interface MessageRenderer {
82
- render: (
83
- key: string,
84
- content: ContentType,
85
- isLast: boolean,
86
- ) => React.ReactNode;
88
+ render: (key: string, content: ContentType, isLast: boolean) => ReactNode;
87
89
  }
88
90
 
89
91
  const messageRenderers: Record<string, MessageRenderer> = {
@@ -99,6 +101,33 @@ const messageRenderers: Record<string, MessageRenderer> = {
99
101
  );
100
102
  },
101
103
  },
104
+ reasoning: {
105
+ render: (key, content, isLast) => {
106
+ const r = content as ContentReasoning;
107
+ return (
108
+ <Fragment key={key}>
109
+ <div
110
+ className={clsx(
111
+ "text-style-label",
112
+ "text-style-secondary",
113
+ isLast ? "no-last-para-padding" : "",
114
+ )}
115
+ >
116
+ Reasoning
117
+ </div>
118
+ <ExpandablePanel collapse={true}>
119
+ <MarkdownDiv
120
+ markdown={
121
+ r.redacted
122
+ ? "Reasoning encrypted by model provider."
123
+ : r.reasoning
124
+ }
125
+ />
126
+ </ExpandablePanel>
127
+ </Fragment>
128
+ );
129
+ },
130
+ },
102
131
  image: {
103
132
  render: (key, content) => {
104
133
  const c = content as ContentImage;
@@ -8,7 +8,7 @@ import { MessageContent } from "./MessageContent";
8
8
  import { resolveToolInput } from "./tools/tool";
9
9
  import { ToolCallView } from "./tools/ToolCallView";
10
10
 
11
- import { Fragment } from "react";
11
+ import { FC, Fragment } from "react";
12
12
  import { ContentTool } from "../../types";
13
13
  import styles from "./MessageContents.module.css";
14
14
 
@@ -18,7 +18,7 @@ interface MessageContentsProps {
18
18
  toolCallStyle: "compact" | "complete";
19
19
  }
20
20
 
21
- export const MessageContents: React.FC<MessageContentsProps> = ({
21
+ export const MessageContents: FC<MessageContentsProps> = ({
22
22
  message,
23
23
  toolMessages,
24
24
  toolCallStyle,
@@ -6,6 +6,7 @@ import {
6
6
  ChatMessageUser,
7
7
  ContentAudio,
8
8
  ContentImage,
9
+ ContentReasoning,
9
10
  ContentText,
10
11
  ContentVideo,
11
12
  Messages,
@@ -54,6 +55,7 @@ export const resolveMessages = (messages: Messages) => {
54
55
  | ContentImage
55
56
  | ContentAudio
56
57
  | ContentVideo
58
+ | ContentReasoning
57
59
  )[] = [];
58
60
  for (const systemMessage of systemMessages) {
59
61
  const contents = Array.isArray(systemMessage.content)
@@ -99,8 +101,19 @@ export const iconForMsg = (
99
101
  * Normalize strings
100
102
  */
101
103
  const normalizeContent = (
102
- content: ContentText | ContentImage | ContentAudio | ContentVideo | string,
103
- ): ContentText | ContentImage | ContentAudio | ContentVideo => {
104
+ content:
105
+ | ContentText
106
+ | ContentImage
107
+ | ContentAudio
108
+ | ContentVideo
109
+ | ContentReasoning
110
+ | string,
111
+ ):
112
+ | ContentText
113
+ | ContentImage
114
+ | ContentAudio
115
+ | ContentVideo
116
+ | ContentReasoning => {
104
117
  if (typeof content === "string") {
105
118
  return {
106
119
  type: "text",
@@ -1,9 +1,10 @@
1
- import { useMemo } from "react";
1
+ import { FC, useMemo } from "react";
2
2
  import ExpandablePanel from "../../../components/ExpandablePanel";
3
3
  import { ContentTool } from "../../../types";
4
4
  import {
5
5
  ContentAudio,
6
6
  ContentImage,
7
+ ContentReasoning,
7
8
  ContentText,
8
9
  ContentVideo,
9
10
  ToolCallContent,
@@ -26,12 +27,14 @@ interface ToolCallViewProps {
26
27
  | ContentImage
27
28
  | ContentVideo
28
29
  | ContentTool
30
+ | ContentReasoning
29
31
  | (
30
32
  | ContentText
31
33
  | ContentAudio
32
34
  | ContentImage
33
35
  | ContentVideo
34
36
  | ContentTool
37
+ | ContentReasoning
35
38
  )[];
36
39
  mode?: "compact";
37
40
  }
@@ -39,7 +42,7 @@ interface ToolCallViewProps {
39
42
  /**
40
43
  * Renders the ToolCallView component.
41
44
  */
42
- export const ToolCallView: React.FC<ToolCallViewProps> = ({
45
+ export const ToolCallView: FC<ToolCallViewProps> = ({
43
46
  functionCall,
44
47
  input,
45
48
  highlightLanguage,
@@ -57,7 +60,8 @@ export const ToolCallView: React.FC<ToolCallViewProps> = ({
57
60
  | ContentAudio
58
61
  | ContentImage
59
62
  | ContentVideo
60
- | ContentTool,
63
+ | ContentTool
64
+ | ContentReasoning,
61
65
  ) {
62
66
  if (value && typeof value === "object") {
63
67
  if (value.type === "image") {
@@ -79,6 +83,8 @@ export const ToolCallView: React.FC<ToolCallViewProps> = ({
79
83
  : !isContentImage(output);
80
84
  const normalizedContent = useMemo(() => normalizeContent(output), [output]);
81
85
 
86
+ const contents = mode !== "compact" ? input : input || functionCall;
87
+
82
88
  return (
83
89
  <div>
84
90
  {mode !== "compact" && (!view || view.title) ? (
@@ -90,7 +96,7 @@ export const ToolCallView: React.FC<ToolCallViewProps> = ({
90
96
  <div>
91
97
  <ToolInput
92
98
  highlightLanguage={highlightLanguage}
93
- contents={input}
99
+ contents={contents}
94
100
  toolCallView={view}
95
101
  />
96
102
  <ExpandablePanel collapse={collapse} border={true} lines={15}>
@@ -115,12 +121,14 @@ const normalizeContent = (
115
121
  | ContentAudio
116
122
  | ContentVideo
117
123
  | ContentTool
124
+ | ContentReasoning
118
125
  | (
119
126
  | ContentText
120
127
  | ContentImage
121
128
  | ContentAudio
122
129
  | ContentVideo
123
130
  | ContentTool
131
+ | ContentReasoning
124
132
  )[],
125
133
  ): (
126
134
  | ContentText
@@ -128,6 +136,7 @@ const normalizeContent = (
128
136
  | ContentAudio
129
137
  | ContentVideo
130
138
  | ContentTool
139
+ | ContentReasoning
131
140
  )[] => {
132
141
  if (Array.isArray(output)) {
133
142
  return output;
@@ -9,6 +9,6 @@
9
9
  white-space: pre-wrap;
10
10
  }
11
11
 
12
- .bottomMargin {
13
- margin-bottom: 1em;
12
+ .bottomPadding {
13
+ padding-bottom: 1em;
14
14
  }
@@ -1,6 +1,6 @@
1
1
  import clsx from "clsx";
2
2
  import { highlightElement } from "prismjs";
3
- import { memo, useEffect, useRef } from "react";
3
+ import { FC, memo, useEffect, useRef } from "react";
4
4
  import { MarkdownDiv } from "../../../components/MarkdownDiv";
5
5
 
6
6
  import styles from "./ToolInput.module.css";
@@ -22,35 +22,34 @@ interface ToolInputProps {
22
22
  contents?: string | object;
23
23
  toolCallView?: { content: string };
24
24
  }
25
- export const ToolInput: React.FC<ToolInputProps> = memo((props) => {
25
+ export const ToolInput: FC<ToolInputProps> = memo((props) => {
26
26
  const { highlightLanguage, contents, toolCallView } = props;
27
27
 
28
28
  const codeRef = useCodeHighlight(highlightLanguage);
29
+ const toolViewRef = useRef<HTMLDivElement>(null);
30
+
31
+ useEffect(() => {
32
+ if (toolCallView?.content && toolViewRef.current) {
33
+ requestAnimationFrame(() => {
34
+ const codeBlocks = toolViewRef.current!.querySelectorAll("pre code");
35
+ codeBlocks.forEach((block) => {
36
+ if (block.className.includes("language-")) {
37
+ block.classList.add("sourceCode");
38
+ highlightElement(block as HTMLElement);
39
+ }
40
+ });
41
+ });
42
+ }
43
+ }, [toolCallView?.content]);
29
44
 
30
45
  if (!contents && !toolCallView?.content) return null;
31
46
 
32
47
  if (toolCallView) {
33
- const toolViewRef = useRef<HTMLDivElement>(null);
34
-
35
- useEffect(() => {
36
- if (toolCallView?.content && toolViewRef.current) {
37
- requestAnimationFrame(() => {
38
- const codeBlocks = toolViewRef.current!.querySelectorAll("pre code");
39
- codeBlocks.forEach((block) => {
40
- if (block.className.includes("language-")) {
41
- block.classList.add("sourceCode");
42
- highlightElement(block as HTMLElement);
43
- }
44
- });
45
- });
46
- }
47
- }, [toolCallView?.content]);
48
-
49
48
  return (
50
49
  <MarkdownDiv
51
50
  markdown={toolCallView.content}
52
51
  ref={toolViewRef}
53
- className={clsx(styles.bottomMargin, "text-size-small")}
52
+ className={clsx("text-size-small", "tool-output")}
54
53
  />
55
54
  );
56
55
  }
@@ -8,7 +8,7 @@
8
8
  }
9
9
 
10
10
  .textOutput {
11
- margin-left: 2px;
11
+ padding-left: 2px;
12
12
  padding: 0.5em 0.5em 0.5em 0.5em;
13
13
  white-space: pre-wrap;
14
14
  margin-bottom: 0;
@@ -1,4 +1,5 @@
1
1
  import clsx from "clsx";
2
+ import { FC } from "react";
2
3
  import { ContentImage, ContentText } from "../../../types/log";
3
4
  import styles from "./ToolOutput.module.css";
4
5
 
@@ -9,7 +10,7 @@ interface ToolOutputProps {
9
10
  /**
10
11
  * Renders the ToolOutput component.
11
12
  */
12
- export const ToolOutput: React.FC<ToolOutputProps> = ({ output }) => {
13
+ export const ToolOutput: FC<ToolOutputProps> = ({ output }) => {
13
14
  // If there is no output, don't show the tool
14
15
  if (!output) {
15
16
  return null;
@@ -51,9 +52,9 @@ interface ToolTextOutputProps {
51
52
  /**
52
53
  * Renders the ToolTextOutput component.
53
54
  */
54
- const ToolTextOutput: React.FC<ToolTextOutputProps> = ({ text }) => {
55
+ const ToolTextOutput: FC<ToolTextOutputProps> = ({ text }) => {
55
56
  return (
56
- <pre className={clsx(styles.textOutput)}>
57
+ <pre className={clsx(styles.textOutput, "tool-output")}>
57
58
  <code className={clsx("sourceCode", styles.textCode)}>{text.trim()}</code>
58
59
  </pre>
59
60
  );
@@ -1,5 +1,5 @@
1
1
  import clsx from "clsx";
2
- import { Fragment } from "react";
2
+ import { FC, Fragment } from "react";
3
3
  import styles from "./ToolTitle.module.css";
4
4
  interface ToolTitleProps {
5
5
  title: string;
@@ -8,7 +8,7 @@ interface ToolTitleProps {
8
8
  /**
9
9
  * Renders the ToolCallView component.
10
10
  */
11
- export const ToolTitle: React.FC<ToolTitleProps> = ({ title }) => {
11
+ export const ToolTitle: FC<ToolTitleProps> = ({ title }) => {
12
12
  return (
13
13
  <Fragment>
14
14
  <i className={clsx("bi", "bi-tools", styles.styles)} />
@@ -1,6 +1,7 @@
1
1
  import { ApplicationIcons } from "../../appearance/icons";
2
2
 
3
3
  import clsx from "clsx";
4
+ import { FC } from "react";
4
5
  import styles from "./FlatSampleErrorView.module.css";
5
6
  import { errorType } from "./error";
6
7
 
@@ -10,9 +11,7 @@ interface FlatSampleErrorViewProps {
10
11
  /**
11
12
  * Component to display a styled error message.
12
13
  */
13
- export const FlatSampleError: React.FC<FlatSampleErrorViewProps> = ({
14
- message,
15
- }) => {
14
+ export const FlatSampleError: FC<FlatSampleErrorViewProps> = ({ message }) => {
16
15
  return (
17
16
  <div className={clsx(styles.flatBody)}>
18
17
  <i className={clsx(ApplicationIcons.error, styles.iconSmall)} />
@@ -2,19 +2,20 @@ import { ApplicationIcons } from "../../appearance/icons";
2
2
  import { ApplicationStyles } from "../../appearance/styles";
3
3
 
4
4
  import clsx from "clsx";
5
+ import { CSSProperties, FC } from "react";
5
6
  import styles from "./SampleErrorView.module.css";
6
7
  import { errorType } from "./error";
7
8
 
8
9
  interface SampleErrorViewProps {
9
10
  message?: string;
10
11
  align?: string;
11
- style?: React.CSSProperties;
12
+ style?: CSSProperties;
12
13
  }
13
14
 
14
15
  /**
15
16
  * Component to display a styled error message.
16
17
  */
17
- export const SampleErrorView: React.FC<SampleErrorViewProps> = ({
18
+ export const SampleErrorView: FC<SampleErrorViewProps> = ({
18
19
  message,
19
20
  align,
20
21
  }) => {
@@ -3,9 +3,10 @@ interface SampleFooterProps {
3
3
  }
4
4
 
5
5
  import clsx from "clsx";
6
+ import { FC } from "react";
6
7
  import styles from "./SampleFooter.module.css";
7
8
 
8
- export const SampleFooter: React.FC<SampleFooterProps> = ({ sampleCount }) => {
9
+ export const SampleFooter: FC<SampleFooterProps> = ({ sampleCount }) => {
9
10
  return (
10
11
  <div className={clsx("text-size-smaller", styles.footer)}>
11
12
  <div>{sampleCount} Samples</div>
@@ -7,9 +7,10 @@ interface SampleHeaderProps {
7
7
  gridColumnsTemplate: string;
8
8
  }
9
9
  import clsx from "clsx";
10
+ import { FC } from "react";
10
11
  import styles from "./SampleHeader.module.css";
11
12
 
12
- export const SampleHeader: React.FC<SampleHeaderProps> = ({
13
+ export const SampleHeader: FC<SampleHeaderProps> = ({
13
14
  input = true,
14
15
  target = true,
15
16
  answer = true,
@@ -1,5 +1,5 @@
1
- import clsx from "clsx";
2
1
  import {
2
+ FC,
3
3
  KeyboardEvent,
4
4
  RefObject,
5
5
  useCallback,
@@ -8,15 +8,16 @@ import {
8
8
  useRef,
9
9
  useState,
10
10
  } from "react";
11
+ import { Virtuoso, VirtuosoHandle } from "react-virtuoso";
11
12
  import { EmptyPanel } from "../../components/EmptyPanel";
12
13
  import { MessageBand } from "../../components/MessageBand";
13
- import { VirtualList, VirtualListRef } from "../../components/VirtualList";
14
14
  import { formatNoDecimal } from "../../utils/format";
15
15
  import { ListItem } from "../../workspace/tabs/types";
16
16
  import { SamplesDescriptor } from "../descriptor/samplesDescriptor";
17
17
  import { SampleRow } from "./SampleRow";
18
18
  import { SampleSeparator } from "./SampleSeparator";
19
19
 
20
+ import clsx from "clsx";
20
21
  import { SampleFooter } from "./SampleFooter";
21
22
  import { SampleHeader } from "./SampleHeader";
22
23
  import styles from "./SampleList.module.css";
@@ -25,7 +26,6 @@ const kSampleHeight = 88;
25
26
  const kSeparatorHeight = 24;
26
27
 
27
28
  interface SampleListProps {
28
- listRef: RefObject<VirtualListRef | null>;
29
29
  items: ListItem[];
30
30
  sampleDescriptor: SamplesDescriptor;
31
31
  selectedIndex: number;
@@ -33,11 +33,11 @@ interface SampleListProps {
33
33
  prevSample: () => void;
34
34
  showSample: (index: number) => void;
35
35
  className?: string | string[];
36
+ listHandle: RefObject<VirtuosoHandle | null>;
36
37
  }
37
38
 
38
- export const SampleList: React.FC<SampleListProps> = (props) => {
39
+ export const SampleList: FC<SampleListProps> = (props) => {
39
40
  const {
40
- listRef,
41
41
  items,
42
42
  sampleDescriptor,
43
43
  selectedIndex,
@@ -45,12 +45,10 @@ export const SampleList: React.FC<SampleListProps> = (props) => {
45
45
  prevSample,
46
46
  showSample,
47
47
  className,
48
+ listHandle,
48
49
  } = props;
49
50
 
50
- // If there are no samples, just display an empty state
51
- if (items.length === 0) {
52
- return <EmptyPanel>No Samples</EmptyPanel>;
53
- }
51
+ const [followOutput, setFollowOutput] = useState(false);
54
52
 
55
53
  const [hidden, setHidden] = useState(false);
56
54
  useEffect(() => {
@@ -70,16 +68,45 @@ export const SampleList: React.FC<SampleListProps> = (props) => {
70
68
 
71
69
  const prevSelectedIndexRef = useRef<number>(null);
72
70
  useEffect(() => {
73
- const listEl = listRef.current;
71
+ const listEl = listHandle.current;
74
72
  if (listEl) {
75
- const actualRowIndex = itemRowMapping[selectedIndex];
76
-
77
- const direction =
78
- actualRowIndex > (prevSelectedIndexRef.current || 0) ? "down" : "up";
79
- listRef.current?.scrollToIndex(actualRowIndex, direction);
80
- prevSelectedIndexRef.current = actualRowIndex;
73
+ requestAnimationFrame(() => {
74
+ setTimeout(() => {
75
+ const actualRowIndex = itemRowMapping[selectedIndex];
76
+ listEl.scrollToIndex(actualRowIndex);
77
+ prevSelectedIndexRef.current = actualRowIndex;
78
+ }, 10);
79
+ });
81
80
  }
82
- }, [selectedIndex, listRef, itemRowMapping]);
81
+ }, [selectedIndex, listHandle, itemRowMapping]);
82
+
83
+ const onkeydown = useCallback(
84
+ (e: KeyboardEvent<HTMLDivElement>) => {
85
+ switch (e.key) {
86
+ case "ArrowUp":
87
+ prevSample();
88
+ e.preventDefault();
89
+ e.stopPropagation();
90
+ break;
91
+ case "ArrowDown":
92
+ nextSample();
93
+ e.preventDefault();
94
+ e.stopPropagation();
95
+ break;
96
+ case "Enter":
97
+ showSample(selectedIndex);
98
+ e.preventDefault();
99
+ e.stopPropagation();
100
+ break;
101
+ }
102
+ },
103
+ [selectedIndex, nextSample, prevSample, showSample],
104
+ );
105
+
106
+ // If there are no samples, just display an empty state
107
+ if (items.length === 0) {
108
+ return <EmptyPanel>No Samples</EmptyPanel>;
109
+ }
83
110
 
84
111
  const renderRow = (item: ListItem) => {
85
112
  if (item.type === "sample") {
@@ -108,29 +135,6 @@ export const SampleList: React.FC<SampleListProps> = (props) => {
108
135
  }
109
136
  };
110
137
 
111
- const onkeydown = useCallback(
112
- (e: KeyboardEvent<HTMLDivElement>) => {
113
- switch (e.key) {
114
- case "ArrowUp":
115
- prevSample();
116
- e.preventDefault();
117
- e.stopPropagation();
118
- break;
119
- case "ArrowDown":
120
- nextSample();
121
- e.preventDefault();
122
- e.stopPropagation();
123
- break;
124
- case "Enter":
125
- showSample(selectedIndex);
126
- e.preventDefault();
127
- e.stopPropagation();
128
- break;
129
- }
130
- },
131
- [selectedIndex],
132
- );
133
-
134
138
  const { input, limit, answer, target } = gridColumns(sampleDescriptor);
135
139
 
136
140
  const sampleCount = items?.reduce((prev, current) => {
@@ -186,13 +190,21 @@ export const SampleList: React.FC<SampleListProps> = (props) => {
186
190
  limit={limit !== "0"}
187
191
  gridColumnsTemplate={gridColumnsValue(sampleDescriptor)}
188
192
  />
189
- <VirtualList
190
- ref={listRef}
193
+ <Virtuoso
194
+ ref={listHandle}
195
+ style={{ height: "100%" }}
191
196
  data={items}
192
- tabIndex={0}
193
- renderRow={renderRow}
197
+ defaultItemHeight={50}
198
+ itemContent={(_index: number, data: ListItem) => {
199
+ return renderRow(data);
200
+ }}
201
+ followOutput={followOutput}
202
+ atBottomStateChange={(atBottom: boolean) => {
203
+ setFollowOutput(atBottom);
204
+ }}
205
+ className={clsx(className)}
194
206
  onKeyDown={onkeydown}
195
- className={clsx(styles.list, className)}
207
+ skipAnimationFrameInResizeObserver={true}
196
208
  />
197
209
  <SampleFooter sampleCount={sampleCount} />
198
210
  </div>
@@ -1,4 +1,5 @@
1
1
  import clsx from "clsx";
2
+ import { FC } from "react";
2
3
  import { SampleSummary } from "../../api/types";
3
4
  import { MarkdownDiv } from "../../components/MarkdownDiv";
4
5
  import { arrayToString, inputString } from "../../utils/format";
@@ -17,7 +18,7 @@ interface SampleRowProps {
17
18
  showSample: (index: number) => void;
18
19
  }
19
20
 
20
- export const SampleRow: React.FC<SampleRowProps> = ({
21
+ export const SampleRow: FC<SampleRowProps> = ({
21
22
  id,
22
23
  index,
23
24
  sample,
@@ -1,4 +1,5 @@
1
1
  import clsx from "clsx";
2
+ import { FC } from "react";
2
3
  import styles from "./SampleSeparator.module.css";
3
4
 
4
5
  interface SampleSeparatorProps {
@@ -7,7 +8,7 @@ interface SampleSeparatorProps {
7
8
  height: number;
8
9
  }
9
10
 
10
- export const SampleSeparator: React.FC<SampleSeparatorProps> = ({
11
+ export const SampleSeparator: FC<SampleSeparatorProps> = ({
11
12
  id,
12
13
  title,
13
14
  height,