@theoremjs/react 0.0.0-stage → 0.3.1

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 (320) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +772 -2
  3. package/client/attachment-hover-preview.d.ts +11 -0
  4. package/client/attachment-hover-preview.js +36 -0
  5. package/client/audio-level.d.ts +5 -0
  6. package/client/audio-level.js +24 -0
  7. package/client/composer-attachments.d.ts +30 -0
  8. package/client/composer-attachments.js +33 -0
  9. package/client/composer-drawer.d.ts +19 -0
  10. package/client/composer-drawer.js +15 -0
  11. package/client/composer-hints.d.ts +25 -0
  12. package/client/composer-hints.js +20 -0
  13. package/client/composer-primary.d.ts +16 -0
  14. package/client/composer-primary.js +25 -0
  15. package/client/decision-images.d.ts +76 -0
  16. package/client/decision-images.js +139 -0
  17. package/client/decision-transport.d.ts +70 -0
  18. package/client/decision-transport.js +175 -0
  19. package/client/decode-composer-draft.d.ts +11 -0
  20. package/client/decode-composer-draft.js +12 -0
  21. package/client/embedding-input.d.ts +84 -0
  22. package/client/embedding-input.js +194 -0
  23. package/client/embedding-space.d.ts +82 -0
  24. package/client/embedding-space.js +389 -0
  25. package/client/embedding-transport.d.ts +40 -0
  26. package/client/embedding-transport.js +71 -0
  27. package/client/encode-composer-draft.d.ts +9 -0
  28. package/client/encode-composer-draft.js +34 -0
  29. package/client/encode-files.d.ts +18 -0
  30. package/client/encode-files.js +54 -0
  31. package/client/failure.d.ts +29 -0
  32. package/client/failure.js +34 -0
  33. package/client/generation-selection.d.ts +15 -0
  34. package/client/generation-selection.js +24 -0
  35. package/client/host-call.d.ts +51 -0
  36. package/client/host-call.js +47 -0
  37. package/client/host-transport.d.ts +70 -0
  38. package/client/host-transport.js +75 -0
  39. package/client/image-output.d.ts +6 -0
  40. package/client/image-output.js +13 -0
  41. package/client/index.d.ts +28 -0
  42. package/client/index.js +22 -0
  43. package/client/ink-waveform.d.ts +17 -0
  44. package/client/ink-waveform.js +68 -0
  45. package/client/live/apply-live-turn-tool-event.d.ts +14 -0
  46. package/client/live/apply-live-turn-tool-event.js +39 -0
  47. package/client/live/live-captions.d.ts +53 -0
  48. package/client/live/live-captions.js +174 -0
  49. package/client/live/live-mic-forward.d.ts +30 -0
  50. package/client/live/live-mic-forward.js +46 -0
  51. package/client/live/live-page-tool.d.ts +34 -0
  52. package/client/live/live-page-tool.js +11 -0
  53. package/client/live/live-state.d.ts +13 -0
  54. package/client/live/live-state.js +22 -0
  55. package/client/live/live-tool.d.ts +11 -0
  56. package/client/live/live-tool.js +1 -0
  57. package/client/live/live-video.d.ts +10 -0
  58. package/client/live/live-video.js +71 -0
  59. package/client/live/run-live-tool-call.d.ts +22 -0
  60. package/client/live/run-live-tool-call.js +70 -0
  61. package/client/live/use-live-caption-log.d.ts +17 -0
  62. package/client/live/use-live-caption-log.js +51 -0
  63. package/client/live-client.d.ts +189 -0
  64. package/client/live-client.js +829 -0
  65. package/client/live-errors.d.ts +2 -0
  66. package/client/live-errors.js +9 -0
  67. package/client/live-messages.d.ts +148 -0
  68. package/client/live-messages.js +100 -0
  69. package/client/mic-capture.d.ts +4 -0
  70. package/client/mic-capture.js +6 -0
  71. package/client/oauth-popup.d.ts +26 -0
  72. package/client/oauth-popup.js +30 -0
  73. package/client/page-dispatch.d.ts +15 -0
  74. package/client/page-dispatch.js +63 -0
  75. package/client/pcm-downsample.d.ts +4 -0
  76. package/client/pcm-downsample.js +45 -0
  77. package/client/run-commit.d.ts +34 -0
  78. package/client/run-commit.js +49 -0
  79. package/client/run-session.d.ts +79 -0
  80. package/client/run-session.js +207 -0
  81. package/client/schema-fields.d.ts +63 -0
  82. package/client/schema-fields.js +199 -0
  83. package/client/shaped-data.d.ts +118 -0
  84. package/client/shaped-data.js +343 -0
  85. package/client/source-citations.d.ts +13 -0
  86. package/client/source-citations.js +56 -0
  87. package/client/space-geometry.d.ts +39 -0
  88. package/client/space-geometry.js +183 -0
  89. package/client/state-fields.d.ts +16 -0
  90. package/client/state-fields.js +44 -0
  91. package/client/tool-result.d.ts +78 -0
  92. package/client/tool-result.js +293 -0
  93. package/client/tool-resume.d.ts +50 -0
  94. package/client/tool-resume.js +14 -0
  95. package/client/trace-feed.d.ts +13 -0
  96. package/client/trace-feed.js +18 -0
  97. package/client/trace-story.d.ts +163 -0
  98. package/client/trace-story.js +440 -0
  99. package/client/trace-view.d.ts +130 -0
  100. package/client/trace-view.js +333 -0
  101. package/client/transcript-groups.d.ts +140 -0
  102. package/client/transcript-groups.js +217 -0
  103. package/client/transcript-schema.d.ts +10 -0
  104. package/client/transcript-schema.js +120 -0
  105. package/client/transcript-scroll.d.ts +7 -0
  106. package/client/transcript-scroll.js +6 -0
  107. package/client/transport.d.ts +264 -0
  108. package/client/transport.js +330 -0
  109. package/client/turn-client.d.ts +44 -0
  110. package/client/turn-client.js +88 -0
  111. package/client/voice-label.d.ts +2 -0
  112. package/client/voice-label.js +15 -0
  113. package/client/voice-recorder.d.ts +27 -0
  114. package/client/voice-recorder.js +162 -0
  115. package/client/wire-line.d.ts +56 -0
  116. package/client/wire-line.js +90 -0
  117. package/client/worklets/mic-capture.js +16 -0
  118. package/components/InkWaveform.d.ts +21 -0
  119. package/components/InkWaveform.js +131 -0
  120. package/components/live/use-live-runner-controls.d.ts +47 -0
  121. package/components/live/use-live-runner-controls.js +96 -0
  122. package/components/live/use-live-runner-model.d.ts +49 -0
  123. package/components/live/use-live-runner-model.js +190 -0
  124. package/components/live/use-live-runner-ui.d.ts +67 -0
  125. package/components/live/use-live-runner-ui.js +167 -0
  126. package/components/live/use-live-session-client.d.ts +41 -0
  127. package/components/live/use-live-session-client.js +126 -0
  128. package/components/use-composer-voice.d.ts +28 -0
  129. package/components/use-composer-voice.js +90 -0
  130. package/components/use-editor-selection.d.ts +3 -0
  131. package/components/use-editor-selection.js +19 -0
  132. package/components/use-voice-playback.d.ts +17 -0
  133. package/components/use-voice-playback.js +68 -0
  134. package/hooks/use-described.d.ts +12 -0
  135. package/hooks/use-described.js +25 -0
  136. package/hooks/use-embedding-index.d.ts +27 -0
  137. package/hooks/use-embedding-index.js +43 -0
  138. package/hooks/use-one-call.d.ts +31 -0
  139. package/hooks/use-one-call.js +76 -0
  140. package/hooks/use-page-tool-warnings.d.ts +6 -0
  141. package/hooks/use-page-tool-warnings.js +25 -0
  142. package/hooks/use-second-ticker.d.ts +2 -0
  143. package/hooks/use-second-ticker.js +13 -0
  144. package/hooks/use-theorem-chat-actions.d.ts +79 -0
  145. package/hooks/use-theorem-chat-actions.js +287 -0
  146. package/hooks/use-theorem-chat-state.d.ts +66 -0
  147. package/hooks/use-theorem-chat-state.js +122 -0
  148. package/hooks/use-theorem-chat.d.ts +97 -0
  149. package/hooks/use-theorem-chat.js +528 -0
  150. package/hooks/use-theorem-decision.d.ts +18 -0
  151. package/hooks/use-theorem-decision.js +12 -0
  152. package/hooks/use-theorem-embedding.d.ts +18 -0
  153. package/hooks/use-theorem-embedding.js +12 -0
  154. package/hooks/use-theorem-host.d.ts +45 -0
  155. package/hooks/use-theorem-host.js +135 -0
  156. package/hooks/use-theorem-interface.d.ts +22 -0
  157. package/hooks/use-theorem-interface.js +15 -0
  158. package/hooks/use-trace-records.d.ts +4 -0
  159. package/hooks/use-trace-records.js +7 -0
  160. package/index.d.ts +17 -0
  161. package/index.js +17 -0
  162. package/live.d.ts +9 -0
  163. package/live.js +10 -0
  164. package/package.json +74 -4
  165. package/server/checkpoint-ownership.d.ts +6 -0
  166. package/server/checkpoint-ownership.js +42 -0
  167. package/server/conversation-store.d.ts +92 -0
  168. package/server/conversation-store.js +131 -0
  169. package/server/conversation.d.ts +193 -0
  170. package/server/conversation.js +552 -0
  171. package/server/credential-store.d.ts +24 -0
  172. package/server/credential-store.js +14 -0
  173. package/server/decision-handler.d.ts +42 -0
  174. package/server/decision-handler.js +46 -0
  175. package/server/embedding-handler.d.ts +33 -0
  176. package/server/embedding-handler.js +45 -0
  177. package/server/handler.d.ts +152 -0
  178. package/server/handler.js +771 -0
  179. package/server/json-response.d.ts +2 -0
  180. package/server/json-response.js +7 -0
  181. package/server/mod.d.ts +25 -0
  182. package/server/mod.js +23 -0
  183. package/server/page-dispatch.d.ts +22 -0
  184. package/server/page-dispatch.js +127 -0
  185. package/server/request-body.d.ts +2 -0
  186. package/server/request-body.js +42 -0
  187. package/server/request-check.d.ts +21 -0
  188. package/server/request-check.js +49 -0
  189. package/server/session-authority.d.ts +8 -0
  190. package/server/session-authority.js +78 -0
  191. package/server/session-boundary.d.ts +26 -0
  192. package/server/session-boundary.js +64 -0
  193. package/server/session-identity.d.ts +16 -0
  194. package/server/session-identity.js +41 -0
  195. package/server/session-limits.d.ts +12 -0
  196. package/server/session-limits.js +59 -0
  197. package/server/session-store.d.ts +123 -0
  198. package/server/session-store.js +264 -0
  199. package/server/single-action.d.ts +21 -0
  200. package/server/single-action.js +30 -0
  201. package/server/steer-inbox.d.ts +35 -0
  202. package/server/steer-inbox.js +52 -0
  203. package/server/tool-operations.d.ts +6 -0
  204. package/server/tool-operations.js +132 -0
  205. package/server/turn-input.d.ts +10 -0
  206. package/server/turn-input.js +29 -0
  207. package/styles/ink-controls.css +134 -0
  208. package/ui/CardWall.d.ts +10 -0
  209. package/ui/CardWall.js +61 -0
  210. package/ui/ChatComposerBar.d.ts +62 -0
  211. package/ui/ChatComposerBar.js +306 -0
  212. package/ui/ChatTranscript.d.ts +43 -0
  213. package/ui/ChatTranscript.js +527 -0
  214. package/ui/ConsoleFrame.d.ts +104 -0
  215. package/ui/ConsoleFrame.js +146 -0
  216. package/ui/DecisionAnswers.d.ts +53 -0
  217. package/ui/DecisionAnswers.js +233 -0
  218. package/ui/DecisionImages.d.ts +16 -0
  219. package/ui/DecisionImages.js +46 -0
  220. package/ui/EmbeddingDocuments.d.ts +78 -0
  221. package/ui/EmbeddingDocuments.js +278 -0
  222. package/ui/EmbeddingQuery.d.ts +27 -0
  223. package/ui/EmbeddingQuery.js +95 -0
  224. package/ui/EmbeddingResults.d.ts +41 -0
  225. package/ui/EmbeddingResults.js +165 -0
  226. package/ui/EmbeddingSpace.d.ts +26 -0
  227. package/ui/EmbeddingSpace.js +106 -0
  228. package/ui/LiveCaptionsPanel.d.ts +22 -0
  229. package/ui/LiveCaptionsPanel.js +27 -0
  230. package/ui/LiveRunner.d.ts +30 -0
  231. package/ui/LiveRunner.js +180 -0
  232. package/ui/PaneState.d.ts +33 -0
  233. package/ui/PaneState.js +50 -0
  234. package/ui/SchemaFields.d.ts +10 -0
  235. package/ui/SchemaFields.js +150 -0
  236. package/ui/ShapedData.d.ts +11 -0
  237. package/ui/ShapedData.js +196 -0
  238. package/ui/SidePanel.d.ts +126 -0
  239. package/ui/SidePanel.js +123 -0
  240. package/ui/StateFields.d.ts +44 -0
  241. package/ui/StateFields.js +139 -0
  242. package/ui/TheoremChat.d.ts +122 -0
  243. package/ui/TheoremChat.js +134 -0
  244. package/ui/TheoremDecision.d.ts +30 -0
  245. package/ui/TheoremDecision.js +130 -0
  246. package/ui/TheoremEmbedding.d.ts +27 -0
  247. package/ui/TheoremEmbedding.js +122 -0
  248. package/ui/TheoremHost.d.ts +55 -0
  249. package/ui/TheoremHost.js +240 -0
  250. package/ui/ToolGateCard.d.ts +32 -0
  251. package/ui/ToolGateCard.js +107 -0
  252. package/ui/ToolResult.d.ts +10 -0
  253. package/ui/ToolResult.js +62 -0
  254. package/ui/ToolResultCharts.d.ts +5 -0
  255. package/ui/ToolResultCharts.js +103 -0
  256. package/ui/TraceCharts.d.ts +13 -0
  257. package/ui/TraceCharts.js +266 -0
  258. package/ui/TraceGuardrails.d.ts +11 -0
  259. package/ui/TraceGuardrails.js +74 -0
  260. package/ui/TraceInspector.d.ts +16 -0
  261. package/ui/TraceInspector.js +206 -0
  262. package/ui/TraceInspectorPanel.d.ts +46 -0
  263. package/ui/TraceInspectorPanel.js +95 -0
  264. package/ui/TraceOverview.d.ts +38 -0
  265. package/ui/TraceOverview.js +126 -0
  266. package/ui/TraceSpanDetail.d.ts +10 -0
  267. package/ui/TraceSpanDetail.js +190 -0
  268. package/ui/TraceStory.d.ts +20 -0
  269. package/ui/TraceStory.js +108 -0
  270. package/ui/TraceValues.d.ts +36 -0
  271. package/ui/TraceValues.js +123 -0
  272. package/ui/TraceWaterfall.d.ts +13 -0
  273. package/ui/TraceWaterfall.js +135 -0
  274. package/ui/VoiceNote.d.ts +12 -0
  275. package/ui/VoiceNote.js +28 -0
  276. package/ui/approval-heading.d.ts +4 -0
  277. package/ui/approval-heading.js +9 -0
  278. package/ui/arrive.d.ts +18 -0
  279. package/ui/arrive.js +46 -0
  280. package/ui/built/theme.css +792 -0
  281. package/ui/built/theme.css.d.ts +9 -0
  282. package/ui/built/theorem.d.ts +13 -0
  283. package/ui/built/theorem.js +660 -0
  284. package/ui/built/theorem.variants.d.ts +22 -0
  285. package/ui/code-language.d.ts +12 -0
  286. package/ui/code-language.js +50 -0
  287. package/ui/disclosure-motion.d.ts +6 -0
  288. package/ui/disclosure-motion.js +207 -0
  289. package/ui/embedding-space-gl.d.ts +37 -0
  290. package/ui/embedding-space-gl.js +663 -0
  291. package/ui/embedding-space-view.d.ts +8 -0
  292. package/ui/embedding-space-view.js +8 -0
  293. package/ui/glide.d.ts +7 -0
  294. package/ui/glide.js +44 -0
  295. package/ui/icons.d.ts +4 -0
  296. package/ui/icons.js +38 -0
  297. package/ui/index.d.ts +36 -0
  298. package/ui/index.js +39 -0
  299. package/ui/labels-provider.d.ts +16 -0
  300. package/ui/labels-provider.js +64 -0
  301. package/ui/labels.d.ts +1442 -0
  302. package/ui/labels.js +1443 -0
  303. package/ui/markdown-plugins.d.ts +9 -0
  304. package/ui/markdown-plugins.js +13 -0
  305. package/ui/mcp-icon.d.ts +6 -0
  306. package/ui/mcp-icon.js +8 -0
  307. package/ui/row-keys.d.ts +19 -0
  308. package/ui/row-keys.js +33 -0
  309. package/ui/theme.d.ts +10 -0
  310. package/ui/theme.js +13 -0
  311. package/ui/theorem-theme.d.ts +10 -0
  312. package/ui/theorem-theme.js +105 -0
  313. package/ui/trace-palette.d.ts +10 -0
  314. package/ui/trace-palette.js +10 -0
  315. package/ui/trace-patterns.d.ts +40 -0
  316. package/ui/trace-patterns.js +57 -0
  317. package/ui/transcript-copy-text.d.ts +4 -0
  318. package/ui/transcript-copy-text.js +40 -0
  319. package/ui/wall-columns.d.ts +8 -0
  320. package/ui/wall-columns.js +19 -0
@@ -0,0 +1,95 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Icon } from '@astryxdesign/core/Icon';
3
+ import { IconActivity } from '@tabler/icons-react';
4
+ import { cloneElement, createContext, isValidElement, lazy, Suspense, use, useCallback, useId, useRef, useState, } from 'react';
5
+ import { TheoremLabelsProvider, useLabels } from "./labels-provider.js";
6
+ import { InPlace, isSidePanelWide, RaisedPane, SidePanel, SidePanelHeader, SidePanelToggle, useSidePanel, useWidth, } from "./SidePanel.js";
7
+ // why: The inspector and its charts are fetched when the trace first opens, not with the chat.
8
+ const TraceGuardrailsBody = lazy(() => import("./TraceInspector.js").then((module) => ({ default: module.TraceGuardrailsBody })));
9
+ const TraceFeedBody = lazy(() => import("./TraceInspector.js").then((module) => ({ default: module.TraceFeedBody })));
10
+ /** `replace` takes the surface's place. `panel` docks at the inline end; its width eases with the theme. */
11
+ const TracePlacementContext = createContext('replace');
12
+ /** Where an open trace sits on this page. */
13
+ export function TracePlacement({ value, children, }) {
14
+ return _jsx(TracePlacementContext, { value: value, children: children });
15
+ }
16
+ function TraceView({ id, header, traces, }) {
17
+ return (_jsx(RaisedPane, { id: id, header: header, children: (isWide) => (_jsx(Suspense, { fallback: null, children: _jsx(TraceFeedBody, { traces: traces, isWide: isWide }) })) }));
18
+ }
19
+ /**
20
+ * The trace inspector, offered when the profile records traces. By default the
21
+ * open trace takes the surface's place. Inside `TracePlacement value="panel"`
22
+ * it docks at the inline end instead, and the theme eases that panel's width.
23
+ * It reads the records the host delivers on `traces`; a host that delivers none
24
+ * shows the empty state. Pass `open` to drive it from the host's own control,
25
+ * which hides the built-in toggle. The open trace takes the surface's place,
26
+ * unless this page is inside `TracePlacement value="panel"`, where it docks.
27
+ */
28
+ export function useTraceInspector(iface, traces, open) {
29
+ const t = useLabels();
30
+ const id = useId();
31
+ const [own, setOwn] = useState(false);
32
+ const placement = use(TracePlacementContext);
33
+ const labels = {
34
+ name: t('@theorem.panel.trace.name'),
35
+ show: t('@theorem.panel.trace.show'),
36
+ hide: t('@theorem.panel.trace.hide'),
37
+ resize: t('@theorem.panel.trace.resize'),
38
+ };
39
+ if (iface.observability?.record !== true)
40
+ return { toggle: null, view: null, labels, offered: false };
41
+ const isOpen = open ?? own;
42
+ const toggle = open === undefined ? (_jsx(SidePanelToggle, { labels: labels, icon: _jsx(Icon, { icon: IconActivity }), panelId: id, open: isOpen, onToggle: () => setOwn((value) => !value) })) : null;
43
+ const view = isOpen ? openTrace(placement === 'panel', id, traces, toggle) : null;
44
+ return { toggle, view, labels, offered: true };
45
+ }
46
+ /** The open trace: filling the host's docked panel, or as its own panel with the toggle on top. */
47
+ function openTrace(docked, id, traces, toggle) {
48
+ if (docked)
49
+ return _jsx(TraceFill, { id: id, traces: traces });
50
+ return (_jsx(TraceView, { id: id, header: toggle ? _jsx(SidePanelHeader, { floating: true, children: toggle }) : undefined, traces: traces }));
51
+ }
52
+ /** The trace body, filling the docked panel. The panel supplies the raised card. */
53
+ function TraceFill({ id, traces }) {
54
+ const { ref, width } = useWidth();
55
+ return (_jsx("div", { id: id, ref: ref, style: { height: '100%' }, children: _jsx(Suspense, { fallback: null, children: _jsx(TraceFeedBody, { traces: traces, isWide: isSidePanelWide(width) }) }) }));
56
+ }
57
+ /** The surface, with the trace docked at its inline end. A host-driven trace stays in place. */
58
+ function TraceDock({ inspector, children }) {
59
+ const layoutRef = useRef(null);
60
+ const side = useSidePanel(layoutRef, false);
61
+ const childRef = useRef(undefined);
62
+ const setLayout = useCallback((node) => {
63
+ layoutRef.current = node;
64
+ const ref = childRef.current;
65
+ if (typeof ref === 'function')
66
+ ref(node);
67
+ else if (ref != null)
68
+ ref.current = node;
69
+ }, []);
70
+ if (!isValidElement(children)) {
71
+ return _jsx(InPlace, { view: inspector.view, children: children });
72
+ }
73
+ childRef.current = children.props.ref;
74
+ const open = inspector.view != null;
75
+ return cloneElement(children, {
76
+ ref: setLayout,
77
+ end: (_jsx(SidePanel, { labels: inspector.labels, resizable: side.resizable, open: open, children: inspector.view })),
78
+ });
79
+ }
80
+ /** The surface, or the trace in its place — or, on a docked page, beside it. */
81
+ export function WithTrace({ inspector, children, }) {
82
+ const placement = use(TracePlacementContext);
83
+ if (placement === 'panel' && inspector.offered) {
84
+ return _jsx(TraceDock, { inspector: inspector, children: children });
85
+ }
86
+ return _jsx(InPlace, { view: inspector.view, children: children });
87
+ }
88
+ /**
89
+ * What `records` say of guardrails, for a host that holds a trace of its own
90
+ * (the studio's guardrail test): the checks' time and count, then each
91
+ * check, laid out as the trace lays them out. `head` leads it.
92
+ */
93
+ export function TraceGuardrailsView({ records, head, }) {
94
+ return (_jsx(TheoremLabelsProvider, { children: _jsx(Suspense, { fallback: null, children: _jsx(TraceGuardrailsBody, { records: records, head: head }) }) }));
95
+ }
@@ -0,0 +1,38 @@
1
+ import { type ReactNode } from 'react';
2
+ import { type TraceLatency, type TraceTurn } from '../client/trace-story.ts';
3
+ import type { TraceTotals } from '../client/trace-view.ts';
4
+ /** Width a chart draws at before it has measured its column: the panel's narrowest. */
5
+ export declare const FIRST_WIDTH_PX = 280;
6
+ /**
7
+ * Holds a chart. Recharts makes its layers focusable, so a click would move
8
+ * focus into the SVG and draw the browser's ring; a press here keeps focus
9
+ * where it was. Clicks and pointer drags still reach the chart.
10
+ */
11
+ export declare function ChartFrame({ children }: {
12
+ children: ReactNode;
13
+ }): import("react").JSX.Element;
14
+ /** A chart's hover card, drawn like Astryx's own tooltip. */
15
+ export declare function ChartTip({ children }: {
16
+ children: ReactNode;
17
+ }): import("react").JSX.Element;
18
+ /** Which turn is open: its name, and the previous and next turn. */
19
+ export declare function TurnPicker({ turns, index, onChange, onBack, }: {
20
+ turns: readonly TraceTurn[];
21
+ index: number;
22
+ onChange: (index: number) => void;
23
+ /** Leaves the turn for the whole conversation; absent when there is only the one turn. */
24
+ onBack?: (() => void) | undefined;
25
+ }): import("react").JSX.Element | null;
26
+ /** A turn's guardrail figures alone, as {@link TurnStats} lays them out. */
27
+ export declare function GuardrailStats({ latency }: {
28
+ latency: TraceLatency;
29
+ }): import("react").JSX.Element | null;
30
+ /**
31
+ * Duration, first text, cost, tokens, steps, and guardrails of the open turn;
32
+ * a total the trace did not record is left out.
33
+ */
34
+ export declare function TurnStats({ totals, tools, latency, }: {
35
+ totals: TraceTotals;
36
+ tools: number;
37
+ latency?: TraceLatency;
38
+ }): import("react").JSX.Element;
@@ -0,0 +1,126 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button } from '@astryxdesign/core/Button';
3
+ import { Card } from '@astryxdesign/core/Card';
4
+ import { Grid } from '@astryxdesign/core/Grid';
5
+ import { HStack } from '@astryxdesign/core/HStack';
6
+ import { Icon } from '@astryxdesign/core/Icon';
7
+ import { IconButton } from '@astryxdesign/core/IconButton';
8
+ import { Text } from '@astryxdesign/core/Text';
9
+ import { VStack } from '@astryxdesign/core/VStack';
10
+ import { IconArrowLeft, IconChevronLeft, IconChevronRight } from '@tabler/icons-react';
11
+ import { TRACE_FIELDS, traceAttributeMeta } from '@theoremjs/agents';
12
+ import { useEffect, useRef } from 'react';
13
+ import { isCallTrace } from "../client/trace-story.js";
14
+ import { useTraceFormat } from "./TraceValues.js";
15
+ import { TRACE_HUE } from "./trace-palette.js";
16
+ /** Width a chart draws at before it has measured its column: the panel's narrowest. */
17
+ export const FIRST_WIDTH_PX = 280;
18
+ /**
19
+ * Holds a chart. Recharts makes its layers focusable, so a click would move
20
+ * focus into the SVG and draw the browser's ring; a press here keeps focus
21
+ * where it was. Clicks and pointer drags still reach the chart.
22
+ */
23
+ export function ChartFrame({ children }) {
24
+ const frame = useRef(null);
25
+ useEffect(() => {
26
+ const node = frame.current;
27
+ // why: A native listener keeps the frame a plain element; it is not a control, so it takes no role.
28
+ const keepFocus = (event) => event.preventDefault();
29
+ node?.addEventListener('mousedown', keepFocus);
30
+ return () => node?.removeEventListener('mousedown', keepFocus);
31
+ }, []);
32
+ return _jsx("div", { ref: frame, children: children });
33
+ }
34
+ /** A chart's hover card, drawn like Astryx's own tooltip. */
35
+ export function ChartTip({ children }) {
36
+ return (_jsx("div", { style: {
37
+ background: 'var(--color-background-popover)',
38
+ border: '1px solid var(--color-border)',
39
+ borderRadius: 'var(--radius-element)',
40
+ padding: '6px 8px',
41
+ boxShadow: 'var(--shadow-med)',
42
+ pointerEvents: 'none',
43
+ }, children: children }));
44
+ }
45
+ /** Which turn is open: its name, and the previous and next turn. */
46
+ export function TurnPicker({ turns, index, onChange, onBack, }) {
47
+ const { t } = useTraceFormat();
48
+ const turn = turns[index];
49
+ if (!turn)
50
+ return null;
51
+ const isCalls = isCallTrace(turns);
52
+ return (_jsxs(VStack, { gap: 1, hAlign: "start", children: [onBack ? (_jsx(Button, { label: t(isCalls ? '@theorem.panel.trace.calls.back' : '@theorem.panel.trace.conversation.back'), variant: "ghost", size: "sm", icon: _jsx(Icon, { icon: IconArrowLeft }), onClick: onBack })) : null, _jsxs(HStack, { gap: 1, align: "center", justify: "between", width: "100%", children: [_jsxs(HStack, { gap: 2, align: "center", children: [_jsx(Text, { weight: "semibold", children: t('@theorem.panel.trace.turn', {
53
+ label: turn.node.meta.label,
54
+ index: index + 1,
55
+ count: turns.length,
56
+ }) }), turn.node.meta.subject ? (_jsx(Text, { color: "secondary", maxLines: 1, children: turn.node.meta.subject })) : null] }), _jsxs(HStack, { gap: 0, children: [_jsx(IconButton, { label: t(isCalls ? '@theorem.panel.trace.calls.previous' : '@theorem.panel.trace.previous'), icon: _jsx(Icon, { icon: IconChevronLeft }), variant: "ghost", size: "sm", isDisabled: index === 0, onClick: () => onChange(index - 1) }), _jsx(IconButton, { label: t(isCalls ? '@theorem.panel.trace.calls.next' : '@theorem.panel.trace.next'), icon: _jsx(Icon, { icon: IconChevronRight }), variant: "ghost", size: "sm", isDisabled: index === turns.length - 1, onClick: () => onChange(index + 1) })] })] })] }));
57
+ }
58
+ function Stat({ label, value, detail, }) {
59
+ return (_jsx(Card, { padding: 3, variant: "muted", style: { background: 'var(--color-background-surface)' }, children: _jsxs(VStack, { gap: 1, children: [_jsx(Text, { type: "supporting", color: "secondary", children: label }), _jsx(Text, { type: "large", weight: "semibold", hasTabularNumbers: true, children: value }), _jsx(VStack, { gap: 0, children: [detail]
60
+ .flat()
61
+ .filter(Boolean)
62
+ .map((line) => (_jsx(Text, { type: "supporting", color: "secondary", hasTabularNumbers: true, children: line }, String(line)))) })] }) }));
63
+ }
64
+ function FirstTextStat({ latency, format }) {
65
+ if (latency?.firstTextMs === undefined)
66
+ return null;
67
+ const { t } = format;
68
+ return (_jsx(Stat, { label: t('@theorem.panel.trace.firstText'), value: format.duration(latency.firstTextMs), detail: [
69
+ latency.tokensPerSecond !== undefined &&
70
+ t('@theorem.panel.trace.rate', {
71
+ rate: format.number(Math.round(latency.tokensPerSecond)),
72
+ }),
73
+ latency.heldMs &&
74
+ t('@theorem.panel.trace.held', { duration: format.duration(latency.heldMs) }),
75
+ ] }));
76
+ }
77
+ function CostStat({ totals, format }) {
78
+ if (!totals.cost)
79
+ return null;
80
+ return (_jsx(Stat, { label: traceAttributeMeta('theorem.usage.cost_usd')?.label ?? '', value: format.sum(totals.cost, format.usd) }));
81
+ }
82
+ /** A token total as its card reads it: "–" when no call reported it. */
83
+ function tokenSide(total, format) {
84
+ return total ? format.sum(total, format.number) : '–';
85
+ }
86
+ function TokensStat({ totals, format }) {
87
+ const { input, output } = totals;
88
+ if (!input && !output)
89
+ return null;
90
+ const all = [input, output].reduce((sum, total) => sum + (total?.value ?? 0), 0);
91
+ return (_jsx(Stat, { label: format.t('@theorem.panel.trace.tokens'), value: format.number(all), detail: format.t('@theorem.panel.trace.tokens.detail', {
92
+ input: tokenSide(input, format),
93
+ output: tokenSide(output, format),
94
+ }) }));
95
+ }
96
+ function StepsStat({ totals, tools, format, }) {
97
+ const { t } = format;
98
+ // why: With no model, every step is a tool call the heading already counts.
99
+ if (totals.calls === 0 && totals.errors === 0)
100
+ return null;
101
+ return (_jsx(Stat, { label: t('@theorem.panel.trace.steps'), value: format.number(totals.calls + tools), detail: totals.errors > 0 ? (_jsx("span", { style: { color: TRACE_HUE.oxblood }, children: t('@theorem.panel.trace.failed', { count: totals.errors }) })) : (t('@theorem.panel.trace.steps.detail', { calls: totals.calls, tools })) }));
102
+ }
103
+ function GuardrailsStat({ latency, format, }) {
104
+ const guardrails = latency?.guardrails;
105
+ if (!guardrails)
106
+ return null;
107
+ return (_jsx(Stat, { label: format.t('@theorem.panel.trace.guardrails'), value: format.duration(guardrails.ms), detail: format.t('@theorem.panel.trace.guardrails.detail', {
108
+ checks: guardrails.checks,
109
+ flagged: guardrails.flagged,
110
+ }) }));
111
+ }
112
+ /** A turn's guardrail figures alone, as {@link TurnStats} lays them out. */
113
+ export function GuardrailStats({ latency }) {
114
+ const format = useTraceFormat();
115
+ if (!latency.guardrails)
116
+ return null;
117
+ return (_jsx(Grid, { columns: { minWidth: 120, repeat: 'fit' }, gap: 2, children: _jsx(GuardrailsStat, { latency: latency, format: format }) }));
118
+ }
119
+ /**
120
+ * Duration, first text, cost, tokens, steps, and guardrails of the open turn;
121
+ * a total the trace did not record is left out.
122
+ */
123
+ export function TurnStats({ totals, tools, latency, }) {
124
+ const format = useTraceFormat();
125
+ return (_jsxs(Grid, { columns: { minWidth: 120, repeat: 'fit' }, gap: 2, children: [_jsx(Stat, { label: TRACE_FIELDS.duration.label, value: format.duration(totals.durationMs) }), _jsx(FirstTextStat, { latency: latency, format: format }), _jsx(CostStat, { totals: totals, format: format }), _jsx(TokensStat, { totals: totals, format: format }), _jsx(StepsStat, { totals: totals, tools: tools, format: format }), _jsx(GuardrailsStat, { latency: latency, format: format })] }));
126
+ }
@@ -0,0 +1,10 @@
1
+ import { type TraceNode } from '../client/trace-view.ts';
2
+ /** One span in full: who acted and how it ended, what went in and came out, its tokens, then every detail it recorded. */
3
+ export declare function TraceSpanDetail({ node, turnStartMs, isClose, onBack, onOpen, }: {
4
+ node: TraceNode;
5
+ turnStartMs: number;
6
+ /** In the wide panel the span sits beside the turn: close, not back. */
7
+ isClose?: boolean;
8
+ onBack: () => void;
9
+ onOpen: (node: TraceNode) => void;
10
+ }): import("react").JSX.Element;
@@ -0,0 +1,190 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { Badge } from '@astryxdesign/core/Badge';
3
+ import { Button } from '@astryxdesign/core/Button';
4
+ import { Card } from '@astryxdesign/core/Card';
5
+ import { Collapsible } from '@astryxdesign/core/Collapsible';
6
+ import { HStack } from '@astryxdesign/core/HStack';
7
+ import { Icon } from '@astryxdesign/core/Icon';
8
+ import { Item } from '@astryxdesign/core/Item';
9
+ import { MetadataList, MetadataListItem } from '@astryxdesign/core/MetadataList';
10
+ import { Text } from '@astryxdesign/core/Text';
11
+ import { Token } from '@astryxdesign/core/Token';
12
+ import { Tooltip as HoverTip } from '@astryxdesign/core/Tooltip';
13
+ import { VStack } from '@astryxdesign/core/VStack';
14
+ import { IconArrowLeft, IconX } from '@tabler/icons-react';
15
+ import { inlineContent, TRACE_ATTRIBUTE_GROUPS, TRACE_FIELDS, TRACE_SPAN_TYPES, TRACE_STATUS, traceAttributeMeta, traceEventAttributeMeta, traceEventMeta, } from '@theoremjs/agents';
16
+ import { messageText, storedValue, traceActor, traceOutcome } from "../client/trace-story.js";
17
+ import { nanosToMs } from "../client/trace-view.js";
18
+ import { keyedByContent } from "./row-keys.js";
19
+ import { ShapedData } from "./ShapedData.js";
20
+ import { PanePanel, Prose } from "./SidePanel.js";
21
+ import { ActorMark } from "./TraceStory.js";
22
+ import { attributeSections, TRACE_LABEL_PX, TraceAttributeList, TraceValue, useTraceFormat, } from "./TraceValues.js";
23
+ /** A span's own field, read as an attribute of that format. */
24
+ function fieldMeta(field, format) {
25
+ return { ...field, format, group: 'record' };
26
+ }
27
+ const SPAN_FIELD_META = {
28
+ type: { ...fieldMeta(TRACE_FIELDS.type, 'text'), options: TRACE_SPAN_TYPES },
29
+ status: { ...fieldMeta(TRACE_FIELDS.status, 'text'), options: TRACE_STATUS },
30
+ start: fieldMeta(TRACE_FIELDS.start, 'time'),
31
+ traceId: fieldMeta(TRACE_FIELDS.traceId, 'id'),
32
+ spanId: fieldMeta(TRACE_FIELDS.spanId, 'id'),
33
+ };
34
+ function spanFieldMeta(key) {
35
+ return key in SPAN_FIELD_META ? SPAN_FIELD_META[key] : undefined;
36
+ }
37
+ function Section({ title, children }) {
38
+ return (_jsx(Collapsible, { defaultIsOpen: false, trigger: _jsx(Text, { weight: "medium", children: title }), children: children }));
39
+ }
40
+ function EventList({ node }) {
41
+ const format = useTraceFormat();
42
+ return (_jsx(VStack, { gap: 3, children: keyedByContent(node.span.events, (event) => `${event.name}:${event.timeUnixNano}`).map(({ item: event, key }) => {
43
+ const offset = format.t('@theorem.panel.trace.offset', {
44
+ duration: format.duration(nanosToMs(event.timeUnixNano) - node.startMs),
45
+ });
46
+ const label = traceEventMeta(event.name)?.label ?? event.name;
47
+ return (_jsxs(VStack, { gap: 1, children: [_jsxs(HStack, { gap: 2, align: "center", children: [_jsx(Text, { weight: "medium", children: label }), _jsx(Text, { type: "supporting", hasTabularNumbers: true, children: offset })] }), _jsx(TraceAttributeList, { record: node.record, attributes: event.attributes, metaOf: (key) => traceEventAttributeMeta(event.name, key) })] }, key));
48
+ }) }));
49
+ }
50
+ function LinkList({ node }) {
51
+ return (_jsx(VStack, { gap: 3, children: node.span.links.map((link) => (_jsx(TraceAttributeList, { record: node.record, attributes: { traceId: link.traceId, spanId: link.spanId, ...link.attributes }, metaOf: (key) => spanFieldMeta(key) ?? traceAttributeMeta(key) }, `${link.traceId}:${link.spanId}`))) }));
52
+ }
53
+ const SPAN_FIELD_VALUES = {
54
+ type: (node) => node.meta.type,
55
+ start: (node) => node.span.startTimeUnixNano,
56
+ traceId: (node) => node.span.traceId,
57
+ spanId: (node) => node.span.spanId,
58
+ };
59
+ /** What the span was, how long it took, what it cost, and when it started. */
60
+ function spanFacts(node, turnStartMs, format) {
61
+ const cost = node.span.attributes['theorem.usage.cost_usd'];
62
+ return [
63
+ node.meta.label,
64
+ format.duration(node.durationMs),
65
+ ...(typeof cost === 'number' ? [format.usd(cost)] : []),
66
+ format.t('@theorem.panel.trace.offset', {
67
+ duration: format.duration(node.startMs - turnStartMs),
68
+ }),
69
+ ].join(format.t('@theorem.panel.trace.separator'));
70
+ }
71
+ function OutcomeBadge({ outcome }) {
72
+ if (!outcome)
73
+ return null;
74
+ return (_jsx(HoverTip, { content: outcome.doc ?? outcome.label, children: _jsx(Badge, { variant: outcome.tone, label: outcome.label }) }));
75
+ }
76
+ /** The span's status message, unless the outcome badge already says it. */
77
+ function StatusMessage({ node, outcome, }) {
78
+ const message = node.span.status.message;
79
+ if (!message || message.toLowerCase() === outcome?.label.toLowerCase())
80
+ return null;
81
+ return _jsx(Text, { color: "secondary", children: message });
82
+ }
83
+ /** Back (or close), then who acted, what it was, how it ended, how long it took, and what it cost. */
84
+ function SpanHeader({ node, turnStartMs, onBack, isClose, }) {
85
+ const format = useTraceFormat();
86
+ const outcome = traceOutcome(node);
87
+ return (_jsxs(VStack, { gap: 2, children: [_jsx(HStack, { children: _jsx(Button, { label: format.t(isClose ? '@theorem.panel.trace.close' : '@theorem.panel.trace.back'), variant: "ghost", size: "sm", icon: _jsx(Icon, { icon: isClose ? IconX : IconArrowLeft }), onClick: onBack }) }), _jsx(Item, { startContent: _jsx(ActorMark, { actor: traceActor(node) }), label: _jsx(Text, { weight: "semibold", children: node.meta.subject ?? node.meta.label }), description: spanFacts(node, turnStartMs, format), endContent: _jsx(OutcomeBadge, { outcome: outcome }), align: "start" }), _jsx(StatusMessage, { node: node, outcome: outcome })] }));
88
+ }
89
+ function parsed(value) {
90
+ if (typeof value !== 'string')
91
+ return value;
92
+ try {
93
+ return JSON.parse(value);
94
+ }
95
+ catch {
96
+ return value;
97
+ }
98
+ }
99
+ function isObject(value) {
100
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
101
+ }
102
+ function ToolCallPart({ part }) {
103
+ return (_jsxs(VStack, { gap: 1, children: [_jsx(Text, { weight: "medium", children: String(part.name ?? '') }), _jsx(ShapedData, { value: parsed(part.arguments) })] }));
104
+ }
105
+ /** One message part: its text, or a tool call's name and arguments, or what a tool returned. */
106
+ function PartView({ part }) {
107
+ if (part.type === 'text' && typeof part.content === 'string')
108
+ return _jsx(Prose, { text: part.content });
109
+ if (part.type === 'tool_call')
110
+ return _jsx(ToolCallPart, { part: part });
111
+ const body = part.response ?? part.result ?? part.content;
112
+ return body === undefined ? null : _jsx(ShapedData, { value: parsed(body) });
113
+ }
114
+ /** Messages as the model saw them: each one's role, then its parts. */
115
+ function MessageList({ messages }) {
116
+ return (_jsx(VStack, { gap: 3, children: keyedByContent(messages, (message) => JSON.stringify(message)).map(({ item: message, key }) => (_jsxs(VStack, { gap: 1, children: [_jsx(HStack, { children: _jsx(Token, { label: String(message.role ?? ''), size: "sm", color: "gray" }) }), Array.isArray(message.parts)
117
+ ? keyedByContent(message.parts.filter(isObject), (part) => JSON.stringify(part)).map(({ item: part, key: partKey }) => _jsx(PartView, { part: part }, partKey))
118
+ : null] }, key))) }));
119
+ }
120
+ function messagesOf(node, key) {
121
+ const value = inlineContent(node.record, node.span.attributes[key]);
122
+ return Array.isArray(value) ? value.filter(isObject) : [];
123
+ }
124
+ function label(key) {
125
+ const meta = traceAttributeMeta(key);
126
+ return meta ? { title: meta.label, doc: meta.doc } : { title: key };
127
+ }
128
+ /** A stored value under its attribute's name; nothing when the span has none. */
129
+ function DataPanel({ attribute, value }) {
130
+ if (value === undefined)
131
+ return null;
132
+ return (_jsx(PanePanel, { ...label(attribute), children: _jsx(ShapedData, { value: value }) }));
133
+ }
134
+ /** Text under its attribute's name; nothing when there is none. */
135
+ function ProsePanel({ attribute, text }) {
136
+ if (typeof text !== 'string' || !text)
137
+ return null;
138
+ return (_jsx(PanePanel, { ...label(attribute), children: _jsx(Prose, { text: text }) }));
139
+ }
140
+ function TurnIO({ node }) {
141
+ return (_jsxs(_Fragment, { children: [_jsx(ProsePanel, { attribute: "gen_ai.input.messages", text: messageText(node, 'gen_ai.input.messages', 'user') }), _jsx(ProsePanel, { attribute: "gen_ai.output.messages", text: messageText(node, 'gen_ai.output.messages', 'assistant') })] }));
142
+ }
143
+ function CallIO({ node }) {
144
+ const input = messagesOf(node, 'gen_ai.input.messages');
145
+ const output = messagesOf(node, 'gen_ai.output.messages');
146
+ return (_jsxs(_Fragment, { children: [output.length > 0 ? (_jsx(PanePanel, { ...label('gen_ai.output.messages'), children: _jsx(MessageList, { messages: output }) })) : null, input.length > 0 ? (_jsx(Collapsible, { defaultIsOpen: false, trigger: _jsx(Text, { weight: "medium", children: `${label('gen_ai.input.messages').title} · ${input.length}` }), children: _jsx(Card, { padding: 3, variant: "muted", style: { background: 'var(--color-background-surface)' }, children: _jsx(MessageList, { messages: input }) }) })) : null] }));
147
+ }
148
+ function ToolIO({ node }) {
149
+ const { attributes } = node.span;
150
+ const result = 'theorem.tool.data' in attributes ? 'theorem.tool.data' : 'gen_ai.tool.call.result';
151
+ return (_jsxs(_Fragment, { children: [_jsx(DataPanel, { attribute: "gen_ai.tool.call.arguments", value: storedValue(node, 'gen_ai.tool.call.arguments') }), _jsx(DataPanel, { attribute: result, value: storedValue(node, result) }), _jsx(ProsePanel, { attribute: "exception.message", text: 'exception.message' in attributes ? storedValue(node, 'exception.message') : undefined })] }));
152
+ }
153
+ /** What went in and what came out, read the way a person would: text, messages, or a tool's data. */
154
+ function SpanIO({ node }) {
155
+ switch (node.meta.type) {
156
+ case 'turn':
157
+ return _jsx(TurnIO, { node: node });
158
+ case 'call':
159
+ case 'response':
160
+ return _jsx(CallIO, { node: node });
161
+ case 'tool':
162
+ return _jsx(ToolIO, { node: node });
163
+ default:
164
+ return null;
165
+ }
166
+ }
167
+ /** The span's own fields: its type, start, and IDs. */
168
+ function SpanFields({ node }) {
169
+ return (_jsx(MetadataList, { columns: "single", label: { position: 'start', width: TRACE_LABEL_PX }, children: Object.keys(SPAN_FIELD_VALUES).map((key) => (_jsx(MetadataListItem, { label: SPAN_FIELD_META[key].label, children: _jsx(TraceValue, { record: node.record, meta: SPAN_FIELD_META[key], value: SPAN_FIELD_VALUES[key](node) }) }, key))) }));
170
+ }
171
+ /** The record's host resource and request metadata, shown on the span that roots the record. */
172
+ function RecordSections({ node }) {
173
+ const { record } = node;
174
+ if (record.spans[0]?.spanId !== node.span.spanId)
175
+ return null;
176
+ return (_jsxs(_Fragment, { children: [Object.keys(record.resource).length > 0 ? (_jsx(Section, { title: TRACE_FIELDS.resource.label, children: _jsx(TraceAttributeList, { record: record, attributes: record.resource, metaOf: traceAttributeMeta }) })) : null, record.metadata ? (_jsx(Section, { title: TRACE_FIELDS.metadata.label, children: _jsx(TraceAttributeList, { record: record, attributes: record.metadata, metaOf: () => undefined }) })) : null] }));
177
+ }
178
+ /** One span in full: who acted and how it ended, what went in and came out, its tokens, then every detail it recorded. */
179
+ export function TraceSpanDetail({ node, turnStartMs, isClose = false, onBack, onOpen, }) {
180
+ const format = useTraceFormat();
181
+ const { t } = format;
182
+ const { span, record } = node;
183
+ const sections = attributeSections(span.attributes);
184
+ const usage = sections.find((section) => section.key === 'usage');
185
+ return (_jsxs(VStack, { gap: 4, children: [_jsx(SpanHeader, { node: node, turnStartMs: turnStartMs, onBack: onBack, isClose: isClose }), _jsx(SpanIO, { node: node }), usage ? (_jsx(PanePanel, { title: TRACE_ATTRIBUTE_GROUPS.usage.label, doc: TRACE_ATTRIBUTE_GROUPS.usage.doc, children: _jsx(TraceAttributeList, { record: record, attributes: usage.attributes, metaOf: traceAttributeMeta }) })) : null, node.children.length > 0 ? (_jsx(PanePanel, { title: TRACE_FIELDS.children.label, doc: TRACE_FIELDS.children.doc, children: _jsx(VStack, { gap: 0, children: node.children.map((child) => (_jsx(Item, { startContent: _jsx(ActorMark, { actor: traceActor(child) }), label: child.meta.subject ?? child.meta.label, description: child.meta.label, endContent: _jsx(Text, { type: "supporting", hasTabularNumbers: true, children: format.duration(child.durationMs) }), density: "compact", onClick: () => onOpen(child) }, child.id))) }) })) : null, _jsx(Collapsible, { defaultIsOpen: false, trigger: _jsx(Text, { weight: "medium", children: t('@theorem.panel.trace.details') }), children: _jsxs(VStack, { gap: 3, children: [_jsx(SpanFields, { node: node }), sections
186
+ .filter((section) => section !== usage)
187
+ .map((section) => (_jsx(Section, { title: section.key === 'other'
188
+ ? t('@theorem.panel.trace.other')
189
+ : TRACE_ATTRIBUTE_GROUPS[section.key].label, children: _jsx(TraceAttributeList, { record: record, attributes: section.attributes, metaOf: traceAttributeMeta }) }, section.key))), span.events.length > 0 ? (_jsx(Section, { title: TRACE_FIELDS.events.label, children: _jsx(EventList, { node: node }) })) : null, span.links.length > 0 ? (_jsx(Section, { title: TRACE_FIELDS.links.label, children: _jsx(LinkList, { node: node }) })) : null, _jsx(RecordSections, { node: node })] }) })] }));
190
+ }
@@ -0,0 +1,20 @@
1
+ import { IconUser } from '@tabler/icons-react';
2
+ import { type TraceActor, type TraceStep } from '../client/trace-story.ts';
3
+ import type { TraceNode } from '../client/trace-view.ts';
4
+ /** An actor's icon, in the text's own colour. */
5
+ export declare function ActorMark({ actor, icon }: {
6
+ actor: TraceActor;
7
+ icon?: typeof IconUser;
8
+ }): import("react").JSX.Element;
9
+ /**
10
+ * The turn, told in order: what the user asked, each model call with the tool
11
+ * calls it asked for set in under it, what changed course, and how it ended.
12
+ * A line opens its span.
13
+ */
14
+ export declare function TraceStory({ steps, selectedId, matches, onSelect, }: {
15
+ steps: readonly TraceStep[];
16
+ selectedId: string | undefined;
17
+ /** Spans the search matched; the others dim. Absent when nothing is searched. */
18
+ matches: ReadonlySet<string> | undefined;
19
+ onSelect: (node: TraceNode) => void;
20
+ }): import("react").JSX.Element;
@@ -0,0 +1,108 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Badge } from '@astryxdesign/core/Badge';
3
+ import { HStack } from '@astryxdesign/core/HStack';
4
+ import { Icon } from '@astryxdesign/core/Icon';
5
+ import { Item } from '@astryxdesign/core/Item';
6
+ import { Text } from '@astryxdesign/core/Text';
7
+ import { Tooltip } from '@astryxdesign/core/Tooltip';
8
+ import { VStack } from '@astryxdesign/core/VStack';
9
+ import { IconAlertTriangle, IconBolt, IconInputAi, IconMessageCircle, IconServer, IconTool, IconUser, } from '@tabler/icons-react';
10
+ import { toolArguments, traceActor, traceOutcome, } from "../client/trace-story.js";
11
+ import { Arrive, Stream } from "./arrive.js";
12
+ import { useTraceFormat } from "./TraceValues.js";
13
+ /** Each actor's mark, shared by the story and the turn list. */
14
+ const ACTOR_ICON = {
15
+ user: IconUser,
16
+ model: IconInputAi,
17
+ tool: IconTool,
18
+ host: IconServer,
19
+ theorem: IconBolt,
20
+ error: IconAlertTriangle,
21
+ };
22
+ /** An actor's icon, in the text's own colour. */
23
+ export function ActorMark({ actor, icon }) {
24
+ return _jsx(Icon, { icon: icon ?? ACTOR_ICON[actor], size: "sm", color: "secondary" });
25
+ }
26
+ /** "city: Lisbon · to: USD": a tool call's plain arguments on one line. */
27
+ function argumentsLine(node, separator) {
28
+ return toolArguments(node)
29
+ .map(([key, value]) => (key ? `${key}: ${value}` : value))
30
+ .join(separator);
31
+ }
32
+ /** Duration, then cost when the span reported one. */
33
+ function StepMeasure({ node }) {
34
+ const format = useTraceFormat();
35
+ const cost = node.span.attributes['theorem.usage.cost_usd'];
36
+ return (_jsxs(VStack, { gap: 0, hAlign: "end", children: [_jsx(Text, { type: "supporting", hasTabularNumbers: true, children: format.duration(node.durationMs) }), typeof cost === 'number' ? (_jsx(Text, { type: "supporting", color: "secondary", hasTabularNumbers: true, children: format.usd(cost) })) : null] }));
37
+ }
38
+ function Offset({ ms }) {
39
+ const format = useTraceFormat();
40
+ return (_jsx(Text, { type: "supporting", color: "secondary", hasTabularNumbers: true, children: format.t('@theorem.panel.trace.offset', { duration: format.duration(ms) }) }));
41
+ }
42
+ /** A span step's line: the tools a call asked for or that it wrote, a tool's arguments, else the span's own label. */
43
+ function spanLine(step, format) {
44
+ const { node } = step;
45
+ if (node.meta.type === 'tool')
46
+ return argumentsLine(node, format.t('@theorem.panel.trace.separator'));
47
+ if (node.meta.type !== 'call' && node.meta.type !== 'response')
48
+ return node.meta.label;
49
+ return step.requested > 0
50
+ ? format.t('@theorem.panel.trace.story.requested', { count: step.requested })
51
+ : format.t('@theorem.panel.trace.story.wrote');
52
+ }
53
+ /** What a span step says under its name: how it ended when that is news, then its line. */
54
+ function spanDescription(step, format) {
55
+ const outcome = traceOutcome(step.node);
56
+ const line = spanLine(step, format);
57
+ if (!outcome)
58
+ return line;
59
+ return (_jsxs(HStack, { gap: 1, align: "center", wrap: "wrap", children: [_jsx(Tooltip, { content: outcome.doc ?? outcome.label, children: _jsx(Badge, { variant: outcome.tone, label: outcome.label }) }), line ? _jsx(Text, { type: "supporting", children: line }) : null] }));
60
+ }
61
+ function Quote({ text }) {
62
+ return (_jsx(Text, { color: "secondary", maxLines: 3, hasTruncateTooltip: false, children: text }));
63
+ }
64
+ function AskItem({ step, isSelected, select }) {
65
+ const { t } = useTraceFormat();
66
+ return (_jsx(Item, { startContent: _jsx(ActorMark, { actor: "user" }), label: _jsx(Text, { weight: "medium", children: t('@theorem.panel.trace.story.asked') }), description: _jsx(Quote, { text: step.text }), endContent: _jsx(Offset, { ms: 0 }), align: "start", density: "compact", onClick: select, isSelected: isSelected }));
67
+ }
68
+ function SpanItem({ step, isSelected, select }) {
69
+ const format = useTraceFormat();
70
+ return (_jsx(Item, { startContent: _jsx(ActorMark, { actor: traceActor(step.node) }), label: _jsx(Text, { weight: "medium", maxLines: 1, children: step.node.meta.subject ?? step.node.meta.label }), description: spanDescription(step, format), endContent: _jsx(StepMeasure, { node: step.node }), align: "start", density: "compact", onClick: select, isSelected: isSelected }));
71
+ }
72
+ function EventItem({ step, isSelected, select }) {
73
+ const { t } = useTraceFormat();
74
+ return (_jsx(Item, { startContent: _jsx(ActorMark, { actor: "theorem" }), label: _jsx(Tooltip, { content: step.doc, children: _jsx(Text, { weight: "medium", children: step.label }) }), description: step.detail.join(t('@theorem.panel.trace.separator')), endContent: _jsx(Offset, { ms: step.offsetMs }), align: "start", density: "compact", onClick: select, isSelected: isSelected }));
75
+ }
76
+ function AnswerItem({ step, isSelected, select }) {
77
+ const { t } = useTraceFormat();
78
+ const failed = step.node.span.status.code === 'ERROR';
79
+ const answer = step.text ? _jsx(Quote, { text: step.text }) : undefined;
80
+ return (_jsx(Item, { startContent: _jsx(ActorMark, { actor: failed ? 'error' : 'model', icon: failed ? undefined : IconMessageCircle }), label: _jsx(Text, { weight: "medium", children: t(failed ? '@theorem.panel.trace.story.failed' : '@theorem.panel.trace.story.answered') }), description: failed ? traceOutcome(step.node)?.label : answer, endContent: _jsx(Offset, { ms: step.offsetMs }), align: "start", density: "compact", onClick: select, isSelected: isSelected }));
81
+ }
82
+ function StepBody({ step, isSelected, select, }) {
83
+ switch (step.kind) {
84
+ case 'ask':
85
+ return _jsx(AskItem, { step: step, isSelected: isSelected, select: select });
86
+ case 'span':
87
+ return _jsx(SpanItem, { step: step, isSelected: isSelected, select: select });
88
+ case 'event':
89
+ return _jsx(EventItem, { step: step, isSelected: isSelected, select: select });
90
+ case 'answer':
91
+ return _jsx(AnswerItem, { step: step, isSelected: isSelected, select: select });
92
+ }
93
+ }
94
+ function StepItem({ step, isSelected, isDimmed, onSelect, }) {
95
+ return (_jsx(Arrive, { children: _jsx("div", { style: {
96
+ paddingInlineStart: step.kind === 'span' && step.nested ? 20 : 0,
97
+ opacity: isDimmed ? 0.35 : 1,
98
+ transition: 'opacity 120ms ease',
99
+ }, children: _jsx(StepBody, { step: step, isSelected: isSelected, select: () => onSelect(step.node) }) }) }));
100
+ }
101
+ /**
102
+ * The turn, told in order: what the user asked, each model call with the tool
103
+ * calls it asked for set in under it, what changed course, and how it ended.
104
+ * A line opens its span.
105
+ */
106
+ export function TraceStory({ steps, selectedId, matches, onSelect, }) {
107
+ return (_jsx(Stream, { children: _jsx(VStack, { gap: 0, children: steps.map((step) => (_jsx(StepItem, { step: step, isSelected: step.kind === 'span' ? step.node.id === selectedId : false, isDimmed: matches !== undefined && !matches.has(step.node.id), onSelect: onSelect }, step.id))) }) }));
108
+ }
@@ -0,0 +1,36 @@
1
+ import { type TraceAttributeGroup, type TraceAttributeMeta, type TraceRecord } from '@theoremjs/agents';
2
+ import { type TraceSum, type TraceTokenSum } from '../client/trace-view.ts';
3
+ import { type LabelText } from './labels.ts';
4
+ /** Width of every label column in the panel's lists, so they line up. */
5
+ export declare const TRACE_LABEL_PX = 120;
6
+ export type AttributeSection = {
7
+ key: TraceAttributeGroup | 'other';
8
+ attributes: Record<string, unknown>;
9
+ };
10
+ /** A span's attributes by catalog group, in the catalog's order; keys it does not name last. */
11
+ export declare function attributeSections(attributes: Readonly<Record<string, unknown>>): AttributeSection[];
12
+ /** Formats for trace values, in the viewer's locale. */
13
+ export interface TraceFormat {
14
+ t: LabelText;
15
+ number(value: number): string;
16
+ usd(value: number): string;
17
+ duration(ms: number): string;
18
+ list(items: readonly string[]): string;
19
+ /** A total, worded as partial or estimated when it is. */
20
+ sum(sum: TraceSum | TraceTokenSum, format: (value: number) => string): string;
21
+ }
22
+ export declare function useTraceFormat(): TraceFormat;
23
+ /** One attribute value, read by its catalog entry; a key the catalog does not name reads by its shape. */
24
+ export declare function TraceValue({ record, meta, value, }: {
25
+ record: TraceRecord;
26
+ meta: TraceAttributeMeta | undefined;
27
+ value: unknown;
28
+ }): import("react").JSX.Element;
29
+ /** Attributes as label and value rows, worded by `metaOf`; a key it does not name shows as recorded. */
30
+ export declare function TraceAttributeList({ record, attributes, metaOf, maxNumOfItems, title, }: {
31
+ record: TraceRecord;
32
+ attributes: Readonly<Record<string, unknown>>;
33
+ metaOf: (key: string) => TraceAttributeMeta | undefined;
34
+ maxNumOfItems?: number;
35
+ title?: string;
36
+ }): import("react").JSX.Element | null;