@theoremjs/react 0.3.0 → 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 (258) hide show
  1. package/README.md +728 -202
  2. package/client/composer-hints.js +1 -1
  3. package/client/decision-images.d.ts +76 -0
  4. package/client/decision-images.js +139 -0
  5. package/client/decision-transport.d.ts +26 -4
  6. package/client/decision-transport.js +79 -6
  7. package/client/embedding-input.d.ts +84 -0
  8. package/client/embedding-input.js +194 -0
  9. package/client/embedding-space.d.ts +82 -0
  10. package/client/embedding-space.js +389 -0
  11. package/client/embedding-transport.d.ts +40 -0
  12. package/client/embedding-transport.js +71 -0
  13. package/client/failure.d.ts +7 -10
  14. package/client/failure.js +9 -9
  15. package/client/host-call.d.ts +1 -1
  16. package/client/host-call.js +7 -2
  17. package/client/host-transport.d.ts +2 -0
  18. package/client/host-transport.js +3 -2
  19. package/client/index.d.ts +19 -11
  20. package/client/index.js +14 -10
  21. package/client/ink-waveform.d.ts +1 -1
  22. package/client/ink-waveform.js +1 -2
  23. package/client/live/apply-live-turn-tool-event.js +1 -1
  24. package/client/live/live-captions.d.ts +30 -0
  25. package/client/live/live-captions.js +105 -1
  26. package/client/live/live-mic-forward.d.ts +1 -0
  27. package/client/live/live-mic-forward.js +11 -2
  28. package/client/live/live-page-tool.d.ts +34 -0
  29. package/client/live/live-page-tool.js +11 -0
  30. package/client/live/live-state.d.ts +4 -2
  31. package/client/live/live-state.js +2 -0
  32. package/client/live/live-video.js +1 -1
  33. package/client/live/run-live-tool-call.d.ts +7 -2
  34. package/client/live/run-live-tool-call.js +48 -10
  35. package/client/live/use-live-caption-log.d.ts +17 -0
  36. package/client/live/use-live-caption-log.js +51 -0
  37. package/client/live-client.d.ts +52 -4
  38. package/client/live-client.js +250 -59
  39. package/client/live-messages.d.ts +51 -13
  40. package/client/live-messages.js +42 -9
  41. package/client/page-dispatch.d.ts +15 -0
  42. package/client/page-dispatch.js +63 -0
  43. package/client/run-commit.d.ts +16 -43
  44. package/client/run-commit.js +26 -101
  45. package/client/run-session.d.ts +40 -41
  46. package/client/run-session.js +104 -112
  47. package/client/schema-fields.js +27 -6
  48. package/client/shaped-data.js +37 -8
  49. package/client/source-citations.js +1 -1
  50. package/client/space-geometry.d.ts +39 -0
  51. package/client/space-geometry.js +183 -0
  52. package/client/state-fields.js +1 -1
  53. package/client/tool-result.js +30 -12
  54. package/client/tool-resume.d.ts +18 -1
  55. package/client/tool-resume.js +4 -1
  56. package/client/trace-feed.d.ts +1 -1
  57. package/client/trace-story.d.ts +2 -2
  58. package/client/trace-story.js +43 -19
  59. package/client/trace-view.d.ts +2 -2
  60. package/client/trace-view.js +56 -16
  61. package/client/transcript-groups.d.ts +28 -2
  62. package/client/transcript-groups.js +63 -13
  63. package/client/transcript-schema.d.ts +10 -0
  64. package/client/transcript-schema.js +120 -0
  65. package/client/transport.d.ts +114 -26
  66. package/client/transport.js +106 -32
  67. package/client/turn-client.d.ts +17 -8
  68. package/client/turn-client.js +26 -31
  69. package/client/voice-recorder.d.ts +1 -1
  70. package/client/voice-recorder.js +2 -5
  71. package/client/wire-line.js +5 -5
  72. package/client/worklets/mic-capture.js +9 -9
  73. package/components/InkWaveform.d.ts +12 -1
  74. package/components/InkWaveform.js +65 -42
  75. package/components/live/use-live-runner-controls.d.ts +3 -4
  76. package/components/live/use-live-runner-controls.js +6 -10
  77. package/components/live/use-live-runner-model.d.ts +10 -6
  78. package/components/live/use-live-runner-model.js +29 -14
  79. package/components/live/use-live-runner-ui.d.ts +10 -8
  80. package/components/live/use-live-runner-ui.js +19 -11
  81. package/components/live/use-live-session-client.d.ts +4 -4
  82. package/components/live/use-live-session-client.js +11 -8
  83. package/components/use-composer-voice.d.ts +4 -4
  84. package/components/use-composer-voice.js +8 -8
  85. package/components/use-editor-selection.js +4 -1
  86. package/components/use-voice-playback.d.ts +2 -1
  87. package/components/use-voice-playback.js +4 -4
  88. package/hooks/use-described.d.ts +5 -1
  89. package/hooks/use-described.js +11 -9
  90. package/hooks/use-embedding-index.d.ts +27 -0
  91. package/hooks/use-embedding-index.js +43 -0
  92. package/hooks/use-one-call.d.ts +31 -0
  93. package/hooks/use-one-call.js +76 -0
  94. package/hooks/use-page-tool-warnings.d.ts +6 -0
  95. package/hooks/use-page-tool-warnings.js +25 -0
  96. package/hooks/use-second-ticker.d.ts +2 -0
  97. package/hooks/use-second-ticker.js +13 -0
  98. package/hooks/use-theorem-chat-actions.d.ts +25 -21
  99. package/hooks/use-theorem-chat-actions.js +67 -45
  100. package/hooks/use-theorem-chat-state.d.ts +6 -6
  101. package/hooks/use-theorem-chat-state.js +13 -9
  102. package/hooks/use-theorem-chat.d.ts +48 -14
  103. package/hooks/use-theorem-chat.js +329 -141
  104. package/hooks/use-theorem-decision.d.ts +5 -10
  105. package/hooks/use-theorem-decision.js +4 -67
  106. package/hooks/use-theorem-embedding.d.ts +18 -0
  107. package/hooks/use-theorem-embedding.js +12 -0
  108. package/hooks/use-theorem-host.d.ts +5 -4
  109. package/hooks/use-theorem-host.js +26 -8
  110. package/hooks/use-theorem-interface.d.ts +6 -3
  111. package/hooks/use-theorem-interface.js +12 -22
  112. package/index.d.ts +6 -3
  113. package/index.js +5 -2
  114. package/live.d.ts +1 -0
  115. package/live.js +1 -1
  116. package/package.json +6 -5
  117. package/server/checkpoint-ownership.d.ts +6 -0
  118. package/server/checkpoint-ownership.js +42 -0
  119. package/server/conversation-store.d.ts +92 -0
  120. package/server/conversation-store.js +131 -0
  121. package/server/conversation.d.ts +193 -0
  122. package/server/conversation.js +552 -0
  123. package/server/decision-handler.d.ts +12 -4
  124. package/server/decision-handler.js +29 -38
  125. package/server/embedding-handler.d.ts +33 -0
  126. package/server/embedding-handler.js +45 -0
  127. package/server/handler.d.ts +58 -20
  128. package/server/handler.js +441 -238
  129. package/server/mod.d.ts +15 -6
  130. package/server/mod.js +13 -5
  131. package/server/page-dispatch.d.ts +22 -0
  132. package/server/page-dispatch.js +127 -0
  133. package/server/request-body.d.ts +2 -0
  134. package/server/request-body.js +42 -0
  135. package/server/request-check.d.ts +6 -1
  136. package/server/request-check.js +27 -12
  137. package/server/session-authority.d.ts +8 -0
  138. package/server/session-authority.js +78 -0
  139. package/server/session-boundary.d.ts +26 -0
  140. package/server/session-boundary.js +64 -0
  141. package/server/session-identity.d.ts +16 -0
  142. package/server/session-identity.js +41 -0
  143. package/server/session-limits.d.ts +12 -0
  144. package/server/session-limits.js +59 -0
  145. package/server/session-store.d.ts +69 -20
  146. package/server/session-store.js +220 -5
  147. package/server/single-action.d.ts +21 -0
  148. package/server/single-action.js +30 -0
  149. package/server/steer-inbox.js +1 -1
  150. package/server/tool-operations.d.ts +6 -0
  151. package/server/tool-operations.js +132 -0
  152. package/server/turn-input.d.ts +10 -0
  153. package/server/turn-input.js +29 -0
  154. package/styles/ink-controls.css +78 -78
  155. package/ui/CardWall.d.ts +10 -0
  156. package/ui/CardWall.js +61 -0
  157. package/ui/ChatComposerBar.d.ts +28 -5
  158. package/ui/ChatComposerBar.js +85 -30
  159. package/ui/ChatTranscript.d.ts +14 -1
  160. package/ui/ChatTranscript.js +110 -57
  161. package/ui/ConsoleFrame.d.ts +61 -4
  162. package/ui/ConsoleFrame.js +109 -9
  163. package/ui/DecisionAnswers.d.ts +40 -2
  164. package/ui/DecisionAnswers.js +166 -35
  165. package/ui/DecisionImages.d.ts +16 -0
  166. package/ui/DecisionImages.js +46 -0
  167. package/ui/EmbeddingDocuments.d.ts +78 -0
  168. package/ui/EmbeddingDocuments.js +278 -0
  169. package/ui/EmbeddingQuery.d.ts +27 -0
  170. package/ui/EmbeddingQuery.js +95 -0
  171. package/ui/EmbeddingResults.d.ts +41 -0
  172. package/ui/EmbeddingResults.js +165 -0
  173. package/ui/EmbeddingSpace.d.ts +26 -0
  174. package/ui/EmbeddingSpace.js +106 -0
  175. package/ui/LiveCaptionsPanel.d.ts +22 -0
  176. package/ui/LiveCaptionsPanel.js +27 -0
  177. package/ui/LiveRunner.d.ts +6 -4
  178. package/ui/LiveRunner.js +42 -55
  179. package/ui/PaneState.d.ts +33 -0
  180. package/ui/PaneState.js +50 -0
  181. package/ui/SchemaFields.d.ts +1 -1
  182. package/ui/SchemaFields.js +54 -26
  183. package/ui/ShapedData.js +73 -28
  184. package/ui/SidePanel.d.ts +74 -5
  185. package/ui/SidePanel.js +82 -9
  186. package/ui/StateFields.d.ts +10 -2
  187. package/ui/StateFields.js +56 -13
  188. package/ui/TheoremChat.d.ts +65 -14
  189. package/ui/TheoremChat.js +66 -78
  190. package/ui/TheoremDecision.d.ts +12 -20
  191. package/ui/TheoremDecision.js +78 -35
  192. package/ui/TheoremEmbedding.d.ts +27 -0
  193. package/ui/TheoremEmbedding.js +122 -0
  194. package/ui/TheoremHost.d.ts +22 -5
  195. package/ui/TheoremHost.js +127 -37
  196. package/ui/ToolGateCard.d.ts +5 -1
  197. package/ui/ToolGateCard.js +30 -23
  198. package/ui/ToolResult.js +12 -10
  199. package/ui/ToolResultCharts.js +29 -12
  200. package/ui/TraceCharts.d.ts +2 -2
  201. package/ui/TraceCharts.js +48 -17
  202. package/ui/TraceGuardrails.d.ts +3 -2
  203. package/ui/TraceGuardrails.js +24 -6
  204. package/ui/TraceInspector.d.ts +11 -1
  205. package/ui/TraceInspector.js +45 -28
  206. package/ui/TraceInspectorPanel.d.ts +31 -9
  207. package/ui/TraceInspectorPanel.js +77 -39
  208. package/ui/TraceOverview.d.ts +7 -3
  209. package/ui/TraceOverview.js +44 -14
  210. package/ui/TraceSpanDetail.js +24 -22
  211. package/ui/TraceStory.js +9 -8
  212. package/ui/TraceValues.js +19 -9
  213. package/ui/TraceWaterfall.js +12 -9
  214. package/ui/VoiceNote.js +4 -4
  215. package/ui/approval-heading.d.ts +4 -0
  216. package/ui/approval-heading.js +9 -0
  217. package/ui/arrive.d.ts +18 -0
  218. package/ui/arrive.js +46 -0
  219. package/ui/built/theme.css +86 -68
  220. package/ui/built/theme.css.d.ts +9 -0
  221. package/ui/built/theorem.d.ts +3 -3
  222. package/ui/built/theorem.js +34 -5
  223. package/ui/built/theorem.variants.d.ts +8 -2
  224. package/ui/code-language.d.ts +12 -0
  225. package/ui/code-language.js +50 -0
  226. package/ui/disclosure-motion.js +53 -9
  227. package/ui/embedding-space-gl.d.ts +37 -0
  228. package/ui/embedding-space-gl.js +663 -0
  229. package/ui/embedding-space-view.d.ts +8 -0
  230. package/ui/embedding-space-view.js +8 -0
  231. package/ui/glide.d.ts +7 -0
  232. package/ui/glide.js +44 -0
  233. package/ui/icons.js +2 -1
  234. package/ui/index.d.ts +20 -9
  235. package/ui/index.js +20 -10
  236. package/ui/labels-provider.js +5 -2
  237. package/ui/labels.d.ts +374 -85
  238. package/ui/labels.js +1028 -188
  239. package/ui/markdown-plugins.d.ts +9 -0
  240. package/ui/markdown-plugins.js +13 -0
  241. package/ui/mcp-icon.d.ts +6 -0
  242. package/ui/mcp-icon.js +8 -0
  243. package/ui/row-keys.d.ts +19 -0
  244. package/ui/row-keys.js +33 -0
  245. package/ui/theme.d.ts +1 -1
  246. package/ui/theme.js +2 -2
  247. package/ui/theorem-theme.js +32 -10
  248. package/ui/trace-palette.d.ts +2 -16
  249. package/ui/trace-palette.js +2 -16
  250. package/ui/trace-patterns.d.ts +11 -3
  251. package/ui/trace-patterns.js +16 -3
  252. package/ui/transcript-copy-text.js +1 -0
  253. package/ui/wall-columns.d.ts +8 -0
  254. package/ui/wall-columns.js +19 -0
  255. package/client/walk-away.d.ts +0 -34
  256. package/client/walk-away.js +0 -48
  257. package/server/walk-away.d.ts +0 -22
  258. package/server/walk-away.js +0 -41
@@ -15,9 +15,11 @@ import { IconArrowLeft, IconX } from '@tabler/icons-react';
15
15
  import { inlineContent, TRACE_ATTRIBUTE_GROUPS, TRACE_FIELDS, TRACE_SPAN_TYPES, TRACE_STATUS, traceAttributeMeta, traceEventAttributeMeta, traceEventMeta, } from '@theoremjs/agents';
16
16
  import { messageText, storedValue, traceActor, traceOutcome } from "../client/trace-story.js";
17
17
  import { nanosToMs } from "../client/trace-view.js";
18
+ import { keyedByContent } from "./row-keys.js";
18
19
  import { ShapedData } from "./ShapedData.js";
20
+ import { PanePanel, Prose } from "./SidePanel.js";
19
21
  import { ActorMark } from "./TraceStory.js";
20
- import { attributeSections, TRACE_LABEL_PX, TraceAttributeList, TraceValue, useTraceFormat } from "./TraceValues.js";
22
+ import { attributeSections, TRACE_LABEL_PX, TraceAttributeList, TraceValue, useTraceFormat, } from "./TraceValues.js";
21
23
  /** A span's own field, read as an attribute of that format. */
22
24
  function fieldMeta(field, format) {
23
25
  return { ...field, format, group: 'record' };
@@ -37,12 +39,12 @@ function Section({ title, children }) {
37
39
  }
38
40
  function EventList({ node }) {
39
41
  const format = useTraceFormat();
40
- return (_jsx(VStack, { gap: 3, children: node.span.events.map((event, index) => {
42
+ return (_jsx(VStack, { gap: 3, children: keyedByContent(node.span.events, (event) => `${event.name}:${event.timeUnixNano}`).map(({ item: event, key }) => {
41
43
  const offset = format.t('@theorem.panel.trace.offset', {
42
44
  duration: format.duration(nanosToMs(event.timeUnixNano) - node.startMs),
43
45
  });
44
46
  const label = traceEventMeta(event.name)?.label ?? event.name;
45
- 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) })] }, `${event.name}:${event.timeUnixNano}:${index}`));
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));
46
48
  }) }));
47
49
  }
48
50
  function LinkList({ node }) {
@@ -54,14 +56,16 @@ const SPAN_FIELD_VALUES = {
54
56
  traceId: (node) => node.span.traceId,
55
57
  spanId: (node) => node.span.spanId,
56
58
  };
57
- /** What the span was, how long it took, what it cost and when it started. */
59
+ /** What the span was, how long it took, what it cost, and when it started. */
58
60
  function spanFacts(node, turnStartMs, format) {
59
61
  const cost = node.span.attributes['theorem.usage.cost_usd'];
60
62
  return [
61
63
  node.meta.label,
62
64
  format.duration(node.durationMs),
63
65
  ...(typeof cost === 'number' ? [format.usd(cost)] : []),
64
- format.t('@theorem.panel.trace.offset', { duration: format.duration(node.startMs - turnStartMs) }),
66
+ format.t('@theorem.panel.trace.offset', {
67
+ duration: format.duration(node.startMs - turnStartMs),
68
+ }),
65
69
  ].join(format.t('@theorem.panel.trace.separator'));
66
70
  }
67
71
  function OutcomeBadge({ outcome }) {
@@ -70,24 +74,18 @@ function OutcomeBadge({ outcome }) {
70
74
  return (_jsx(HoverTip, { content: outcome.doc ?? outcome.label, children: _jsx(Badge, { variant: outcome.tone, label: outcome.label }) }));
71
75
  }
72
76
  /** The span's status message, unless the outcome badge already says it. */
73
- function StatusMessage({ node, outcome }) {
77
+ function StatusMessage({ node, outcome, }) {
74
78
  const message = node.span.status.message;
75
79
  if (!message || message.toLowerCase() === outcome?.label.toLowerCase())
76
80
  return null;
77
81
  return _jsx(Text, { color: "secondary", children: message });
78
82
  }
79
- /** Back (or close), then who acted, what it was, how it ended, how long it took and what it cost. */
80
- function SpanHeader({ node, turnStartMs, onBack, isClose }) {
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, }) {
81
85
  const format = useTraceFormat();
82
86
  const outcome = traceOutcome(node);
83
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 })] }));
84
88
  }
85
- function Panel({ title, doc, children }) {
86
- return (_jsx(Card, { padding: 3, variant: "muted", style: { background: 'var(--color-background-surface)' }, children: _jsxs(VStack, { gap: 2, children: [_jsx(HoverTip, { content: doc ?? title, children: _jsx(Text, { type: "supporting", color: "secondary", children: title }) }), children] }) }));
87
- }
88
- function Prose({ text }) {
89
- return _jsx("span", { style: { whiteSpace: 'pre-wrap', overflowWrap: 'anywhere' }, children: text });
90
- }
91
89
  function parsed(value) {
92
90
  if (typeof value !== 'string')
93
91
  return value;
@@ -115,9 +113,9 @@ function PartView({ part }) {
115
113
  }
116
114
  /** Messages as the model saw them: each one's role, then its parts. */
117
115
  function MessageList({ messages }) {
118
- return (_jsx(VStack, { gap: 3, children: messages.map((message, index) => (_jsxs(VStack, { gap: 1, children: [_jsx(HStack, { children: _jsx(Token, { label: String(message.role ?? ''), size: "sm", color: "gray" }) }), Array.isArray(message.parts)
119
- ? message.parts.filter(isObject).map((part, at) => _jsx(PartView, { part: part }, at))
120
- : null] }, index))) }));
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))) }));
121
119
  }
122
120
  function messagesOf(node, key) {
123
121
  const value = inlineContent(node.record, node.span.attributes[key]);
@@ -131,13 +129,13 @@ function label(key) {
131
129
  function DataPanel({ attribute, value }) {
132
130
  if (value === undefined)
133
131
  return null;
134
- return (_jsx(Panel, { ...label(attribute), children: _jsx(ShapedData, { value: value }) }));
132
+ return (_jsx(PanePanel, { ...label(attribute), children: _jsx(ShapedData, { value: value }) }));
135
133
  }
136
134
  /** Text under its attribute's name; nothing when there is none. */
137
135
  function ProsePanel({ attribute, text }) {
138
136
  if (typeof text !== 'string' || !text)
139
137
  return null;
140
- return (_jsx(Panel, { ...label(attribute), children: _jsx(Prose, { text: text }) }));
138
+ return (_jsx(PanePanel, { ...label(attribute), children: _jsx(Prose, { text: text }) }));
141
139
  }
142
140
  function TurnIO({ node }) {
143
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') })] }));
@@ -145,7 +143,7 @@ function TurnIO({ node }) {
145
143
  function CallIO({ node }) {
146
144
  const input = messagesOf(node, 'gen_ai.input.messages');
147
145
  const output = messagesOf(node, 'gen_ai.output.messages');
148
- return (_jsxs(_Fragment, { children: [output.length > 0 ? (_jsx(Panel, { ...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] }));
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] }));
149
147
  }
150
148
  function ToolIO({ node }) {
151
149
  const { attributes } = node.span;
@@ -166,7 +164,7 @@ function SpanIO({ node }) {
166
164
  return null;
167
165
  }
168
166
  }
169
- /** The span's own fields: its type, start and IDs. */
167
+ /** The span's own fields: its type, start, and IDs. */
170
168
  function SpanFields({ node }) {
171
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))) }));
172
170
  }
@@ -184,5 +182,9 @@ export function TraceSpanDetail({ node, turnStartMs, isClose = false, onBack, on
184
182
  const { span, record } = node;
185
183
  const sections = attributeSections(span.attributes);
186
184
  const usage = sections.find((section) => section.key === 'usage');
187
- return (_jsxs(VStack, { gap: 4, children: [_jsx(SpanHeader, { node: node, turnStartMs: turnStartMs, onBack: onBack, isClose: isClose }), _jsx(SpanIO, { node: node }), usage ? (_jsx(Panel, { 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(Panel, { 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.filter((section) => section !== usage).map((section) => (_jsx(Section, { title: section.key === 'other' ? t('@theorem.panel.trace.other') : 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 })] }) })] }));
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 })] }) })] }));
188
190
  }
package/ui/TraceStory.js CHANGED
@@ -7,7 +7,8 @@ import { Text } from '@astryxdesign/core/Text';
7
7
  import { Tooltip } from '@astryxdesign/core/Tooltip';
8
8
  import { VStack } from '@astryxdesign/core/VStack';
9
9
  import { IconAlertTriangle, IconBolt, IconInputAi, IconMessageCircle, IconServer, IconTool, IconUser, } from '@tabler/icons-react';
10
- import { toolArguments, traceActor, traceOutcome } from "../client/trace-story.js";
10
+ import { toolArguments, traceActor, traceOutcome, } from "../client/trace-story.js";
11
+ import { Arrive, Stream } from "./arrive.js";
11
12
  import { useTraceFormat } from "./TraceValues.js";
12
13
  /** Each actor's mark, shared by the story and the turn list. */
13
14
  const ACTOR_ICON = {
@@ -78,7 +79,7 @@ function AnswerItem({ step, isSelected, select }) {
78
79
  const answer = step.text ? _jsx(Quote, { text: step.text }) : undefined;
79
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 }));
80
81
  }
81
- function StepBody({ step, isSelected, select }) {
82
+ function StepBody({ step, isSelected, select, }) {
82
83
  switch (step.kind) {
83
84
  case 'ask':
84
85
  return _jsx(AskItem, { step: step, isSelected: isSelected, select: select });
@@ -91,11 +92,11 @@ function StepBody({ step, isSelected, select }) {
91
92
  }
92
93
  }
93
94
  function StepItem({ step, isSelected, isDimmed, onSelect, }) {
94
- return (_jsx("div", { style: {
95
- paddingInlineStart: step.kind === 'span' && step.nested ? 20 : 0,
96
- opacity: isDimmed ? 0.35 : 1,
97
- transition: 'opacity 120ms ease',
98
- }, children: _jsx(StepBody, { step: step, isSelected: isSelected, select: () => onSelect(step.node) }) }));
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) }) }) }));
99
100
  }
100
101
  /**
101
102
  * The turn, told in order: what the user asked, each model call with the tool
@@ -103,5 +104,5 @@ function StepItem({ step, isSelected, isDimmed, onSelect, }) {
103
104
  * A line opens its span.
104
105
  */
105
106
  export function TraceStory({ steps, selectedId, matches, onSelect, }) {
106
- return (_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))) }));
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))) }) }));
107
108
  }
package/ui/TraceValues.js CHANGED
@@ -7,11 +7,12 @@ import { Text } from '@astryxdesign/core/Text';
7
7
  import { Timestamp } from '@astryxdesign/core/Timestamp';
8
8
  import { Tooltip } from '@astryxdesign/core/Tooltip';
9
9
  import { VStack } from '@astryxdesign/core/VStack';
10
- import { useMemo, useState } from 'react';
11
10
  import { inlineContent, TRACE_ATTRIBUTE_GROUPS, traceAttributeMeta, } from '@theoremjs/agents';
12
- import { nanosToMs, traceValueShape } from "../client/trace-view.js";
11
+ import { useMemo, useState } from 'react';
12
+ import { nanosToMs, traceValueShape, } from "../client/trace-view.js";
13
13
  import { workDuration } from "./labels.js";
14
14
  import { useLabels } from "./labels-provider.js";
15
+ import { keyedByContent } from "./row-keys.js";
15
16
  /** Width of every label column in the panel's lists, so they line up. */
16
17
  export const TRACE_LABEL_PX = 120;
17
18
  /** A span's attributes by catalog group, in the catalog's order; keys it does not name last. */
@@ -21,7 +22,10 @@ export function attributeSections(attributes) {
21
22
  const group = traceAttributeMeta(key)?.group ?? 'other';
22
23
  byGroup.set(group, { ...byGroup.get(group), [key]: value });
23
24
  }
24
- const order = [...Object.keys(TRACE_ATTRIBUTE_GROUPS), 'other'];
25
+ const order = [
26
+ ...Object.keys(TRACE_ATTRIBUTE_GROUPS),
27
+ 'other',
28
+ ];
25
29
  return order.flatMap((key) => {
26
30
  const grouped = byGroup.get(key);
27
31
  return grouped ? [{ key, attributes: grouped }] : [];
@@ -32,7 +36,11 @@ export function useTraceFormat() {
32
36
  const locale = useLocale();
33
37
  return useMemo(() => {
34
38
  const number = new Intl.NumberFormat(locale);
35
- const usd = new Intl.NumberFormat(locale, { style: 'currency', currency: 'USD', maximumFractionDigits: 6 });
39
+ const usd = new Intl.NumberFormat(locale, {
40
+ style: 'currency',
41
+ currency: 'USD',
42
+ maximumFractionDigits: 6,
43
+ });
36
44
  const list = new Intl.ListFormat(locale, { type: 'conjunction' });
37
45
  return {
38
46
  t,
@@ -41,7 +49,9 @@ export function useTraceFormat() {
41
49
  duration: (ms) => workDuration(t, ms),
42
50
  list: (items) => list.format(items),
43
51
  sum(total, format) {
44
- const value = 'estimated' in total && total.estimated ? t('@theorem.panel.trace.about', { value: format(total.value) }) : format(total.value);
52
+ const value = 'estimated' in total && total.estimated
53
+ ? t('@theorem.panel.trace.about', { value: format(total.value) })
54
+ : format(total.value);
45
55
  return total.complete ? value : t('@theorem.panel.trace.at_least', { value });
46
56
  },
47
57
  };
@@ -75,16 +85,16 @@ function StringValue({ meta, value }) {
75
85
  if (option)
76
86
  return _jsx(OptionValue, { option: option });
77
87
  if (meta?.format === 'time')
78
- return _jsx(Timestamp, { value: nanosToMs(value), format: "system_date_time", size: "base", color: "primary" });
88
+ return (_jsx(Timestamp, { value: nanosToMs(value), format: "system_date_time", size: "base", color: "primary" }));
79
89
  return _jsx(Text, { wordBreak: "break-word", children: value });
80
90
  }
81
- function ScalarValue({ meta, value }) {
91
+ function ScalarValue({ meta, value, }) {
82
92
  const format = useTraceFormat();
83
93
  if (typeof value === 'boolean')
84
94
  return _jsx(Text, { children: format.t(value ? '@theorem.panel.trace.yes' : '@theorem.panel.trace.no') });
85
95
  return _jsx(Text, { hasTabularNumbers: true, children: formatNumber(format, meta, value) });
86
96
  }
87
- function ListValue({ meta, value }) {
97
+ function ListValue({ meta, value, }) {
88
98
  const format = useTraceFormat();
89
99
  return _jsx(Text, { children: format.list(value.map((item) => meta?.options?.[item]?.label ?? item)) });
90
100
  }
@@ -99,7 +109,7 @@ export function TraceValue({ record, meta, value, }) {
99
109
  case 'list':
100
110
  return _jsx(ListValue, { meta: meta, value: shape.value });
101
111
  case 'fields':
102
- return (_jsx(VStack, { gap: 2, children: shape.items.map((item, index) => (_jsx(TraceAttributeList, { record: record, attributes: item, metaOf: (key) => shape.fields[key] }, index))) }));
112
+ return (_jsx(VStack, { gap: 2, children: keyedByContent(shape.items, (item) => JSON.stringify(item)).map(({ item, key }) => (_jsx(TraceAttributeList, { record: record, attributes: item, metaOf: (key) => shape.fields[key] }, key))) }));
103
113
  case 'stored':
104
114
  return _jsx(StoredText, { record: record, value: value });
105
115
  }
@@ -7,11 +7,11 @@ import { VStack } from '@astryxdesign/core/VStack';
7
7
  import { IconZoomOut } from '@tabler/icons-react';
8
8
  import { useMemo, useRef, useState } from 'react';
9
9
  import { Area, AreaChart, Bar, BarChart, CartesianGrid, Cell, ReferenceArea, ResponsiveContainer, Tooltip, XAxis, YAxis, } from 'recharts';
10
- import { traceActivity, traceActor, traceBars, traceOutcome } from "../client/trace-story.js";
10
+ import { traceActivity, traceActor, traceBars, traceOutcome, } from "../client/trace-story.js";
11
11
  import { ChartFrame, ChartTip, FIRST_WIDTH_PX } from "./TraceOverview.js";
12
+ import { useTraceFormat } from "./TraceValues.js";
12
13
  import { TRACE_HUE } from "./trace-palette.js";
13
14
  import { ACTOR_FILL, TRACE_RADIUS, traceFill } from "./trace-patterns.js";
14
- import { useTraceFormat } from "./TraceValues.js";
15
15
  /** Slices in the activity strip. */
16
16
  const BUCKETS = 120;
17
17
  /** Height of one span's row, in pixels. */
@@ -41,7 +41,9 @@ function BarTip({ active, payload }) {
41
41
  format.duration(node.durationMs),
42
42
  format.t('@theorem.panel.trace.offset', { duration: format.duration(from) }),
43
43
  ...(typeof cost === 'number' ? [format.usd(cost)] : []),
44
- ].join(format.t('@theorem.panel.trace.separator')) }), outcome ? (_jsx(Text, { type: "supporting", children: _jsx("span", { style: { color: outcome.tone === 'error' ? TRACE_HUE.oxblood : 'var(--color-text-secondary)' }, children: outcome.label }) })) : null] }) }));
44
+ ].join(format.t('@theorem.panel.trace.separator')) }), outcome ? (_jsx(Text, { type: "supporting", children: _jsx("span", { style: {
45
+ color: outcome.tone === 'error' ? TRACE_HUE.oxblood : 'var(--color-text-secondary)',
46
+ }, children: outcome.label }) })) : null] }) }));
45
47
  }
46
48
  /** A row's name, from the chart's left edge, set in by its depth and cut to the column. */
47
49
  function NameTick({ y: rawY, payload, rows, }) {
@@ -52,14 +54,16 @@ function NameTick({ y: rawY, payload, rows, }) {
52
54
  const indent = Math.min(row.bar.depth, 4) * INDENT_PX;
53
55
  const room = Math.floor((NAME_PX - indent - 10) / 6.2);
54
56
  const name = row.name.length > room ? `${row.name.slice(0, Math.max(1, room - 1))}…` : row.name;
55
- return (_jsxs("text", { x: indent, y: y, dy: "0.35em", fontSize: 11, fill: row.bar.node.span.status.code === 'ERROR' ? TRACE_HUE.oxblood : 'var(--color-text-secondary)', children: [_jsx("title", { children: row.name }), name] }));
57
+ return (_jsxs("text", { x: indent, y: y, dy: "0.35em", fontSize: 11, fill: row.bar.node.span.status.code === 'ERROR'
58
+ ? TRACE_HUE.oxblood
59
+ : 'var(--color-text-secondary)', children: [_jsx("title", { children: row.name }), name] }));
56
60
  }
57
61
  /** How busy the model and tools were over the turn; a drag across it picks the window to zoom into. */
58
- function ActivityStrip({ root, zoom, onZoom }) {
62
+ function ActivityStrip({ root, zoom, onZoom, }) {
59
63
  const activity = useMemo(() => traceActivity(root, BUCKETS), [root]);
60
64
  const total = Math.max(root.durationMs, 1);
61
65
  const [drag, setDrag] = useState(null);
62
- // Pointer events can outrun a render; the ref always holds the drag so far.
66
+ // why: Pointer events can outrun a render; the ref always holds the drag so far.
63
67
  const dragRef = useRef(null);
64
68
  const moveDrag = (next) => {
65
69
  dragRef.current = next;
@@ -76,14 +80,13 @@ function ActivityStrip({ root, zoom, onZoom }) {
76
80
  if (done) {
77
81
  const from = Math.min(done.from, done.to);
78
82
  const to = Math.max(done.from, done.to);
79
- // A click, not a drag: leave the zoom as it was.
80
83
  if (to - from >= total / BUCKETS)
81
84
  onZoom({ root: root.id, from, to });
82
85
  }
83
86
  moveDrag(null);
84
87
  };
85
88
  const shown = drag ?? zoom;
86
- return (_jsx("div", { style: { cursor: 'col-resize', userSelect: 'none', touchAction: 'none' }, onPointerDown: (event) => {
89
+ return (_jsx("div", { role: "application", style: { cursor: 'col-resize', userSelect: 'none', touchAction: 'none' }, onPointerDown: (event) => {
87
90
  event.currentTarget.setPointerCapture(event.pointerId);
88
91
  const value = timeAt(event);
89
92
  moveDrag({ from: value, to: value });
@@ -128,5 +131,5 @@ export function TraceWaterfall({ root, selectedId, matches, onSelect, }) {
128
131
  const { t } = useTraceFormat();
129
132
  const [picked, setPicked] = useState(null);
130
133
  const zoom = picked?.root === root.id ? picked : null;
131
- return (_jsxs(VStack, { gap: 2, children: [_jsxs(HStack, { gap: 2, align: "center", justify: "between", children: [_jsx(Text, { type: "supporting", color: "secondary", children: t('@theorem.panel.trace.timeline.zoom') }), zoom ? (_jsx(Button, { label: t('@theorem.panel.trace.timeline.reset'), variant: "ghost", size: "sm", icon: _jsx(Icon, { icon: IconZoomOut }), onClick: () => setPicked(null) })) : null] }), _jsx(ActivityStrip, { root: root, zoom: zoom, onZoom: setPicked }), _jsx(SpanBars, { root: root, domain: zoom ? [zoom.from, zoom.to] : [0, Math.max(root.durationMs, 1)], selectedId: selectedId, matches: matches, onSelect: onSelect })] }));
134
+ return (_jsxs(VStack, { gap: 2, className: "theorem-arrive", children: [_jsxs(HStack, { gap: 2, align: "center", justify: "between", children: [_jsx(Text, { type: "supporting", color: "secondary", children: t('@theorem.panel.trace.timeline.zoom') }), zoom ? (_jsx(Button, { label: t('@theorem.panel.trace.timeline.reset'), variant: "ghost", size: "sm", icon: _jsx(Icon, { icon: IconZoomOut }), onClick: () => setPicked(null) })) : null] }), _jsx(ActivityStrip, { root: root, zoom: zoom, onZoom: setPicked }), _jsx(SpanBars, { root: root, domain: zoom ? [zoom.from, zoom.to] : [0, Math.max(root.durationMs, 1)], selectedId: selectedId, matches: matches, onSelect: onSelect })] }));
132
135
  }
package/ui/VoiceNote.js CHANGED
@@ -6,10 +6,10 @@ import { IconButton } from '@astryxdesign/core/IconButton';
6
6
  import { VStack } from '@astryxdesign/core/VStack';
7
7
  import { IconX } from '@tabler/icons-react';
8
8
  import { voiceFormatFromMime } from "../client/voice-label.js";
9
- import { voiceNoteName } from "./labels.js";
10
- import { useLabels } from "./labels-provider.js";
11
9
  import { InkWaveform } from "../components/InkWaveform.js";
12
10
  import { useVoicePlayback } from "../components/use-voice-playback.js";
11
+ import { voiceNoteName } from "./labels.js";
12
+ import { useLabels } from "./labels-provider.js";
13
13
  /** Astryx Thumbnail's height, so voice notes sit level with image attachments. */
14
14
  const VOICE_NOTE_HEIGHT = 64;
15
15
  const VOICE_NOTE_WIDTH = 160;
@@ -19,10 +19,10 @@ const VOICE_NOTE_WIDTH = 160;
19
19
  */
20
20
  export function VoiceNote({ src, mimeType = 'audio/webm', label, onRemove }) {
21
21
  const t = useLabels();
22
- const { playing, outputLevel, toggle, audioProps } = useVoicePlayback();
22
+ const { playing, levelsRef, toggle, audioProps } = useVoicePlayback();
23
23
  const name = label ?? voiceNoteName(t, voiceFormatFromMime(mimeType));
24
24
  const remove = t('@theorem.voice_note.remove', { name });
25
25
  return (_jsxs(HStack, { gap: 1, vAlign: "center", children: [_jsx(ClickableCard, { label: t(playing ? '@theorem.voice_note.pause' : '@theorem.voice_note.play', { name }), onClick: () => {
26
26
  void toggle();
27
- }, padding: 0, width: VOICE_NOTE_WIDTH, height: VOICE_NOTE_HEIGHT, children: _jsx(VStack, { width: "100%", height: "100%", paddingInline: 2, paddingBlockStart: 2, style: { color: 'var(--color-icon-primary)' }, "aria-hidden": "true", children: _jsx(InkWaveform, { frozen: !playing, outputLevel: outputLevel, status: playing ? 'speaking' : 'ready', variant: "pill" }) }) }), onRemove ? (_jsx(IconButton, { label: remove, tooltip: remove, variant: "ghost", size: "sm", icon: _jsx(Icon, { icon: IconX }), onClick: onRemove })) : null, _jsx("audio", { ...audioProps, src: src, hidden: true })] }));
27
+ }, padding: 0, width: VOICE_NOTE_WIDTH, height: VOICE_NOTE_HEIGHT, children: _jsx(VStack, { width: "100%", height: "100%", paddingInline: 2, paddingBlockStart: 2, style: { color: 'var(--color-icon-primary)' }, "aria-hidden": "true", children: _jsx(InkWaveform, { frozen: !playing, levelsRef: levelsRef, status: playing ? 'speaking' : 'ready', variant: "pill" }) }) }), onRemove ? (_jsx(IconButton, { label: remove, tooltip: remove, variant: "ghost", size: "sm", icon: _jsx(Icon, { icon: IconX }), onClick: onRemove })) : null, _jsx("audio", { ...audioProps, src: src, hidden: true })] }));
28
28
  }
@@ -0,0 +1,4 @@
1
+ import type { ToolGate } from '@theoremjs/agents/kernel';
2
+ import type { LabelText } from './labels.ts';
3
+ /** "@concierge wants to check the weather": the tool's `labels.request`, else its name in words. */
4
+ export declare function approvalHeading(t: LabelText, gate: ToolGate, toolName: string, agent?: string): string;
@@ -0,0 +1,9 @@
1
+ import { humanize } from "../client/shaped-data.js";
2
+ /** "@concierge wants to check the weather": the tool's `labels.request`, else its name in words. */
3
+ export function approvalHeading(t, gate, toolName, agent) {
4
+ const request = gate.request ??
5
+ t('@theorem.gate.approval.use_tool', { tool: humanize(toolName).toLowerCase() });
6
+ return agent
7
+ ? t('@theorem.gate.approval.title', { agent, request })
8
+ : t('@theorem.gate.approval.title_no_agent', { request });
9
+ }
package/ui/arrive.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ import { type CSSProperties, type ReactNode } from 'react';
2
+ /**
3
+ * Items under this ease in one after another, in tree order. An item that
4
+ * mounts later (a span that just landed, a chart whose module just loaded)
5
+ * eases in on its own. Already-shown items do not replay.
6
+ */
7
+ export declare function Stream({ children }: {
8
+ children: ReactNode;
9
+ }): import("react").JSX.Element;
10
+ /** Class and delay for one item. Nothing outside a {@link Stream}. */
11
+ export declare function useArrive(): {
12
+ className: string;
13
+ style?: CSSProperties;
14
+ } | null;
15
+ /** A block that eases in with its siblings under {@link Stream}. */
16
+ export declare function Arrive({ children }: {
17
+ children: ReactNode;
18
+ }): string | number | bigint | boolean | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | null | undefined;
package/ui/arrive.js ADDED
@@ -0,0 +1,46 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, use, useRef, useState } from 'react';
3
+ /**
4
+ * How long each later item waits. Short enough that a handful still read as
5
+ * one arrival, long enough that the order is visible.
6
+ */
7
+ const STEP_MS = 64;
8
+ /** Past this, the rest start together so a long list is not still waiting. */
9
+ const CAP = 10;
10
+ const ArriveSeq = createContext(null);
11
+ /**
12
+ * Items under this ease in one after another, in tree order. An item that
13
+ * mounts later (a span that just landed, a chart whose module just loaded)
14
+ * eases in on its own. Already-shown items do not replay.
15
+ */
16
+ export function Stream({ children }) {
17
+ const seq = useRef(0);
18
+ // why: Each render starts again. Items remember the place they took, so a
19
+ // re-render does not hand that place to someone else.
20
+ seq.current = 0;
21
+ return _jsx(ArriveSeq, { value: seq, children: children });
22
+ }
23
+ /** Class and delay for one item. Nothing outside a {@link Stream}. */
24
+ export function useArrive() {
25
+ const seq = use(ArriveSeq);
26
+ const slot = useRef(null);
27
+ if (seq && slot.current === null) {
28
+ slot.current = seq.current;
29
+ seq.current += 1;
30
+ }
31
+ const index = seq ? slot.current : null;
32
+ const [delay] = useState(() => (index === null ? 0 : Math.min(index, CAP) * STEP_MS));
33
+ if (index === null)
34
+ return null;
35
+ return {
36
+ className: 'theorem-arrive',
37
+ style: delay > 0 ? { animationDelay: `${String(delay)}ms` } : undefined,
38
+ };
39
+ }
40
+ /** A block that eases in with its siblings under {@link Stream}. */
41
+ export function Arrive({ children }) {
42
+ const arrive = useArrive();
43
+ if (!arrive)
44
+ return children;
45
+ return (_jsx("div", { className: arrive.className, style: arrive.style, children: children }));
46
+ }
@@ -2,10 +2,12 @@
2
2
  * @generated by `astryx theme build` — do not edit manually.
3
3
  * Source: src/ui/theorem-theme.ts
4
4
  * Command: astryx theme build src/ui/theorem-theme.ts --out src/ui/built/theme.css
5
- * CLI: @astryxdesign/cli@0.6.3
6
- * Core: @astryxdesign/core@0.6.3
5
+ * CLI: @astryxdesign/cli@0.7.0
6
+ * Core: @astryxdesign/core@0.7.0
7
7
  */
8
8
 
9
+ @layer reset, astryx-base, astryx-theme;
10
+
9
11
  @layer reset {
10
12
  @scope ([data-astryx-theme="theorem"]) to ([data-astryx-theme]) {
11
13
  :where(h1, h2, h3, h4, h5, h6) {
@@ -77,67 +79,6 @@
77
79
  }
78
80
  }
79
81
 
80
- @layer astryx-base {
81
- :root {
82
- --color-data-categorical-blue: light-dark(#0171E3, #0171E3);
83
- --color-data-categorical-orange: light-dark(#EB6E00, #EB6E00);
84
- --color-data-categorical-purple: light-dark(#6B1EFD, #6B1EFD);
85
- --color-data-categorical-green: light-dark(#0B991F, #0B991F);
86
- --color-data-categorical-pink: light-dark(#F351C0, #F351C0);
87
- --color-data-categorical-cyan: light-dark(#0171A4, #0171A4);
88
- --color-data-categorical-red: light-dark(#F5394F, #F5394F);
89
- --color-data-categorical-teal: light-dark(#08A3A3, #08A3A3);
90
- --color-data-categorical-brown: light-dark(#965E03, #965E03);
91
- --color-data-categorical-indigo: light-dark(#6F8AFF, #6F8AFF);
92
- --color-data-neutral: light-dark(#8494A3, #8C939B);
93
- --color-data-blue-5: light-dark(#02165E, #02165E);
94
- --color-data-blue-4: light-dark(#004CBC, #004CBC);
95
- --color-data-blue-3: light-dark(#2694FE, #2694FE);
96
- --color-data-blue-2: light-dark(#78BEFF, #78BEFF);
97
- --color-data-blue-1: light-dark(#DBECFF, #DBECFF);
98
- --color-data-shamrock-5: light-dark(#0B603D, #0B603D);
99
- --color-data-shamrock-4: light-dark(#138546, #138546);
100
- --color-data-shamrock-3: light-dark(#24BB5E, #24BB5E);
101
- --color-data-shamrock-2: light-dark(#8EF7AA, #8EF7AA);
102
- --color-data-shamrock-1: light-dark(#D6FEE4, #D6FEE4);
103
- --color-data-orange-5: light-dark(#A13F04, #A13F04);
104
- --color-data-orange-4: light-dark(#D66100, #D66100);
105
- --color-data-orange-3: light-dark(#FD9537, #FD9537);
106
- --color-data-orange-2: light-dark(#FDB876, #FDB876);
107
- --color-data-orange-1: light-dark(#FFE6CF, #FFE6CF);
108
- --color-data-pink-5: light-dark(#8E1073, #8E1073);
109
- --color-data-pink-4: light-dark(#D123A1, #D123A1);
110
- --color-data-pink-3: light-dark(#F989D3, #F989D3);
111
- --color-data-pink-2: light-dark(#FEADE3, #FEADE3);
112
- --color-data-pink-1: light-dark(#FCE3F4, #FCE3F4);
113
- --color-data-purple-5: light-dark(#3E0697, #3E0697);
114
- --color-data-purple-4: light-dark(#6B1EFD, #6B1EFD);
115
- --color-data-purple-3: light-dark(#9081FF, #9081FF);
116
- --color-data-purple-2: light-dark(#B3B0FE, #B3B0FE);
117
- --color-data-purple-1: light-dark(#E8E8FB, #E8E8FB);
118
- --color-data-red-5: light-dark(#9D0519, #9D0519);
119
- --color-data-red-4: light-dark(#D31130, #D31130);
120
- --color-data-red-3: light-dark(#FB7D87, #FB7D87);
121
- --color-data-red-2: light-dark(#FFB2B8, #FFB2B8);
122
- --color-data-red-1: light-dark(#FEE4E6, #FEE4E6);
123
- --color-data-teal-5: light-dark(#08767D, #08767D);
124
- --color-data-teal-4: light-dark(#0C9293, #0C9293);
125
- --color-data-teal-3: light-dark(#0DB7AF, #0DB7AF);
126
- --color-data-teal-2: light-dark(#6CE6D8, #6CE6D8);
127
- --color-data-teal-1: light-dark(#D7FCF8, #D7FCF8);
128
- --color-data-yellow-5: light-dark(#8A5001, #8A5001);
129
- --color-data-yellow-4: light-dark(#D69804, #D69804);
130
- --color-data-yellow-3: light-dark(#FBCE03, #FBCE03);
131
- --color-data-yellow-2: light-dark(#FCEC85, #FCEC85);
132
- --color-data-yellow-1: light-dark(#FDF6BA, #FDF6BA);
133
- --color-data-gray-5: light-dark(#25363F, #333338);
134
- --color-data-gray-4: light-dark(#5D6C7B, #666A72);
135
- --color-data-gray-3: light-dark(#AFB9C4, #B2B8BE);
136
- --color-data-gray-2: light-dark(#CCD3DB, #D0D3D6);
137
- --color-data-gray-1: light-dark(#F1F4F7, #F2F4F6);
138
- }
139
- }
140
-
141
82
  @layer astryx-theme {
142
83
  :root { color-scheme: light dark; }
143
84
  html[data-theme="light"] { color-scheme: light; }
@@ -641,6 +582,15 @@
641
582
  --astryx-card-padding: var(--spacing-3);
642
583
  }
643
584
 
585
+ .astryx-card[data-variant="bubble"] {
586
+ background-color: var(--color-neutral);
587
+ border-radius: var(--radius-chat);
588
+ --astryx-card-padding-inline: var(--spacing-4);
589
+ --astryx-card-padding-block-start: var(--spacing-3);
590
+ --astryx-card-padding-block-end: var(--spacing-3);
591
+ --_card-radius: var(--radius-chat);
592
+ }
593
+
644
594
  .astryx-section {
645
595
  --astryx-section-padding: var(--spacing-3);
646
596
  }
@@ -681,11 +631,15 @@
681
631
  align-self: baseline;
682
632
  }
683
633
 
634
+ .astryx-code-block[data-container="card"] {
635
+ border-radius: var(--radius-container);
636
+ }
637
+
684
638
  .astryx-layout-panel:where([role="complementary"]) {
685
639
  transition: width var(--duration-medium) var(--ease-standard);
686
640
  }
687
641
 
688
- .astryx-layout-panel:where([data-resizing] + [role="complementary"]) {
642
+ .astryx-layout-panel:where([data-resizing] + [role="complementary"], [role="complementary"]:has(+ [data-resizing])) {
689
643
  transition: none;
690
644
  }
691
645
 
@@ -742,15 +696,79 @@
742
696
  }
743
697
 
744
698
  @layer astryx-theme {
699
+ @media (width < 1024px) and (pointer: coarse) {
700
+ @scope ([data-astryx-theme="theorem"]) to ([data-astryx-theme]) {
701
+ :scope {
702
+ --font-size-4xs: 0.4375rem;
703
+ --font-size-3xs: 0.5rem;
704
+ --font-size-2xs: 0.625rem;
705
+ --font-size-xs: 0.75rem;
706
+ --font-size-sm: 0.875rem;
707
+ --font-size-base: 1rem;
708
+ --font-size-lg: 1.1875rem;
709
+ --font-size-xl: 1.375rem;
710
+ --font-size-2xl: 1.625rem;
711
+ --font-size-3xl: 1.875rem;
712
+ --font-size-4xl: 2.25rem;
713
+ --font-size-5xl: 2.625rem;
714
+ --text-heading-1-size: var(--font-size-2xl);
715
+ --text-heading-1-weight: var(--font-weight-semibold);
716
+ --text-heading-1-leading: 1.3846;
717
+ --text-heading-2-size: var(--font-size-xl);
718
+ --text-heading-2-weight: var(--font-weight-semibold);
719
+ --text-heading-2-leading: 1.4545;
720
+ --text-heading-3-size: var(--font-size-lg);
721
+ --text-heading-3-weight: var(--font-weight-bold);
722
+ --text-heading-3-leading: 1.4737;
723
+ --text-heading-4-size: var(--font-size-base);
724
+ --text-heading-4-weight: var(--font-weight-bold);
725
+ --text-heading-4-leading: 1.5;
726
+ --text-heading-5-size: var(--font-size-sm);
727
+ --text-heading-5-weight: var(--font-weight-semibold);
728
+ --text-heading-5-leading: 1.4286;
729
+ --text-heading-6-size: var(--font-size-xs);
730
+ --text-heading-6-weight: var(--font-weight-semibold);
731
+ --text-heading-6-leading: 1.6667;
732
+ --text-body-size: var(--font-size-base);
733
+ --text-body-weight: var(--font-weight-normal);
734
+ --text-body-leading: 1.5;
735
+ --text-large-size: var(--font-size-lg);
736
+ --text-large-weight: var(--font-weight-semibold);
737
+ --text-large-leading: 1.4737;
738
+ --text-label-size: var(--font-size-base);
739
+ --text-label-weight: var(--font-weight-medium);
740
+ --text-label-leading: 1.5;
741
+ --text-code-size: var(--font-size-base);
742
+ --text-code-weight: var(--font-weight-normal);
743
+ --text-code-leading: 1.5;
744
+ --text-supporting-size: var(--font-size-sm);
745
+ --text-supporting-weight: var(--font-weight-normal);
746
+ --text-supporting-leading: 1.4286;
747
+ --text-display-1-size: var(--font-size-5xl);
748
+ --text-display-1-weight: var(--font-weight-normal);
749
+ --text-display-1-leading: 1.2381;
750
+ --text-display-2-size: var(--font-size-4xl);
751
+ --text-display-2-weight: var(--font-weight-normal);
752
+ --text-display-2-leading: 1.2222;
753
+ --text-display-3-size: var(--font-size-3xl);
754
+ --text-display-3-weight: var(--font-weight-normal);
755
+ --text-display-3-leading: 1.4667;
756
+ --font-family-body: Figtree, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
757
+ --font-family-heading: Figtree, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
758
+ --font-family-code: ui-monospace, "SF Mono", Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
759
+ }
760
+ }
761
+ }
762
+
745
763
  @media (prefers-reduced-motion: reduce) {
746
764
  @scope ([data-astryx-theme="theorem"]) to ([data-astryx-theme]) {
747
765
  .astryx-collapsible-content {
748
- transition: none;
749
- }
766
+ transition: none;
767
+ }
750
768
 
751
769
  .astryx-layout-panel:where([role="complementary"]) {
752
- transition: none;
753
- }
770
+ transition: none;
771
+ }
754
772
  }
755
773
  }
756
774
  }