@workflow/web-shared 5.0.0-beta.2 → 5.0.0-beta.20

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 (321) hide show
  1. package/dist/components/error-boundary.js +1 -1
  2. package/dist/components/event-list-view.d.ts +16 -1
  3. package/dist/components/event-list-view.d.ts.map +1 -1
  4. package/dist/components/event-list-view.js +196 -85
  5. package/dist/components/hook-actions.js +1 -1
  6. package/dist/components/index.d.ts +4 -0
  7. package/dist/components/index.d.ts.map +1 -1
  8. package/dist/components/index.js +5 -1
  9. package/dist/components/new-trace-viewer/components/copy-button.d.ts +9 -0
  10. package/dist/components/new-trace-viewer/components/copy-button.d.ts.map +1 -0
  11. package/dist/components/new-trace-viewer/components/copy-button.js +27 -0
  12. package/dist/components/new-trace-viewer/components/event-list.d.ts +10 -0
  13. package/dist/components/new-trace-viewer/components/event-list.d.ts.map +1 -0
  14. package/dist/components/new-trace-viewer/components/event-list.js +46 -0
  15. package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.d.ts +18 -0
  16. package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.d.ts.map +1 -0
  17. package/dist/components/new-trace-viewer/components/middle-truncate/copy-selection.js +54 -0
  18. package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.d.ts +20 -0
  19. package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.d.ts.map +1 -0
  20. package/dist/components/new-trace-viewer/components/middle-truncate/middle-truncate.js +81 -0
  21. package/dist/components/new-trace-viewer/components/middle-truncate/truncate.d.ts +25 -0
  22. package/dist/components/new-trace-viewer/components/middle-truncate/truncate.d.ts.map +1 -0
  23. package/dist/components/new-trace-viewer/components/middle-truncate/truncate.js +101 -0
  24. package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.d.ts +20 -0
  25. package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.d.ts.map +1 -0
  26. package/dist/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.js +114 -0
  27. package/dist/components/new-trace-viewer/components/span-markers.d.ts +46 -0
  28. package/dist/components/new-trace-viewer/components/span-markers.d.ts.map +1 -0
  29. package/dist/components/new-trace-viewer/components/span-markers.js +85 -0
  30. package/dist/components/new-trace-viewer/components/split-pane.d.ts +15 -0
  31. package/dist/components/new-trace-viewer/components/split-pane.d.ts.map +1 -0
  32. package/dist/components/new-trace-viewer/components/split-pane.js +105 -0
  33. package/dist/components/new-trace-viewer/components/timeline.d.ts +36 -0
  34. package/dist/components/new-trace-viewer/components/timeline.d.ts.map +1 -0
  35. package/dist/components/new-trace-viewer/components/timeline.js +254 -0
  36. package/dist/components/new-trace-viewer/components/timeline.module.css +46 -0
  37. package/dist/components/new-trace-viewer/components/trace-viewer-skeleton.d.ts +2 -0
  38. package/dist/components/new-trace-viewer/components/trace-viewer-skeleton.d.ts.map +1 -0
  39. package/dist/components/new-trace-viewer/components/trace-viewer-skeleton.js +19 -0
  40. package/dist/components/new-trace-viewer/components/use-row-window.d.ts +34 -0
  41. package/dist/components/new-trace-viewer/components/use-row-window.d.ts.map +1 -0
  42. package/dist/components/new-trace-viewer/components/use-row-window.js +107 -0
  43. package/dist/components/new-trace-viewer/context.d.ts +15 -0
  44. package/dist/components/new-trace-viewer/context.d.ts.map +1 -0
  45. package/dist/components/new-trace-viewer/context.js +47 -0
  46. package/dist/components/new-trace-viewer/icons.d.ts +6 -0
  47. package/dist/components/new-trace-viewer/icons.d.ts.map +1 -0
  48. package/dist/components/new-trace-viewer/icons.js +15 -0
  49. package/dist/components/new-trace-viewer/search.d.ts +19 -0
  50. package/dist/components/new-trace-viewer/search.d.ts.map +1 -0
  51. package/dist/components/new-trace-viewer/search.js +134 -0
  52. package/dist/components/new-trace-viewer/trace-viewer.d.ts +11 -0
  53. package/dist/components/new-trace-viewer/trace-viewer.d.ts.map +1 -0
  54. package/dist/components/new-trace-viewer/trace-viewer.js +462 -0
  55. package/dist/components/new-trace-viewer/types.d.ts +3 -0
  56. package/dist/components/new-trace-viewer/types.d.ts.map +1 -0
  57. package/dist/components/new-trace-viewer/types.js +2 -0
  58. package/dist/components/new-trace-viewer/utils.d.ts +61 -0
  59. package/dist/components/new-trace-viewer/utils.d.ts.map +1 -0
  60. package/dist/components/new-trace-viewer/utils.js +345 -0
  61. package/dist/components/run-trace-view.js +1 -1
  62. package/dist/components/sidebar/attribute-panel.d.ts.map +1 -1
  63. package/dist/components/sidebar/attribute-panel.js +129 -102
  64. package/dist/components/sidebar/attributes-block.d.ts +28 -0
  65. package/dist/components/sidebar/attributes-block.d.ts.map +1 -0
  66. package/dist/components/sidebar/attributes-block.js +81 -0
  67. package/dist/components/sidebar/conversation-view.js +1 -1
  68. package/dist/components/sidebar/copyable-data-block.d.ts +1 -0
  69. package/dist/components/sidebar/copyable-data-block.d.ts.map +1 -1
  70. package/dist/components/sidebar/copyable-data-block.js +16 -15
  71. package/dist/components/sidebar/detail-card.d.ts +5 -6
  72. package/dist/components/sidebar/detail-card.d.ts.map +1 -1
  73. package/dist/components/sidebar/detail-card.js +32 -16
  74. package/dist/components/sidebar/entity-detail-panel.d.ts +1 -3
  75. package/dist/components/sidebar/entity-detail-panel.d.ts.map +1 -1
  76. package/dist/components/sidebar/entity-detail-panel.js +17 -35
  77. package/dist/components/sidebar/events-list.d.ts +3 -1
  78. package/dist/components/sidebar/events-list.d.ts.map +1 -1
  79. package/dist/components/sidebar/events-list.js +36 -22
  80. package/dist/components/sidebar/resolve-hook-modal.js +1 -1
  81. package/dist/components/sidebar/sidebar-data-context.d.ts +29 -0
  82. package/dist/components/sidebar/sidebar-data-context.d.ts.map +1 -0
  83. package/dist/components/sidebar/sidebar-data-context.js +19 -0
  84. package/dist/components/sidebar/span-detail-merge.d.ts +16 -0
  85. package/dist/components/sidebar/span-detail-merge.d.ts.map +1 -0
  86. package/dist/components/sidebar/span-detail-merge.js +53 -0
  87. package/dist/components/stream-viewer.d.ts +1 -1
  88. package/dist/components/stream-viewer.d.ts.map +1 -1
  89. package/dist/components/stream-viewer.js +3 -27
  90. package/dist/components/trace-viewer/components/map.js +1 -1
  91. package/dist/components/trace-viewer/components/markers.js +1 -1
  92. package/dist/components/trace-viewer/components/node.d.ts.map +1 -1
  93. package/dist/components/trace-viewer/components/node.js +2 -1
  94. package/dist/components/trace-viewer/components/search-input.js +1 -1
  95. package/dist/components/trace-viewer/components/search.js +1 -1
  96. package/dist/components/trace-viewer/components/span-content.js +1 -1
  97. package/dist/components/trace-viewer/components/span-detail-panel.js +1 -1
  98. package/dist/components/trace-viewer/components/span-segments.js +1 -1
  99. package/dist/components/trace-viewer/components/span-strategies.js +1 -1
  100. package/dist/components/trace-viewer/components/ui.js +1 -1
  101. package/dist/components/trace-viewer/components/zoom-button.js +1 -1
  102. package/dist/components/trace-viewer/components/zoom-icons.js +1 -1
  103. package/dist/components/trace-viewer/context.js +1 -1
  104. package/dist/components/trace-viewer/index.js +1 -1
  105. package/dist/components/trace-viewer/trace-viewer.js +1 -1
  106. package/dist/components/trace-viewer/trace-viewer.module.css +4 -4
  107. package/dist/components/trace-viewer/types.js +1 -1
  108. package/dist/components/trace-viewer/util/constants.js +1 -1
  109. package/dist/components/trace-viewer/util/scrollbar-width.js +1 -1
  110. package/dist/components/trace-viewer/util/timing.d.ts +3 -3
  111. package/dist/components/trace-viewer/util/timing.d.ts.map +1 -1
  112. package/dist/components/trace-viewer/util/timing.js +8 -11
  113. package/dist/components/trace-viewer/util/tree.js +1 -1
  114. package/dist/components/trace-viewer/util/use-immediate-style.js +1 -1
  115. package/dist/components/trace-viewer/util/use-streaming-spans.js +1 -1
  116. package/dist/components/trace-viewer/util/use-trackpad-zoom.js +1 -1
  117. package/dist/components/trace-viewer/worker.js +1 -1
  118. package/dist/components/trace-viewer-new.d.ts +14 -0
  119. package/dist/components/trace-viewer-new.d.ts.map +1 -0
  120. package/dist/components/trace-viewer-new.js +21 -0
  121. package/dist/components/ui/alert.js +1 -1
  122. package/dist/components/ui/button.d.ts +10 -0
  123. package/dist/components/ui/button.d.ts.map +1 -0
  124. package/dist/components/ui/button.js +46 -0
  125. package/dist/components/ui/card.js +1 -1
  126. package/dist/components/ui/context-card.d.ts +47 -0
  127. package/dist/components/ui/context-card.d.ts.map +1 -0
  128. package/dist/components/ui/context-card.js +471 -0
  129. package/dist/components/ui/data-inspector.d.ts +22 -0
  130. package/dist/components/ui/data-inspector.d.ts.map +1 -1
  131. package/dist/components/ui/data-inspector.js +103 -13
  132. package/dist/components/ui/decrypt-button.js +1 -1
  133. package/dist/components/ui/error-card.js +1 -1
  134. package/dist/components/ui/error-stack-block.d.ts +17 -10
  135. package/dist/components/ui/error-stack-block.d.ts.map +1 -1
  136. package/dist/components/ui/error-stack-block.js +49 -30
  137. package/dist/components/ui/icon-button.d.ts +19 -0
  138. package/dist/components/ui/icon-button.d.ts.map +1 -0
  139. package/dist/components/ui/icon-button.js +29 -0
  140. package/dist/components/ui/inspector-theme.d.ts +9 -10
  141. package/dist/components/ui/inspector-theme.d.ts.map +1 -1
  142. package/dist/components/ui/inspector-theme.js +39 -72
  143. package/dist/components/ui/kbd.d.ts +6 -0
  144. package/dist/components/ui/kbd.d.ts.map +1 -0
  145. package/dist/components/ui/kbd.js +6 -0
  146. package/dist/components/ui/load-more-button.js +1 -1
  147. package/dist/components/ui/menu-dropdown.js +1 -1
  148. package/dist/components/ui/skeleton.js +1 -1
  149. package/dist/components/ui/spinner.js +1 -1
  150. package/dist/components/ui/timestamp-tooltip.d.ts +34 -1
  151. package/dist/components/ui/timestamp-tooltip.d.ts.map +1 -1
  152. package/dist/components/ui/timestamp-tooltip.js +80 -132
  153. package/dist/components/ui/tooltip.d.ts +10 -0
  154. package/dist/components/ui/tooltip.d.ts.map +1 -0
  155. package/dist/components/ui/tooltip.js +12 -0
  156. package/dist/components/workflow-trace-view.d.ts +1 -3
  157. package/dist/components/workflow-trace-view.d.ts.map +1 -1
  158. package/dist/components/workflow-trace-view.js +11 -13
  159. package/dist/components/workflow-traces/event-colors.d.ts +1 -0
  160. package/dist/components/workflow-traces/event-colors.d.ts.map +1 -1
  161. package/dist/components/workflow-traces/event-colors.js +12 -1
  162. package/dist/components/workflow-traces/trace-colors.js +1 -1
  163. package/dist/components/workflow-traces/trace-span-construction.d.ts +2 -2
  164. package/dist/components/workflow-traces/trace-span-construction.d.ts.map +1 -1
  165. package/dist/components/workflow-traces/trace-span-construction.js +19 -5
  166. package/dist/components/workflow-traces/trace-time-utils.js +1 -1
  167. package/dist/hooks/use-dark-mode.js +1 -1
  168. package/dist/hooks/use-intersection-observer.d.ts +17 -0
  169. package/dist/hooks/use-intersection-observer.d.ts.map +1 -0
  170. package/dist/hooks/use-intersection-observer.js +29 -0
  171. package/dist/hooks/use-load-more-on-scroll.d.ts +21 -0
  172. package/dist/hooks/use-load-more-on-scroll.d.ts.map +1 -0
  173. package/dist/hooks/use-load-more-on-scroll.js +28 -0
  174. package/dist/hooks/use-reduced-motion.d.ts +10 -0
  175. package/dist/hooks/use-reduced-motion.d.ts.map +1 -0
  176. package/dist/hooks/use-reduced-motion.js +29 -0
  177. package/dist/index.d.ts +3 -1
  178. package/dist/index.d.ts.map +1 -1
  179. package/dist/index.js +3 -2
  180. package/dist/lib/event-analysis.js +1 -1
  181. package/dist/lib/event-materialization.js +1 -1
  182. package/dist/lib/exact-event-search-id.d.ts +25 -0
  183. package/dist/lib/exact-event-search-id.d.ts.map +1 -0
  184. package/dist/lib/exact-event-search-id.js +39 -0
  185. package/dist/lib/hydration.d.ts +6 -0
  186. package/dist/lib/hydration.d.ts.map +1 -1
  187. package/dist/lib/hydration.js +154 -2
  188. package/dist/lib/stream-display.d.ts +18 -0
  189. package/dist/lib/stream-display.d.ts.map +1 -0
  190. package/dist/lib/stream-display.js +30 -0
  191. package/dist/lib/toast.js +1 -1
  192. package/dist/lib/trace-builder.d.ts +15 -0
  193. package/dist/lib/trace-builder.d.ts.map +1 -1
  194. package/dist/lib/trace-builder.js +29 -3
  195. package/dist/lib/utils.d.ts +20 -9
  196. package/dist/lib/utils.d.ts.map +1 -1
  197. package/dist/lib/utils.js +74 -31
  198. package/dist/lib/zstd-browser-decoder.d.ts +7 -0
  199. package/dist/lib/zstd-browser-decoder.d.ts.map +1 -0
  200. package/dist/lib/zstd-browser-decoder.js +41 -0
  201. package/dist/styles.css +484 -1
  202. package/package.json +10 -5
  203. package/src/components/event-list-view.tsx +279 -104
  204. package/src/components/index.ts +7 -0
  205. package/src/components/new-trace-viewer/components/copy-button.tsx +68 -0
  206. package/src/components/new-trace-viewer/components/event-list.tsx +136 -0
  207. package/src/components/new-trace-viewer/components/middle-truncate/copy-selection.ts +114 -0
  208. package/src/components/new-trace-viewer/components/middle-truncate/middle-truncate.tsx +157 -0
  209. package/src/components/new-trace-viewer/components/middle-truncate/truncate.ts +132 -0
  210. package/src/components/new-trace-viewer/components/middle-truncate/use-middle-truncate.ts +167 -0
  211. package/src/components/new-trace-viewer/components/span-markers.tsx +173 -0
  212. package/src/components/new-trace-viewer/components/split-pane.tsx +198 -0
  213. package/src/components/new-trace-viewer/components/timeline.module.css +46 -0
  214. package/src/components/new-trace-viewer/components/timeline.tsx +744 -0
  215. package/src/components/new-trace-viewer/components/trace-viewer-skeleton.tsx +94 -0
  216. package/src/components/new-trace-viewer/components/use-row-window.ts +140 -0
  217. package/src/components/new-trace-viewer/context.tsx +90 -0
  218. package/src/components/new-trace-viewer/icons.tsx +79 -0
  219. package/src/components/new-trace-viewer/search.ts +178 -0
  220. package/src/components/new-trace-viewer/trace-viewer.tsx +843 -0
  221. package/src/components/new-trace-viewer/types.ts +2 -0
  222. package/src/components/new-trace-viewer/utils.test.ts +182 -0
  223. package/src/components/new-trace-viewer/utils.ts +519 -0
  224. package/src/components/sidebar/attribute-panel.tsx +194 -240
  225. package/src/components/sidebar/attributes-block.tsx +173 -0
  226. package/src/components/sidebar/copyable-data-block.tsx +49 -27
  227. package/src/components/sidebar/detail-card.tsx +119 -59
  228. package/src/components/sidebar/entity-detail-panel.tsx +55 -111
  229. package/src/components/sidebar/events-list.tsx +85 -96
  230. package/src/components/sidebar/sidebar-data-context.tsx +62 -0
  231. package/src/components/sidebar/span-detail-merge.ts +65 -0
  232. package/src/components/stream-viewer.tsx +18 -40
  233. package/src/components/trace-viewer/components/node.tsx +3 -2
  234. package/src/components/trace-viewer/trace-viewer.module.css +4 -4
  235. package/src/components/trace-viewer/util/timing.ts +7 -11
  236. package/src/components/trace-viewer-new.tsx +55 -0
  237. package/src/components/ui/button.tsx +68 -0
  238. package/src/components/ui/context-card.tsx +784 -0
  239. package/src/components/ui/data-inspector.tsx +244 -22
  240. package/src/components/ui/error-stack-block.tsx +84 -55
  241. package/src/components/ui/icon-button.tsx +53 -0
  242. package/src/components/ui/inspector-theme.ts +39 -81
  243. package/src/components/ui/kbd.tsx +21 -0
  244. package/src/components/ui/timestamp-tooltip.tsx +132 -194
  245. package/src/components/ui/tooltip.tsx +47 -0
  246. package/src/components/workflow-trace-view.tsx +19 -15
  247. package/src/components/workflow-traces/event-colors.ts +12 -0
  248. package/src/components/workflow-traces/trace-span-construction.ts +24 -5
  249. package/src/hooks/use-intersection-observer.ts +57 -0
  250. package/src/hooks/use-load-more-on-scroll.ts +49 -0
  251. package/src/hooks/use-reduced-motion.ts +34 -0
  252. package/src/index.ts +9 -0
  253. package/src/lib/exact-event-search-id.ts +67 -0
  254. package/src/lib/hydration.ts +166 -1
  255. package/src/lib/stream-display.ts +48 -0
  256. package/src/lib/trace-builder.ts +34 -2
  257. package/src/lib/utils.ts +83 -31
  258. package/src/lib/zstd-browser-decoder.ts +42 -0
  259. package/src/styles.css +484 -1
  260. package/dist/components/error-boundary.js.map +0 -1
  261. package/dist/components/event-list-view.js.map +0 -1
  262. package/dist/components/hook-actions.js.map +0 -1
  263. package/dist/components/index.js.map +0 -1
  264. package/dist/components/run-trace-view.js.map +0 -1
  265. package/dist/components/sidebar/attribute-panel.js.map +0 -1
  266. package/dist/components/sidebar/conversation-view.js.map +0 -1
  267. package/dist/components/sidebar/copyable-data-block.js.map +0 -1
  268. package/dist/components/sidebar/detail-card.js.map +0 -1
  269. package/dist/components/sidebar/entity-detail-panel.js.map +0 -1
  270. package/dist/components/sidebar/events-list.js.map +0 -1
  271. package/dist/components/sidebar/resolve-hook-modal.js.map +0 -1
  272. package/dist/components/stream-viewer.js.map +0 -1
  273. package/dist/components/trace-viewer/components/map.js.map +0 -1
  274. package/dist/components/trace-viewer/components/markers.js.map +0 -1
  275. package/dist/components/trace-viewer/components/node.js.map +0 -1
  276. package/dist/components/trace-viewer/components/search-input.js.map +0 -1
  277. package/dist/components/trace-viewer/components/search.js.map +0 -1
  278. package/dist/components/trace-viewer/components/span-content.js.map +0 -1
  279. package/dist/components/trace-viewer/components/span-detail-panel.js.map +0 -1
  280. package/dist/components/trace-viewer/components/span-segments.js.map +0 -1
  281. package/dist/components/trace-viewer/components/span-strategies.js.map +0 -1
  282. package/dist/components/trace-viewer/components/ui.js.map +0 -1
  283. package/dist/components/trace-viewer/components/zoom-button.js.map +0 -1
  284. package/dist/components/trace-viewer/components/zoom-icons.js.map +0 -1
  285. package/dist/components/trace-viewer/context.js.map +0 -1
  286. package/dist/components/trace-viewer/index.js.map +0 -1
  287. package/dist/components/trace-viewer/trace-viewer.js.map +0 -1
  288. package/dist/components/trace-viewer/types.js.map +0 -1
  289. package/dist/components/trace-viewer/util/constants.js.map +0 -1
  290. package/dist/components/trace-viewer/util/scrollbar-width.js.map +0 -1
  291. package/dist/components/trace-viewer/util/timing.js.map +0 -1
  292. package/dist/components/trace-viewer/util/tree.js.map +0 -1
  293. package/dist/components/trace-viewer/util/use-immediate-style.js.map +0 -1
  294. package/dist/components/trace-viewer/util/use-streaming-spans.js.map +0 -1
  295. package/dist/components/trace-viewer/util/use-trackpad-zoom.js.map +0 -1
  296. package/dist/components/trace-viewer/worker.js.map +0 -1
  297. package/dist/components/ui/alert.js.map +0 -1
  298. package/dist/components/ui/card.js.map +0 -1
  299. package/dist/components/ui/data-inspector.js.map +0 -1
  300. package/dist/components/ui/decrypt-button.js.map +0 -1
  301. package/dist/components/ui/error-card.js.map +0 -1
  302. package/dist/components/ui/error-stack-block.js.map +0 -1
  303. package/dist/components/ui/inspector-theme.js.map +0 -1
  304. package/dist/components/ui/load-more-button.js.map +0 -1
  305. package/dist/components/ui/menu-dropdown.js.map +0 -1
  306. package/dist/components/ui/skeleton.js.map +0 -1
  307. package/dist/components/ui/spinner.js.map +0 -1
  308. package/dist/components/ui/timestamp-tooltip.js.map +0 -1
  309. package/dist/components/workflow-trace-view.js.map +0 -1
  310. package/dist/components/workflow-traces/event-colors.js.map +0 -1
  311. package/dist/components/workflow-traces/trace-colors.js.map +0 -1
  312. package/dist/components/workflow-traces/trace-span-construction.js.map +0 -1
  313. package/dist/components/workflow-traces/trace-time-utils.js.map +0 -1
  314. package/dist/hooks/use-dark-mode.js.map +0 -1
  315. package/dist/index.js.map +0 -1
  316. package/dist/lib/event-analysis.js.map +0 -1
  317. package/dist/lib/event-materialization.js.map +0 -1
  318. package/dist/lib/hydration.js.map +0 -1
  319. package/dist/lib/toast.js.map +0 -1
  320. package/dist/lib/trace-builder.js.map +0 -1
  321. package/dist/lib/utils.js.map +0 -1
@@ -26,6 +26,11 @@ import {
26
26
  } from 'react-inspector';
27
27
  import { useDarkMode } from '../../hooks/use-dark-mode';
28
28
  import { ENCRYPTED_DISPLAY_NAME } from '../../lib/hydration';
29
+ import {
30
+ type DecodedStreamChunkSource,
31
+ type FormattedStreamChunkDisplay,
32
+ formatArrayBufferViewForDisplay,
33
+ } from '../../lib/stream-display';
29
34
  import {
30
35
  type InspectorThemeExtended,
31
36
  inspectorThemeDark,
@@ -33,6 +38,7 @@ import {
33
38
  inspectorThemeExtendedLight,
34
39
  inspectorThemeLight,
35
40
  } from './inspector-theme';
41
+ import { Button } from './button';
36
42
  import { Spinner } from './spinner';
37
43
 
38
44
  // ---------------------------------------------------------------------------
@@ -43,6 +49,7 @@ import { Spinner } from './spinner';
43
49
  const STREAM_REF_TYPE = '__workflow_stream_ref__';
44
50
  const CLASS_INSTANCE_REF_TYPE = '__workflow_class_instance_ref__';
45
51
  const RUN_REF_TYPE = '__workflow_run_ref__';
52
+ const BYTES_DISPLAY_TYPE = '__workflow_bytes_display__';
46
53
 
47
54
  interface StreamRef {
48
55
  __type: typeof STREAM_REF_TYPE;
@@ -54,6 +61,32 @@ interface RunRef {
54
61
  runId: string;
55
62
  }
56
63
 
64
+ interface BytesDisplay {
65
+ __type: typeof BYTES_DISPLAY_TYPE;
66
+ text: string;
67
+ decodedFrom?: DecodedStreamChunkSource;
68
+ }
69
+
70
+ function deserializeChunkText(text: string): string {
71
+ try {
72
+ const parsed = JSON.parse(text);
73
+ if (typeof parsed === 'string') {
74
+ return parsed;
75
+ }
76
+ return JSON.stringify(parsed, null, 2);
77
+ } catch {
78
+ return text;
79
+ }
80
+ }
81
+
82
+ function parseChunkData(text: string): unknown {
83
+ try {
84
+ return JSON.parse(text);
85
+ } catch {
86
+ return text;
87
+ }
88
+ }
89
+
57
90
  function isStreamRef(value: unknown): value is StreamRef {
58
91
  if (value === null || typeof value !== 'object') return false;
59
92
  // Check both enumerable and non-enumerable __type (opaque refs use non-enumerable)
@@ -67,6 +100,12 @@ function isRunRef(value: unknown): value is RunRef {
67
100
  return desc?.value === RUN_REF_TYPE;
68
101
  }
69
102
 
103
+ export function isBytesDisplay(value: unknown): value is BytesDisplay {
104
+ if (value === null || typeof value !== 'object') return false;
105
+ const desc = Object.getOwnPropertyDescriptor(value, '__type');
106
+ return desc?.value === BYTES_DISPLAY_TYPE;
107
+ }
108
+
70
109
  function isClassInstanceRef(value: unknown): value is {
71
110
  __type: string;
72
111
  className: string;
@@ -100,6 +139,7 @@ export const StreamClickContext = createContext<
100
139
  export type DecryptClickContextValue = {
101
140
  onDecrypt: () => void;
102
141
  isDecrypting: boolean;
142
+ hasEncryptedData?: boolean;
103
143
  };
104
144
 
105
145
  export const DecryptClickContext = createContext<
@@ -114,33 +154,22 @@ function EncryptedInlineLabel() {
114
154
  const ctx = useContext(DecryptClickContext);
115
155
  if (ctx) {
116
156
  return (
117
- <button
118
- type="button"
119
- className="inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-[11px] cursor-pointer"
120
- style={{
121
- backgroundColor: 'var(--ds-gray-100)',
122
- color: 'var(--ds-gray-700)',
123
- border: '1px solid var(--ds-gray-400)',
124
- fontStyle: 'italic',
125
- opacity: ctx.isDecrypting ? 0.6 : 1,
126
- }}
157
+ <Button
158
+ size="xs"
159
+ className="align-baseline gap-x-1"
127
160
  disabled={ctx.isDecrypting}
128
161
  onClick={(e) => {
129
162
  e.stopPropagation();
130
163
  ctx.onDecrypt();
131
164
  }}
132
- title="Click to decrypt"
133
165
  >
134
166
  {ctx.isDecrypting ? (
135
- <Spinner size={12} />
167
+ <Spinner size={10} />
136
168
  ) : (
137
- <Lock
138
- className="h-3 w-3"
139
- style={{ display: 'inline', flexShrink: 0 }}
140
- />
169
+ <Lock className="h-3 w-3" />
141
170
  )}
142
- <span>{ctx.isDecrypting ? 'Decrypting…' : 'Decrypt'}</span>
143
- </button>
171
+ <span>Decrypt</span>
172
+ </Button>
144
173
  );
145
174
  }
146
175
  return (
@@ -219,6 +248,147 @@ const ExtendedThemeContext = createContext<InspectorThemeExtended>(
219
248
  inspectorThemeExtendedLight
220
249
  );
221
250
 
251
+ function DecodedBytesChunk({
252
+ decodedText,
253
+ source,
254
+ }: {
255
+ decodedText: string;
256
+ source: DecodedStreamChunkSource;
257
+ }) {
258
+ const [selectedView, setSelectedView] = useState<'decoded' | 'bytes'>(
259
+ 'decoded'
260
+ );
261
+ const parsed = parseChunkData(decodedText);
262
+
263
+ return (
264
+ <div className="min-w-0">
265
+ {selectedView === 'decoded' ? (
266
+ <div className="min-w-0">
267
+ {typeof parsed === 'string' ? (
268
+ <span
269
+ className="whitespace-pre-wrap break-words"
270
+ style={{ color: 'var(--ds-gray-1000)' }}
271
+ >
272
+ {deserializeChunkText(parsed)}
273
+ </span>
274
+ ) : (
275
+ <DataInspector data={parsed} expandLevel={1} />
276
+ )}
277
+ </div>
278
+ ) : (
279
+ <DecodedBytesInspector decodedText={decodedText} source={source} />
280
+ )}
281
+ <div className="mt-2 flex">
282
+ <div
283
+ className="inline-flex overflow-hidden rounded border"
284
+ style={{ borderColor: 'var(--ds-gray-400)' }}
285
+ title={`${source.type} decoded as ${source.encoding.toUpperCase()} text. Switch to Bytes to inspect the summarized raw value.`}
286
+ >
287
+ <button
288
+ type="button"
289
+ className="h-5 px-1.5 text-[10px] font-medium"
290
+ style={{
291
+ backgroundColor:
292
+ selectedView === 'decoded'
293
+ ? 'var(--ds-gray-200)'
294
+ : 'var(--ds-gray-100)',
295
+ color: 'var(--ds-gray-900)',
296
+ }}
297
+ onClick={() => setSelectedView('decoded')}
298
+ aria-pressed={selectedView === 'decoded'}
299
+ aria-label="Show decoded text"
300
+ >
301
+ Decoded
302
+ </button>
303
+ <button
304
+ type="button"
305
+ className="h-5 border-l px-1.5 text-[10px] font-medium"
306
+ style={{
307
+ borderColor: 'var(--ds-gray-400)',
308
+ backgroundColor:
309
+ selectedView === 'bytes'
310
+ ? 'var(--ds-gray-200)'
311
+ : 'var(--ds-gray-100)',
312
+ color: 'var(--ds-gray-900)',
313
+ }}
314
+ onClick={() => setSelectedView('bytes')}
315
+ aria-pressed={selectedView === 'bytes'}
316
+ aria-label="Show raw bytes summary"
317
+ >
318
+ Bytes
319
+ </button>
320
+ </div>
321
+ </div>
322
+ </div>
323
+ );
324
+ }
325
+
326
+ function DecodedBytesInspector({
327
+ decodedText,
328
+ source,
329
+ }: {
330
+ decodedText: string;
331
+ source: DecodedStreamChunkSource;
332
+ }) {
333
+ const [expanded, setExpanded] = useState(false);
334
+
335
+ return (
336
+ <div className="font-mono">
337
+ <button
338
+ type="button"
339
+ className="flex max-w-full items-start gap-1 text-left"
340
+ style={{ color: 'var(--ds-gray-1000)' }}
341
+ onClick={() => setExpanded((value) => !value)}
342
+ title={`${source.type} decoded as ${source.encoding.toUpperCase()} text`}
343
+ >
344
+ <span className="select-none" style={{ color: 'var(--ds-gray-700)' }}>
345
+ {expanded ? '▼' : '▶'}
346
+ </span>
347
+ <span className="min-w-0 break-words">{source.rawSummary}</span>
348
+ </button>
349
+ {expanded && (
350
+ <div className="mt-1 pl-5">
351
+ <span style={{ color: 'var(--ds-gray-700)' }}>decoded: </span>
352
+ <span
353
+ className="whitespace-pre-wrap break-words"
354
+ style={{ color: 'var(--ds-green-900)' }}
355
+ >
356
+ {JSON.stringify(decodedText)}
357
+ </span>
358
+ </div>
359
+ )}
360
+ </div>
361
+ );
362
+ }
363
+
364
+ function BytesDisplayLabel({
365
+ name,
366
+ display,
367
+ }: {
368
+ name?: string;
369
+ display: BytesDisplay;
370
+ }) {
371
+ return (
372
+ <div className="inline-block min-w-0 align-top">
373
+ {name != null && <ObjectName name={name} />}
374
+ {name != null && <span>: </span>}
375
+ {display.decodedFrom ? (
376
+ <DecodedBytesChunk
377
+ decodedText={display.text}
378
+ source={display.decodedFrom}
379
+ />
380
+ ) : (
381
+ <span
382
+ className="whitespace-pre-wrap break-words"
383
+ style={{ color: 'var(--ds-gray-1000)' }}
384
+ >
385
+ {display.text}
386
+ </span>
387
+ )}
388
+ </div>
389
+ );
390
+ }
391
+
222
392
  // ---------------------------------------------------------------------------
223
393
  // Custom nodeRenderer
224
394
  // ---------------------------------------------------------------------------
@@ -248,6 +418,10 @@ function NodeRenderer({
248
418
  }) {
249
419
  const extendedTheme = useContext(ExtendedThemeContext);
250
420
 
421
+ if (isBytesDisplay(data)) {
422
+ return <BytesDisplayLabel name={name} display={data} />;
423
+ }
424
+
251
425
  // Encrypted marker → flat label with Lock icon, clickable when onDecrypt is available
252
426
  if (
253
427
  data !== null &&
@@ -352,18 +526,53 @@ function makeOpaqueRef(ref: Record<string, unknown>): unknown {
352
526
  return opaque;
353
527
  }
354
528
 
529
+ function makeBytesDisplay(display: FormattedStreamChunkDisplay): unknown {
530
+ const opaque = Object.create(null);
531
+ Object.defineProperty(opaque, '__type', {
532
+ value: BYTES_DISPLAY_TYPE,
533
+ enumerable: false,
534
+ });
535
+ Object.defineProperty(opaque, 'text', {
536
+ value: display.text,
537
+ enumerable: false,
538
+ });
539
+ Object.defineProperty(opaque, 'decodedFrom', {
540
+ value: display.decodedFrom,
541
+ enumerable: false,
542
+ });
543
+ return opaque;
544
+ }
545
+
355
546
  /**
356
- * Recursively walk data and replace RunRef/StreamRef objects with
547
+ * Recursively walk data and replace RunRef/StreamRef/typed array objects with
357
548
  * non-expandable versions so ObjectInspector doesn't show their internals.
358
549
  * Only recurses into plain objects and arrays to avoid stripping class
359
- * instances (Date, Error, Map, Set, URL, Headers, etc.) that have their
360
- * own rendering in NodeRenderer.
550
+ * instances (Date, Error, URL, Headers, etc.) that have their own rendering in
551
+ * NodeRenderer. Map and Set containers are preserved while their contents are
552
+ * prepared for display.
553
+ *
554
+ * Exported for testing the typed-array detection path used by hydrated
555
+ * AI agent stream chunks (e.g. `{ delta: new Uint8Array(...) }`).
361
556
  */
362
- function collapseRefs(data: unknown): unknown {
557
+ export function collapseRefs(data: unknown): unknown {
363
558
  if (data === null || typeof data !== 'object') return data;
559
+ if (ArrayBuffer.isView(data) && !(data instanceof DataView)) {
560
+ return makeBytesDisplay(formatArrayBufferViewForDisplay(data));
561
+ }
364
562
  if (isRunRef(data) || isStreamRef(data))
365
563
  return makeOpaqueRef(data as unknown as Record<string, unknown>);
366
564
  if (Array.isArray(data)) return data.map(collapseRefs);
565
+ if (data instanceof Map) {
566
+ return new Map(
567
+ Array.from(data.entries(), ([key, value]) => [
568
+ collapseRefs(key),
569
+ collapseRefs(value),
570
+ ])
571
+ );
572
+ }
573
+ if (data instanceof Set) {
574
+ return new Set(Array.from(data.values(), collapseRefs));
575
+ }
367
576
  // Only recurse into plain objects — leave class instances untouched
368
577
  const proto = Object.getPrototypeOf(data);
369
578
  if (proto !== Object.prototype && proto !== null) return data;
@@ -467,9 +676,22 @@ function isObjectLike(value: unknown): value is Record<string, unknown> {
467
676
  return typeof value === 'object' && value !== null;
468
677
  }
469
678
 
679
+ function isSameBytesDisplay(a: BytesDisplay, b: BytesDisplay): boolean {
680
+ return (
681
+ a.text === b.text &&
682
+ a.decodedFrom?.type === b.decodedFrom?.type &&
683
+ a.decodedFrom?.encoding === b.decodedFrom?.encoding &&
684
+ a.decodedFrom?.rawSummary === b.decodedFrom?.rawSummary
685
+ );
686
+ }
687
+
470
688
  function isDeepEqual(a: unknown, b: unknown, seen = new WeakMap()): boolean {
471
689
  if (Object.is(a, b)) return true;
472
690
 
691
+ if (isBytesDisplay(a) || isBytesDisplay(b)) {
692
+ return isBytesDisplay(a) && isBytesDisplay(b) && isSameBytesDisplay(a, b);
693
+ }
694
+
473
695
  if (a instanceof Date && b instanceof Date) {
474
696
  return a.getTime() === b.getTime();
475
697
  }
@@ -1,37 +1,73 @@
1
1
  'use client';
2
2
 
3
- import { AlertCircle, Copy } from 'lucide-react';
4
- import { useToast } from '../../lib/toast';
3
+ import { AlertCircle } from 'lucide-react';
4
+ import { CopyButton } from '../new-trace-viewer/components/copy-button';
5
+
6
+ export type StructuredErrorRecord = Record<string, unknown> & {
7
+ message?: string;
8
+ stack?: string;
9
+ };
5
10
 
6
11
  /**
7
- * Check whether `value` looks like a structured error object with a `stack`
8
- * field that we can render as pre-formatted text.
12
+ * Check whether `value` looks like a structured error object we can render
13
+ * with the error block. Some persisted workflow errors only include a
14
+ * `message`, while runtime errors usually also include `stack`.
9
15
  */
10
- export function isStructuredErrorWithStack(
16
+ export function isStructuredError(
11
17
  value: unknown
12
- ): value is Record<string, unknown> & { stack: string } {
18
+ ): value is StructuredErrorRecord {
13
19
  return (
14
20
  value != null &&
15
21
  typeof value === 'object' &&
16
- 'stack' in value &&
17
- typeof (value as Record<string, unknown>).stack === 'string'
22
+ (typeof (value as Record<string, unknown>).message === 'string' ||
23
+ typeof (value as Record<string, unknown>).stack === 'string')
24
+ );
25
+ }
26
+
27
+ /**
28
+ * Narrower guard kept for callers that specifically need a stack trace.
29
+ */
30
+ export function isStructuredErrorWithStack(
31
+ value: unknown
32
+ ): value is StructuredErrorRecord & { stack: string } {
33
+ return (
34
+ isStructuredError(value) &&
35
+ typeof (value as StructuredErrorRecord).stack === 'string'
18
36
  );
19
37
  }
20
38
 
21
39
  /**
22
- * Renders an error with a `stack` field as a visually distinct error block.
23
- * Shows the error message with an alert icon at the top, separated from
24
- * the stack trace below.
40
+ * Pull a short, single-line title out of an error message.
41
+ *
42
+ * Workflow's structured error messages are multi-line — the first line is
43
+ * the headline (`Failed to serialize step return value`) and the rest are
44
+ * `╰▶ hint:` / `╰▶ docs:` framed details. The full message belongs in the
45
+ * body of the error block; the title should just be the headline so the
46
+ * card stays scannable.
25
47
  */
26
- export function ErrorStackBlock({
27
- value,
28
- }: {
29
- value: Record<string, unknown> & { stack: string };
30
- }) {
31
- const toast = useToast();
32
- const stack = value.stack;
48
+ function deriveTitle(message: string): string {
49
+ const firstLine =
50
+ message.split('\n').find((line) => line.trim().length > 0) ?? message;
51
+ return firstLine.trim();
52
+ }
53
+
54
+ /**
55
+ * Renders a structured error as a visually distinct error block. Shows the
56
+ * error message with an alert icon at the top, separated from the stack trace
57
+ * or full message below.
58
+ */
59
+ export function ErrorStackBlock({ value }: { value: StructuredErrorRecord }) {
60
+ const stack = typeof value.stack === 'string' ? value.stack : undefined;
33
61
  const message = typeof value.message === 'string' ? value.message : undefined;
34
- const copyText = message ? `${message}\n\n${stack}` : stack;
62
+ const body = stack ?? message ?? '';
63
+ // V8's `Error.stack` already starts with `Name: message`; message-only
64
+ // errors use the message as the body so long single-line failures remain
65
+ // readable even when the header truncates.
66
+ const title = message ? deriveTitle(message) : deriveTitle(body);
67
+ const copyText =
68
+ message && stack && !stack.includes(message)
69
+ ? `${message}\n\n${stack}`
70
+ : body;
35
71
 
36
72
  return (
37
73
  <div
@@ -41,51 +77,44 @@ export function ErrorStackBlock({
41
77
  background: 'var(--ds-red-100)',
42
78
  }}
43
79
  >
44
- <button
45
- type="button"
46
- aria-label="Copy error"
47
- title="Copy"
48
- className="!absolute !right-2 !top-2 !flex !h-6 !w-6 !items-center !justify-center !rounded-md !border transition-transform transition-colors duration-100 hover:!bg-[var(--ds-red-200)] active:!scale-95"
49
- style={{
50
- borderColor: 'var(--ds-red-400)',
51
- background: 'var(--ds-red-100)',
52
- color: 'var(--ds-red-900)',
53
- }}
54
- onClick={() => {
55
- navigator.clipboard
56
- .writeText(copyText)
57
- .then(() => {
58
- toast.success('Copied to clipboard');
59
- })
60
- .catch(() => {
61
- toast.error('Failed to copy');
62
- });
63
- }}
64
- >
65
- <Copy size={12} />
66
- </button>
80
+ <CopyButton
81
+ copyText={copyText}
82
+ ariaLabel="Copy error"
83
+ className="absolute right-2 top-2 flex h-6 w-6 items-center justify-center rounded-md border border-red-400 bg-red-100 p-0 text-red-900 transition-transform transition-colors duration-100 hover:bg-red-200 active:scale-95"
84
+ />
67
85
 
68
- {message && (
86
+ {title && (
69
87
  <div
70
- className="flex items-start gap-2 px-3 py-2.5 pr-10"
88
+ className="flex items-center gap-2 px-3 py-2.5 pr-10"
71
89
  style={{
72
90
  color: 'var(--ds-red-900)',
73
91
  borderBottom: '1px solid var(--ds-red-400)',
74
92
  }}
75
93
  >
76
- <AlertCircle className="h-4 w-4 shrink-0" style={{ marginTop: 1 }} />
77
- <p className="text-xs font-semibold m-0 break-words">{message}</p>
94
+ <AlertCircle className="h-4 w-4 shrink-0" />
95
+ <p
96
+ className="text-xs font-semibold m-0 truncate"
97
+ // The full message or stack is in the body below; the header just
98
+ // shows the first line, single-line, with overflow
99
+ // ellipsised so a long title doesn't push the copy button or
100
+ // wrap into the framed hint/docs lines.
101
+ title={message}
102
+ >
103
+ {title}
104
+ </p>
78
105
  </div>
79
106
  )}
80
- <pre
81
- className="px-3 py-2.5 text-xs font-mono whitespace-pre-wrap break-words overflow-auto m-0"
82
- style={{
83
- color: 'var(--ds-red-900)',
84
- background: 'var(--ds-red-200)',
85
- }}
86
- >
87
- {stack}
88
- </pre>
107
+ {body && (
108
+ <pre
109
+ className="px-3 py-2.5 text-xs font-mono whitespace-pre-wrap break-words overflow-auto m-0"
110
+ style={{
111
+ color: 'var(--ds-red-900)',
112
+ background: 'var(--ds-red-200)',
113
+ }}
114
+ >
115
+ {body}
116
+ </pre>
117
+ )}
89
118
  </div>
90
119
  );
91
120
  }
@@ -0,0 +1,53 @@
1
+ import { cva, type VariantProps } from 'class-variance-authority';
2
+ import * as React from 'react';
3
+ import { cn } from '../../lib/utils';
4
+
5
+ const iconButtonVariants = cva(
6
+ [
7
+ 'm-0 inline-flex shrink-0 appearance-none items-center justify-center border-0 bg-transparent p-0 align-baseline font-inherit no-underline [background:none] [-webkit-appearance:none] [-webkit-tap-highlight-color:transparent]',
8
+ 'transition-colors duration-150 ease-in-out',
9
+ 'enabled:cursor-pointer disabled:cursor-not-allowed disabled:opacity-40',
10
+ 'focus-visible:outline focus-visible:outline-2 focus-visible:outline-[var(--ds-focus-color)] focus-visible:outline-offset-2',
11
+ ],
12
+ {
13
+ variants: {
14
+ variant: {
15
+ tertiary:
16
+ 'text-gray-900 enabled:hover:bg-gray-alpha-200 enabled:hover:text-gray-1000 enabled:active:bg-gray-alpha-200 focus-visible:text-gray-1000',
17
+ muted:
18
+ 'text-gray-900 enabled:hover:bg-gray-alpha-200 enabled:hover:text-gray-1000 enabled:active:bg-gray-alpha-200 focus-visible:text-gray-1000',
19
+ },
20
+ size: {
21
+ tiny: 'h-6 w-6 rounded-[4px] [&_svg]:h-4 [&_svg]:w-4',
22
+ small: 'h-8 w-8 rounded-md [&_svg]:h-4 [&_svg]:w-4',
23
+ },
24
+ },
25
+ defaultVariants: {
26
+ variant: 'tertiary',
27
+ size: 'tiny',
28
+ },
29
+ }
30
+ );
31
+
32
+ export type IconButtonProps = Omit<
33
+ React.ButtonHTMLAttributes<HTMLButtonElement>,
34
+ 'type'
35
+ > &
36
+ VariantProps<typeof iconButtonVariants> & {
37
+ 'aria-label': string;
38
+ type?: 'button' | 'submit' | 'reset';
39
+ };
40
+
41
+ export const IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>(
42
+ ({ className, variant, size, type = 'button', ...props }, ref) => (
43
+ <button
44
+ ref={ref}
45
+ type={type}
46
+ className={cn(iconButtonVariants({ variant, size, className }))}
47
+ {...props}
48
+ />
49
+ )
50
+ );
51
+ IconButton.displayName = 'IconButton';
52
+
53
+ export { iconButtonVariants };