@gram-ai/elements 1.27.4 → 1.27.6

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 (278) hide show
  1. package/README.md +72 -60
  2. package/README.typedoc.md +6 -6
  3. package/bin/cli.js +74 -74
  4. package/dist/compat-shims-CO9JXXV4.cjs.map +1 -1
  5. package/dist/{compat-shims-BPJ7Q68c.js → compat-shims-DxtUrORi.js} +4 -2
  6. package/dist/compat-shims-DxtUrORi.js.map +1 -0
  7. package/dist/components/ShareButton/index.d.ts +2 -2
  8. package/dist/components/assistant-ui/message-feedback.d.ts +1 -1
  9. package/dist/components/assistant-ui/tooltip-icon-button.d.ts +2 -2
  10. package/dist/components/ui/avatar.d.ts +2 -2
  11. package/dist/components/ui/button.d.ts +1 -1
  12. package/dist/components/ui/calendar.d.ts +1 -1
  13. package/dist/components/ui/collapsible.d.ts +1 -1
  14. package/dist/components/ui/dialog.d.ts +4 -4
  15. package/dist/components/ui/popover.d.ts +2 -2
  16. package/dist/components/ui/skeleton.d.ts +1 -1
  17. package/dist/components/ui/time-range-picker.d.ts +1 -1
  18. package/dist/components/ui/tool-ui.d.ts +7 -7
  19. package/dist/components/ui/tooltip.d.ts +2 -2
  20. package/dist/contexts/ConnectionStatusContext.d.ts +1 -1
  21. package/dist/elements.cjs +1 -1
  22. package/dist/elements.css +1 -1
  23. package/dist/elements.js +2 -2
  24. package/dist/hooks/useDensity.d.ts +73 -73
  25. package/dist/hooks/useMCPTools.d.ts +1 -1
  26. package/dist/hooks/useRadius.d.ts +1 -1
  27. package/dist/{index-KSX4Qjip.cjs → index-A17b62wR.cjs} +10 -10
  28. package/dist/index-A17b62wR.cjs.map +1 -0
  29. package/dist/{index-BpJstUh1.cjs → index-C4bFBGfl.cjs} +4 -4
  30. package/dist/{index-BpJstUh1.cjs.map → index-C4bFBGfl.cjs.map} +1 -1
  31. package/dist/{index-CUitXazZ.js → index-D93pV0_o.js} +55 -55
  32. package/dist/{index-CUitXazZ.js.map → index-D93pV0_o.js.map} +1 -1
  33. package/dist/{index-D0bAYNQy.js → index-Dm2wLFTN.js} +304 -282
  34. package/dist/index-Dm2wLFTN.js.map +1 -0
  35. package/dist/lib/cassette.d.ts +4 -4
  36. package/dist/lib/errorTracking.d.ts +1 -1
  37. package/dist/lib/messageConverter.d.ts +1 -1
  38. package/dist/lib/models.d.ts +1 -1
  39. package/dist/plugins/chart/ui/bar-chart.d.ts +1 -1
  40. package/dist/plugins/generative-ui/ui/accordion-wrapper.d.ts +2 -2
  41. package/dist/plugins/generative-ui/ui/accordion.d.ts +1 -1
  42. package/dist/plugins/generative-ui/ui/action-button.d.ts +2 -2
  43. package/dist/plugins/generative-ui/ui/alert-wrapper.d.ts +1 -1
  44. package/dist/plugins/generative-ui/ui/alert.d.ts +4 -4
  45. package/dist/plugins/generative-ui/ui/avatar.d.ts +5 -5
  46. package/dist/plugins/generative-ui/ui/badge.d.ts +2 -2
  47. package/dist/plugins/generative-ui/ui/button-wrapper.d.ts +2 -2
  48. package/dist/plugins/generative-ui/ui/button.d.ts +2 -2
  49. package/dist/plugins/generative-ui/ui/card-wrapper.d.ts +2 -2
  50. package/dist/plugins/generative-ui/ui/card.d.ts +8 -8
  51. package/dist/plugins/generative-ui/ui/checkbox.d.ts +1 -1
  52. package/dist/plugins/generative-ui/ui/data-table.d.ts +2 -2
  53. package/dist/plugins/generative-ui/ui/dialog.d.ts +3 -3
  54. package/dist/plugins/generative-ui/ui/dropdown-menu.d.ts +3 -3
  55. package/dist/plugins/generative-ui/ui/grid.d.ts +3 -3
  56. package/dist/plugins/generative-ui/ui/input-wrapper.d.ts +1 -1
  57. package/dist/plugins/generative-ui/ui/input.d.ts +2 -2
  58. package/dist/plugins/generative-ui/ui/label.d.ts +1 -1
  59. package/dist/plugins/generative-ui/ui/metric.d.ts +3 -3
  60. package/dist/plugins/generative-ui/ui/pagination.d.ts +6 -6
  61. package/dist/plugins/generative-ui/ui/popover.d.ts +4 -4
  62. package/dist/plugins/generative-ui/ui/progress.d.ts +2 -2
  63. package/dist/plugins/generative-ui/ui/radio-group.d.ts +1 -1
  64. package/dist/plugins/generative-ui/ui/select.d.ts +2 -2
  65. package/dist/plugins/generative-ui/ui/separator.d.ts +1 -1
  66. package/dist/plugins/generative-ui/ui/skeleton.d.ts +1 -1
  67. package/dist/plugins/generative-ui/ui/stack.d.ts +6 -6
  68. package/dist/plugins/generative-ui/ui/switch.d.ts +2 -2
  69. package/dist/plugins/generative-ui/ui/table.d.ts +9 -9
  70. package/dist/plugins/generative-ui/ui/tabs-wrapper.d.ts +1 -1
  71. package/dist/plugins/generative-ui/ui/tabs.d.ts +1 -1
  72. package/dist/plugins/generative-ui/ui/text.d.ts +3 -3
  73. package/dist/plugins/generative-ui/ui/textarea.d.ts +2 -2
  74. package/dist/plugins/generative-ui/ui/tooltip.d.ts +1 -1
  75. package/dist/plugins.cjs +1 -1
  76. package/dist/plugins.js +1 -1
  77. package/dist/{profiler-CyzxBxVz.cjs → profiler-Cbbf4eEX.cjs} +2 -2
  78. package/dist/{profiler-CyzxBxVz.cjs.map → profiler-Cbbf4eEX.cjs.map} +1 -1
  79. package/dist/{profiler-BFkhZRxj.js → profiler-mca4IXaY.js} +2 -2
  80. package/dist/{profiler-BFkhZRxj.js.map → profiler-mca4IXaY.js.map} +1 -1
  81. package/dist/react-shim.js +1 -1
  82. package/dist/server/express.cjs.map +1 -1
  83. package/dist/server/express.js.map +1 -1
  84. package/dist/{startRecording-C-PPAs_Z.js → startRecording-BCafdS7B.js} +2 -2
  85. package/dist/{startRecording-C-PPAs_Z.js.map → startRecording-BCafdS7B.js.map} +1 -1
  86. package/dist/{startRecording-Dq92sEHf.cjs → startRecording-Eb5f7wqP.cjs} +2 -2
  87. package/dist/{startRecording-Dq92sEHf.cjs.map → startRecording-Eb5f7wqP.cjs.map} +1 -1
  88. package/dist/types/index.d.ts +4 -4
  89. package/package.json +1 -5
  90. package/src/compat-plugin.ts +14 -14
  91. package/src/compat-shims.ts +33 -31
  92. package/src/compat.test.ts +48 -48
  93. package/src/compat.ts +6 -6
  94. package/src/components/Chat/index.tsx +17 -17
  95. package/src/components/Chat/stories/Charts.stories.tsx +98 -98
  96. package/src/components/Chat/stories/Composer.stories.tsx +15 -15
  97. package/src/components/Chat/stories/ConnectionConfiguration.stories.tsx +44 -44
  98. package/src/components/Chat/stories/CustomComponents.stories.tsx +17 -17
  99. package/src/components/Chat/stories/Density.stories.tsx +20 -20
  100. package/src/components/Chat/stories/ErrorBoundary.stories.tsx +47 -47
  101. package/src/components/Chat/stories/FrontendTools.stories.tsx +39 -39
  102. package/src/components/Chat/stories/GenerativeUI.stories.tsx +48 -48
  103. package/src/components/Chat/stories/MessageFeedback.stories.tsx +52 -52
  104. package/src/components/Chat/stories/Modal.stories.tsx +28 -28
  105. package/src/components/Chat/stories/Model.stories.tsx +11 -11
  106. package/src/components/Chat/stories/Radius.stories.tsx +20 -20
  107. package/src/components/Chat/stories/Sidecar.stories.tsx +13 -13
  108. package/src/components/Chat/stories/StyleIsolation.stories.tsx +11 -11
  109. package/src/components/Chat/stories/Theme.stories.tsx +25 -25
  110. package/src/components/Chat/stories/Thread.stories.tsx +25 -25
  111. package/src/components/Chat/stories/ToolApproval.stories.tsx +55 -55
  112. package/src/components/Chat/stories/ToolMentions.stories.tsx +17 -17
  113. package/src/components/Chat/stories/Tools.stories.tsx +88 -88
  114. package/src/components/Chat/stories/Variants.stories.tsx +32 -32
  115. package/src/components/Chat/stories/Welcome.stories.tsx +14 -14
  116. package/src/components/ChatHistory.tsx +7 -7
  117. package/src/components/FrontendTools/index.tsx +5 -5
  118. package/src/components/Replay.stories.tsx +157 -157
  119. package/src/components/Replay.tsx +76 -73
  120. package/src/components/ShadowRoot.tsx +40 -40
  121. package/src/components/ShareButton/index.tsx +32 -32
  122. package/src/components/assistant-ui/assistant-modal.tsx +92 -87
  123. package/src/components/assistant-ui/assistant-sidecar.tsx +35 -35
  124. package/src/components/assistant-ui/attachment.tsx +80 -80
  125. package/src/components/assistant-ui/connection-status-indicator.tsx +33 -33
  126. package/src/components/assistant-ui/error-boundary.tsx +34 -34
  127. package/src/components/assistant-ui/follow-on-suggestions.tsx +26 -26
  128. package/src/components/assistant-ui/markdown-text.tsx +69 -69
  129. package/src/components/assistant-ui/mentioned-tools-badges.tsx +38 -38
  130. package/src/components/assistant-ui/message-feedback.tsx +57 -50
  131. package/src/components/assistant-ui/reasoning.tsx +83 -83
  132. package/src/components/assistant-ui/thread-list.tsx +45 -45
  133. package/src/components/assistant-ui/thread.tsx +278 -278
  134. package/src/components/assistant-ui/tool-fallback.tsx +37 -37
  135. package/src/components/assistant-ui/tool-group.tsx +26 -26
  136. package/src/components/assistant-ui/tool-mention-autocomplete.tsx +122 -122
  137. package/src/components/assistant-ui/tooltip-icon-button.tsx +18 -18
  138. package/src/components/ui/avatar.tsx +12 -12
  139. package/src/components/ui/button.tsx +12 -12
  140. package/src/components/ui/buttonVariants.ts +17 -17
  141. package/src/components/ui/calendar.tsx +106 -106
  142. package/src/components/ui/charts.stories.tsx +56 -56
  143. package/src/components/ui/collapsible.tsx +5 -5
  144. package/src/components/ui/dialog.tsx +30 -30
  145. package/src/components/ui/generative-ui.stories.tsx +200 -200
  146. package/src/components/ui/generative-ui.tsx +26 -26
  147. package/src/components/ui/popover.tsx +14 -14
  148. package/src/components/ui/skeleton.tsx +5 -5
  149. package/src/components/ui/time-range-picker.stories.tsx +80 -80
  150. package/src/components/ui/time-range-picker.tsx +248 -246
  151. package/src/components/ui/tool-ui.stories.tsx +37 -37
  152. package/src/components/ui/tool-ui.tsx +221 -215
  153. package/src/components/ui/tooltip.tsx +15 -15
  154. package/src/constants/tailwind.ts +1 -1
  155. package/src/contexts/ChatIdContext.tsx +7 -7
  156. package/src/contexts/ConnectionStatusContext.tsx +64 -64
  157. package/src/contexts/ElementsProvider.tsx +214 -213
  158. package/src/contexts/ReplayContext.ts +3 -3
  159. package/src/contexts/ToolApprovalContext.tsx +54 -54
  160. package/src/contexts/ToolExecutionContext.tsx +34 -34
  161. package/src/contexts/contexts.ts +7 -7
  162. package/src/contexts/portal-container-context.ts +2 -2
  163. package/src/contexts/portal-container.tsx +7 -7
  164. package/src/embedded.ts +1 -1
  165. package/src/global.css +25 -25
  166. package/src/hooks/useAuth.ts +72 -72
  167. package/src/hooks/useDensity.ts +79 -79
  168. package/src/hooks/useElements.ts +6 -6
  169. package/src/hooks/useExpanded.ts +12 -12
  170. package/src/hooks/useFollowOnSuggestions.ts +83 -83
  171. package/src/hooks/useGramThreadListAdapter.tsx +99 -99
  172. package/src/hooks/useMCPTools.ts +47 -47
  173. package/src/hooks/useModel.ts +14 -14
  174. package/src/hooks/usePluginComponents.ts +11 -11
  175. package/src/hooks/usePortalContainer.ts +5 -5
  176. package/src/hooks/useRadius.ts +23 -23
  177. package/src/hooks/useRecordCassette.ts +34 -34
  178. package/src/hooks/useSession.ts +11 -11
  179. package/src/hooks/useThemeProps.ts +13 -13
  180. package/src/hooks/useThreadId.ts +4 -4
  181. package/src/hooks/useToolApproval.ts +7 -7
  182. package/src/hooks/useToolMentions.ts +40 -40
  183. package/src/index.ts +26 -26
  184. package/src/lib/api.test.ts +61 -61
  185. package/src/lib/api.ts +4 -3
  186. package/src/lib/auth.ts +13 -13
  187. package/src/lib/cassette.ts +84 -84
  188. package/src/lib/easing.ts +1 -1
  189. package/src/lib/errorTracking.config.ts +5 -5
  190. package/src/lib/errorTracking.ts +29 -29
  191. package/src/lib/generative-ui.ts +7 -7
  192. package/src/lib/humanize.ts +3 -3
  193. package/src/lib/messageConverter.test.ts +130 -127
  194. package/src/lib/messageConverter.ts +196 -196
  195. package/src/lib/models.ts +28 -20
  196. package/src/lib/token.test.ts +56 -56
  197. package/src/lib/token.ts +14 -14
  198. package/src/lib/tool-mentions.ts +45 -45
  199. package/src/lib/tools.ts +66 -62
  200. package/src/lib/utils.ts +5 -5
  201. package/src/lib.d.ts +1 -1
  202. package/src/plugins/README.md +5 -5
  203. package/src/plugins/chart/catalog.ts +18 -18
  204. package/src/plugins/chart/chart.test.ts +31 -31
  205. package/src/plugins/chart/component.tsx +34 -34
  206. package/src/plugins/chart/index.ts +4 -4
  207. package/src/plugins/chart/ui/area-chart.tsx +42 -42
  208. package/src/plugins/chart/ui/bar-chart.tsx +46 -46
  209. package/src/plugins/chart/ui/donut-chart.tsx +48 -48
  210. package/src/plugins/chart/ui/index.ts +7 -7
  211. package/src/plugins/chart/ui/line-chart.tsx +43 -43
  212. package/src/plugins/chart/ui/pie-chart.tsx +44 -44
  213. package/src/plugins/chart/ui/radar-chart.tsx +33 -33
  214. package/src/plugins/chart/ui/scatter-chart.tsx +43 -43
  215. package/src/plugins/components/MacOSWindowFrame.tsx +15 -15
  216. package/src/plugins/components/PluginLoadingState.tsx +10 -10
  217. package/src/plugins/components/index.ts +1 -1
  218. package/src/plugins/generative-ui/catalog.ts +54 -54
  219. package/src/plugins/generative-ui/component.tsx +85 -85
  220. package/src/plugins/generative-ui/index.ts +4 -4
  221. package/src/plugins/generative-ui/ui/accordion-wrapper.tsx +16 -16
  222. package/src/plugins/generative-ui/ui/accordion.tsx +16 -16
  223. package/src/plugins/generative-ui/ui/action-button.tsx +28 -28
  224. package/src/plugins/generative-ui/ui/alert-wrapper.tsx +8 -8
  225. package/src/plugins/generative-ui/ui/alert.tsx +20 -20
  226. package/src/plugins/generative-ui/ui/avatar-wrapper.tsx +7 -7
  227. package/src/plugins/generative-ui/ui/avatar.tsx +30 -30
  228. package/src/plugins/generative-ui/ui/badge.tsx +22 -22
  229. package/src/plugins/generative-ui/ui/button-wrapper.tsx +12 -12
  230. package/src/plugins/generative-ui/ui/button.tsx +28 -28
  231. package/src/plugins/generative-ui/ui/card-wrapper.tsx +8 -8
  232. package/src/plugins/generative-ui/ui/card.tsx +27 -27
  233. package/src/plugins/generative-ui/ui/checkbox-wrapper.tsx +9 -9
  234. package/src/plugins/generative-ui/ui/checkbox.tsx +9 -9
  235. package/src/plugins/generative-ui/ui/data-table.tsx +8 -8
  236. package/src/plugins/generative-ui/ui/dialog.tsx +31 -31
  237. package/src/plugins/generative-ui/ui/dropdown-menu.tsx +44 -44
  238. package/src/plugins/generative-ui/ui/grid.tsx +12 -12
  239. package/src/plugins/generative-ui/ui/index.ts +40 -40
  240. package/src/plugins/generative-ui/ui/input-wrapper.tsx +11 -11
  241. package/src/plugins/generative-ui/ui/input.tsx +9 -9
  242. package/src/plugins/generative-ui/ui/label.tsx +8 -8
  243. package/src/plugins/generative-ui/ui/list.tsx +11 -11
  244. package/src/plugins/generative-ui/ui/metric.tsx +23 -23
  245. package/src/plugins/generative-ui/ui/pagination.tsx +28 -28
  246. package/src/plugins/generative-ui/ui/popover.tsx +21 -21
  247. package/src/plugins/generative-ui/ui/progress.tsx +13 -13
  248. package/src/plugins/generative-ui/ui/radio-group.tsx +12 -12
  249. package/src/plugins/generative-ui/ui/select-wrapper.tsx +7 -7
  250. package/src/plugins/generative-ui/ui/select.tsx +37 -37
  251. package/src/plugins/generative-ui/ui/separator.tsx +9 -9
  252. package/src/plugins/generative-ui/ui/skeleton-wrapper.tsx +10 -10
  253. package/src/plugins/generative-ui/ui/skeleton.tsx +5 -5
  254. package/src/plugins/generative-ui/ui/stack.tsx +28 -28
  255. package/src/plugins/generative-ui/ui/switch.tsx +11 -11
  256. package/src/plugins/generative-ui/ui/table.tsx +32 -32
  257. package/src/plugins/generative-ui/ui/tabs-wrapper.tsx +11 -11
  258. package/src/plugins/generative-ui/ui/tabs.tsx +26 -26
  259. package/src/plugins/generative-ui/ui/text.tsx +12 -12
  260. package/src/plugins/generative-ui/ui/textarea.tsx +7 -7
  261. package/src/plugins/generative-ui/ui/tooltip.tsx +12 -12
  262. package/src/plugins/index.ts +7 -7
  263. package/src/react-shim.ts +6 -6
  264. package/src/server/bun.ts +12 -12
  265. package/src/server/core.ts +25 -25
  266. package/src/server/express.ts +17 -15
  267. package/src/server/fastify.ts +14 -14
  268. package/src/server/hono.ts +9 -9
  269. package/src/server/nextjs.ts +12 -12
  270. package/src/server/tanstack-start.ts +12 -12
  271. package/src/server.ts +27 -27
  272. package/src/storybook.d.ts +4 -4
  273. package/src/types/index.ts +124 -124
  274. package/src/types/plugins.ts +7 -7
  275. package/src/vite-env.d.ts +12 -12
  276. package/dist/compat-shims-BPJ7Q68c.js.map +0 -1
  277. package/dist/index-D0bAYNQy.js.map +0 -1
  278. package/dist/index-KSX4Qjip.cjs.map +0 -1
@@ -1,22 +1,22 @@
1
- import type { StoryFn } from '@storybook/react-vite'
2
- import { Chat } from '@/components/Chat'
3
- import { Replay } from '@/components/Replay'
4
- import type { Cassette } from '@/lib/cassette'
1
+ import type { StoryFn } from "@storybook/react-vite";
2
+ import { Chat } from "@/components/Chat";
3
+ import { Replay } from "@/components/Replay";
4
+ import type { Cassette } from "@/lib/cassette";
5
5
 
6
6
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
7
  const meta: any = {
8
- title: 'Misc/Replay',
8
+ title: "Misc/Replay",
9
9
  component: Replay,
10
10
  parameters: {
11
- layout: 'fullscreen',
11
+ layout: "fullscreen",
12
12
  // Skip the global ElementsProvider — Replay is its own provider
13
13
  elements: { skipProvider: true },
14
14
  },
15
- }
15
+ };
16
16
 
17
- export default meta
17
+ export default meta;
18
18
 
19
- type Story = StoryFn<typeof Replay>
19
+ type Story = StoryFn<typeof Replay>;
20
20
 
21
21
  // ---------------------------------------------------------------------------
22
22
  // Sample cassettes
@@ -25,121 +25,121 @@ type Story = StoryFn<typeof Replay>
25
25
  const textOnlyCassette: Cassette = {
26
26
  messages: [
27
27
  {
28
- role: 'user',
29
- content: [{ type: 'text', text: 'What can you help me with?' }],
28
+ role: "user",
29
+ content: [{ type: "text", text: "What can you help me with?" }],
30
30
  },
31
31
  {
32
- role: 'assistant',
32
+ role: "assistant",
33
33
  content: [
34
34
  {
35
- type: 'text',
35
+ type: "text",
36
36
  text: "I can help you with a wide range of tasks! Here are a few things I'm great at:\n\n- **Answering questions** about virtually any topic\n- **Writing and editing** emails, documents, and code\n- **Brainstorming ideas** for projects, names, or strategies\n- **Explaining concepts** in simple terms\n- **Analyzing data** and summarizing information\n\nWhat would you like to explore?",
37
37
  },
38
38
  ],
39
39
  },
40
40
  {
41
- role: 'user',
42
- content: [{ type: 'text', text: 'Tell me about the Speakeasy SDK.' }],
41
+ role: "user",
42
+ content: [{ type: "text", text: "Tell me about the Speakeasy SDK." }],
43
43
  },
44
44
  {
45
- role: 'assistant',
45
+ role: "assistant",
46
46
  content: [
47
47
  {
48
- type: 'text',
49
- text: 'Speakeasy generates **type-safe, idiomatic SDKs** from your OpenAPI spec. You get production-ready client libraries in TypeScript, Python, Go, and more — complete with authentication, pagination, and retries built in.\n\nThe generated SDKs stay in sync with your API automatically through CI/CD integration, so your users always have an up-to-date client library. No more hand-writing API wrappers!',
48
+ type: "text",
49
+ text: "Speakeasy generates **type-safe, idiomatic SDKs** from your OpenAPI spec. You get production-ready client libraries in TypeScript, Python, Go, and more — complete with authentication, pagination, and retries built in.\n\nThe generated SDKs stay in sync with your API automatically through CI/CD integration, so your users always have an up-to-date client library. No more hand-writing API wrappers!",
50
50
  },
51
51
  ],
52
52
  },
53
53
  ],
54
- }
54
+ };
55
55
 
56
56
  const toolCallCassette: Cassette = {
57
57
  messages: [
58
58
  {
59
- role: 'user',
59
+ role: "user",
60
60
  content: [
61
- { type: 'text', text: "What's the weather like in San Francisco?" },
61
+ { type: "text", text: "What's the weather like in San Francisco?" },
62
62
  ],
63
63
  },
64
64
  {
65
- role: 'assistant',
65
+ role: "assistant",
66
66
  content: [
67
67
  {
68
- type: 'text',
69
- text: 'Let me check the current weather in San Francisco for you.',
68
+ type: "text",
69
+ text: "Let me check the current weather in San Francisco for you.",
70
70
  },
71
71
  {
72
- type: 'tool-call',
73
- toolCallId: 'tc_weather_1',
74
- toolName: 'getWeather',
75
- args: { city: 'San Francisco', units: 'fahrenheit' },
72
+ type: "tool-call",
73
+ toolCallId: "tc_weather_1",
74
+ toolName: "getWeather",
75
+ args: { city: "San Francisco", units: "fahrenheit" },
76
76
  result: {
77
77
  temperature: 68,
78
- conditions: 'Partly cloudy',
78
+ conditions: "Partly cloudy",
79
79
  humidity: 72,
80
- wind: '12 mph NW',
80
+ wind: "12 mph NW",
81
81
  },
82
82
  },
83
83
  {
84
- type: 'text',
84
+ type: "text",
85
85
  text: "It's currently **68°F** in San Francisco with partly cloudy skies. The humidity is at 72% with northwest winds at 12 mph. A beautiful day to be outside!",
86
86
  },
87
87
  ],
88
88
  },
89
89
  {
90
- role: 'user',
91
- content: [{ type: 'text', text: 'How about New York?' }],
90
+ role: "user",
91
+ content: [{ type: "text", text: "How about New York?" }],
92
92
  },
93
93
  {
94
- role: 'assistant',
94
+ role: "assistant",
95
95
  content: [
96
96
  {
97
- type: 'tool-call',
98
- toolCallId: 'tc_weather_2',
99
- toolName: 'getWeather',
100
- args: { city: 'New York', units: 'fahrenheit' },
97
+ type: "tool-call",
98
+ toolCallId: "tc_weather_2",
99
+ toolName: "getWeather",
100
+ args: { city: "New York", units: "fahrenheit" },
101
101
  result: {
102
102
  temperature: 45,
103
- conditions: 'Rainy',
103
+ conditions: "Rainy",
104
104
  humidity: 89,
105
- wind: '8 mph E',
105
+ wind: "8 mph E",
106
106
  },
107
107
  },
108
108
  {
109
- type: 'text',
109
+ type: "text",
110
110
  text: "New York is quite different — it's **45°F** and rainy with high humidity at 89%. You'd want an umbrella and a warm coat today!",
111
111
  },
112
112
  ],
113
113
  },
114
114
  ],
115
- }
115
+ };
116
116
 
117
117
  const reasoningCassette: Cassette = {
118
118
  messages: [
119
119
  {
120
- role: 'user',
120
+ role: "user",
121
121
  content: [
122
122
  {
123
- type: 'text',
124
- text: 'If I have 3 boxes, each containing 2 red balls and 1 blue ball, what is the probability of drawing a red ball from each box?',
123
+ type: "text",
124
+ text: "If I have 3 boxes, each containing 2 red balls and 1 blue ball, what is the probability of drawing a red ball from each box?",
125
125
  },
126
126
  ],
127
127
  },
128
128
  {
129
- role: 'assistant',
129
+ role: "assistant",
130
130
  content: [
131
131
  {
132
- type: 'reasoning',
133
- text: 'The user wants to find the probability of drawing a red ball from each of the 3 boxes.\n\nEach box has 3 balls total: 2 red and 1 blue.\nProbability of red from one box = 2/3.\nSince the draws are independent, I multiply the probabilities:\nP(all red) = (2/3) × (2/3) × (2/3) = 8/27 ≈ 0.296',
132
+ type: "reasoning",
133
+ text: "The user wants to find the probability of drawing a red ball from each of the 3 boxes.\n\nEach box has 3 balls total: 2 red and 1 blue.\nProbability of red from one box = 2/3.\nSince the draws are independent, I multiply the probabilities:\nP(all red) = (2/3) × (2/3) × (2/3) = 8/27 ≈ 0.296",
134
134
  },
135
135
  {
136
- type: 'text',
136
+ type: "text",
137
137
  text: "Each box contains 3 balls (2 red, 1 blue), so the probability of drawing red from a single box is **2/3**.\n\nSince you're drawing independently from each box, you multiply the probabilities:\n\n$$P(\\text{all red}) = \\frac{2}{3} \\times \\frac{2}{3} \\times \\frac{2}{3} = \\frac{8}{27} \\approx 29.6\\%$$\n\nSo there's roughly a **29.6% chance** of drawing a red ball from every box.",
138
138
  },
139
139
  ],
140
140
  },
141
141
  ],
142
- }
142
+ };
143
143
 
144
144
  /**
145
145
  * Simulates what the converter produced BEFORE the dedup fix (AGE-1295).
@@ -156,210 +156,210 @@ const reasoningCassette: Cassette = {
156
156
  const beforeFixCassette: Cassette = {
157
157
  messages: [
158
158
  {
159
- role: 'user',
159
+ role: "user",
160
160
  content: [
161
- { type: 'text', text: 'Search for 3 deals in HubSpot for me.' },
161
+ { type: "text", text: "Search for 3 deals in HubSpot for me." },
162
162
  ],
163
163
  },
164
164
  {
165
- role: 'assistant',
165
+ role: "assistant",
166
166
  content: [
167
167
  // --- chunk 1: first attempt ---
168
168
  {
169
- type: 'text',
169
+ type: "text",
170
170
  text: "I'll search for 3 deals in HubSpot for you.",
171
171
  },
172
172
  {
173
- type: 'tool-call',
174
- toolCallId: 'tc_deals_1',
175
- toolName: 'hubspot_search_deals',
176
- args: { query: 'deals', limit: 3 },
177
- result: { error: 'Invalid filter groups structure' },
173
+ type: "tool-call",
174
+ toolCallId: "tc_deals_1",
175
+ toolName: "hubspot_search_deals",
176
+ args: { query: "deals", limit: 3 },
177
+ result: { error: "Invalid filter groups structure" },
178
178
  },
179
179
  // --- chunk 2: second attempt (accumulates tc_1 + tc_2) ---
180
180
  {
181
- type: 'text',
182
- text: 'Let me try a different approach to retrieve deals:',
181
+ type: "text",
182
+ text: "Let me try a different approach to retrieve deals:",
183
183
  },
184
184
  {
185
- type: 'tool-call',
186
- toolCallId: 'tc_deals_1_dup',
187
- toolName: 'hubspot_search_deals',
188
- args: { query: 'deals', limit: 3 },
189
- result: { error: 'Invalid filter groups structure' },
185
+ type: "tool-call",
186
+ toolCallId: "tc_deals_1_dup",
187
+ toolName: "hubspot_search_deals",
188
+ args: { query: "deals", limit: 3 },
189
+ result: { error: "Invalid filter groups structure" },
190
190
  },
191
191
  {
192
- type: 'tool-call',
193
- toolCallId: 'tc_deals_2',
194
- toolName: 'hubspot_search_deals',
195
- args: { query: 'deals', limit: 3, filterGroups: [] },
196
- result: { error: 'Filter groups must not be empty' },
192
+ type: "tool-call",
193
+ toolCallId: "tc_deals_2",
194
+ toolName: "hubspot_search_deals",
195
+ args: { query: "deals", limit: 3, filterGroups: [] },
196
+ result: { error: "Filter groups must not be empty" },
197
197
  },
198
198
  // --- chunk 3: third attempt (accumulates tc_1 + tc_2 + tc_3) ---
199
199
  {
200
- type: 'text',
201
- text: 'Let me try with proper filter groups structure:',
200
+ type: "text",
201
+ text: "Let me try with proper filter groups structure:",
202
202
  },
203
203
  {
204
- type: 'tool-call',
205
- toolCallId: 'tc_deals_1_dup2',
206
- toolName: 'hubspot_search_deals',
207
- args: { query: 'deals', limit: 3 },
208
- result: { error: 'Invalid filter groups structure' },
204
+ type: "tool-call",
205
+ toolCallId: "tc_deals_1_dup2",
206
+ toolName: "hubspot_search_deals",
207
+ args: { query: "deals", limit: 3 },
208
+ result: { error: "Invalid filter groups structure" },
209
209
  },
210
210
  {
211
- type: 'tool-call',
212
- toolCallId: 'tc_deals_2_dup',
213
- toolName: 'hubspot_search_deals',
214
- args: { query: 'deals', limit: 3, filterGroups: [] },
215
- result: { error: 'Filter groups must not be empty' },
211
+ type: "tool-call",
212
+ toolCallId: "tc_deals_2_dup",
213
+ toolName: "hubspot_search_deals",
214
+ args: { query: "deals", limit: 3, filterGroups: [] },
215
+ result: { error: "Filter groups must not be empty" },
216
216
  },
217
217
  {
218
- type: 'tool-call',
219
- toolCallId: 'tc_deals_3',
220
- toolName: 'hubspot_search_deals',
218
+ type: "tool-call",
219
+ toolCallId: "tc_deals_3",
220
+ toolName: "hubspot_search_deals",
221
221
  args: {
222
222
  limit: 3,
223
223
  filterGroups: [
224
224
  {
225
225
  filters: [
226
- { propertyName: 'dealname', operator: 'HAS_PROPERTY' },
226
+ { propertyName: "dealname", operator: "HAS_PROPERTY" },
227
227
  ],
228
228
  },
229
229
  ],
230
230
  },
231
231
  result: {
232
232
  deals: [
233
- { id: '1', name: 'Acme Corp', amount: 50000 },
234
- { id: '2', name: 'Globex Inc', amount: 75000 },
235
- { id: '3', name: 'Initech LLC', amount: 30000 },
233
+ { id: "1", name: "Acme Corp", amount: 50000 },
234
+ { id: "2", name: "Globex Inc", amount: 75000 },
235
+ { id: "3", name: "Initech LLC", amount: 30000 },
236
236
  ],
237
237
  },
238
238
  },
239
239
  {
240
- type: 'text',
241
- text: 'Here are the 3 deals I found:\n\n1. **Acme Corp** — $50,000\n2. **Globex Inc** — $75,000\n3. **Initech LLC** — $30,000',
240
+ type: "text",
241
+ text: "Here are the 3 deals I found:\n\n1. **Acme Corp** — $50,000\n2. **Globex Inc** — $75,000\n3. **Initech LLC** — $30,000",
242
242
  },
243
243
  ],
244
244
  },
245
245
  ],
246
- }
246
+ };
247
247
 
248
248
  const interleavedToolCallsCassette: Cassette = {
249
249
  messages: [
250
250
  {
251
- role: 'user',
251
+ role: "user",
252
252
  content: [
253
- { type: 'text', text: 'Search for 3 deals in HubSpot for me.' },
253
+ { type: "text", text: "Search for 3 deals in HubSpot for me." },
254
254
  ],
255
255
  },
256
256
  {
257
- role: 'assistant',
257
+ role: "assistant",
258
258
  content: [
259
259
  {
260
- type: 'text',
260
+ type: "text",
261
261
  text: "I'll search for 3 deals in HubSpot for you.",
262
262
  },
263
263
  {
264
- type: 'tool-call',
265
- toolCallId: 'tc_deals_1',
266
- toolName: 'hubspot_search_deals',
267
- args: { query: 'deals', limit: 3 },
268
- result: { error: 'Invalid filter groups structure' },
264
+ type: "tool-call",
265
+ toolCallId: "tc_deals_1",
266
+ toolName: "hubspot_search_deals",
267
+ args: { query: "deals", limit: 3 },
268
+ result: { error: "Invalid filter groups structure" },
269
269
  },
270
270
  {
271
- type: 'text',
272
- text: 'Let me try a different approach to retrieve deals:',
271
+ type: "text",
272
+ text: "Let me try a different approach to retrieve deals:",
273
273
  },
274
274
  {
275
- type: 'tool-call',
276
- toolCallId: 'tc_deals_2',
277
- toolName: 'hubspot_search_deals',
278
- args: { query: 'deals', limit: 3, filterGroups: [] },
279
- result: { error: 'Filter groups must not be empty' },
275
+ type: "tool-call",
276
+ toolCallId: "tc_deals_2",
277
+ toolName: "hubspot_search_deals",
278
+ args: { query: "deals", limit: 3, filterGroups: [] },
279
+ result: { error: "Filter groups must not be empty" },
280
280
  },
281
281
  {
282
- type: 'text',
283
- text: 'Let me try with proper filter groups structure:',
282
+ type: "text",
283
+ text: "Let me try with proper filter groups structure:",
284
284
  },
285
285
  {
286
- type: 'tool-call',
287
- toolCallId: 'tc_deals_3',
288
- toolName: 'hubspot_search_deals',
286
+ type: "tool-call",
287
+ toolCallId: "tc_deals_3",
288
+ toolName: "hubspot_search_deals",
289
289
  args: {
290
290
  limit: 3,
291
291
  filterGroups: [
292
292
  {
293
293
  filters: [
294
- { propertyName: 'dealname', operator: 'HAS_PROPERTY' },
294
+ { propertyName: "dealname", operator: "HAS_PROPERTY" },
295
295
  ],
296
296
  },
297
297
  ],
298
298
  },
299
299
  result: {
300
300
  deals: [
301
- { id: '1', name: 'Acme Corp', amount: 50000 },
302
- { id: '2', name: 'Globex Inc', amount: 75000 },
303
- { id: '3', name: 'Initech LLC', amount: 30000 },
301
+ { id: "1", name: "Acme Corp", amount: 50000 },
302
+ { id: "2", name: "Globex Inc", amount: 75000 },
303
+ { id: "3", name: "Initech LLC", amount: 30000 },
304
304
  ],
305
305
  },
306
306
  },
307
307
  {
308
- type: 'text',
309
- text: 'Here are the 3 deals I found:\n\n1. **Acme Corp** — $50,000\n2. **Globex Inc** — $75,000\n3. **Initech LLC** — $30,000',
308
+ type: "text",
309
+ text: "Here are the 3 deals I found:\n\n1. **Acme Corp** — $50,000\n2. **Globex Inc** — $75,000\n3. **Initech LLC** — $30,000",
310
310
  },
311
311
  ],
312
312
  },
313
313
  ],
314
- }
314
+ };
315
315
 
316
316
  const multiTurnCassette: Cassette = {
317
317
  messages: [
318
318
  {
319
- role: 'user',
319
+ role: "user",
320
320
  content: [
321
- { type: 'text', text: 'Help me plan a REST API for a todo app.' },
321
+ { type: "text", text: "Help me plan a REST API for a todo app." },
322
322
  ],
323
323
  },
324
324
  {
325
- role: 'assistant',
325
+ role: "assistant",
326
326
  content: [
327
327
  {
328
- type: 'text',
328
+ type: "text",
329
329
  text: "Here's a clean REST API design for a todo app:\n\n| Method | Endpoint | Description |\n|--------|----------|-------------|\n| `GET` | `/todos` | List all todos |\n| `POST` | `/todos` | Create a new todo |\n| `GET` | `/todos/:id` | Get a single todo |\n| `PATCH` | `/todos/:id` | Update a todo |\n| `DELETE` | `/todos/:id` | Delete a todo |\n\nWant me to define the request/response schemas?",
330
330
  },
331
331
  ],
332
332
  },
333
333
  {
334
- role: 'user',
334
+ role: "user",
335
335
  content: [
336
- { type: 'text', text: 'Yes, show me the schema for creating a todo.' },
336
+ { type: "text", text: "Yes, show me the schema for creating a todo." },
337
337
  ],
338
338
  },
339
339
  {
340
- role: 'assistant',
340
+ role: "assistant",
341
341
  content: [
342
342
  {
343
- type: 'text',
343
+ type: "text",
344
344
  text: '**POST `/todos`**\n\n**Request body:**\n```json\n{\n "title": "Buy groceries",\n "description": "Milk, eggs, bread",\n "dueDate": "2025-03-15T10:00:00Z",\n "priority": "medium"\n}\n```\n\n**Response (`201 Created`):**\n```json\n{\n "id": "td_abc123",\n "title": "Buy groceries",\n "description": "Milk, eggs, bread",\n "completed": false,\n "dueDate": "2025-03-15T10:00:00Z",\n "priority": "medium",\n "createdAt": "2025-03-10T14:30:00Z",\n "updatedAt": "2025-03-10T14:30:00Z"\n}\n```\n\nThe `title` field is required — everything else is optional. The server generates `id`, `completed` (defaults to `false`), and timestamps.',
345
345
  },
346
346
  ],
347
347
  },
348
348
  {
349
- role: 'user',
350
- content: [{ type: 'text', text: 'What about validation errors?' }],
349
+ role: "user",
350
+ content: [{ type: "text", text: "What about validation errors?" }],
351
351
  },
352
352
  {
353
- role: 'assistant',
353
+ role: "assistant",
354
354
  content: [
355
355
  {
356
- type: 'text',
356
+ type: "text",
357
357
  text: 'For validation errors, return `422 Unprocessable Entity` with a structured error body:\n\n```json\n{\n "error": "validation_error",\n "message": "Request validation failed",\n "details": [\n {\n "field": "title",\n "message": "Title is required and must be between 1-200 characters"\n },\n {\n "field": "priority",\n "message": "Must be one of: low, medium, high"\n }\n ]\n}\n```\n\nThis gives clients enough information to display field-level errors in the UI. Keep the `details` array consistent across all endpoints.',
358
358
  },
359
359
  ],
360
360
  },
361
361
  ],
362
- }
362
+ };
363
363
 
364
364
  // ---------------------------------------------------------------------------
365
365
  // Stories
@@ -372,20 +372,20 @@ const multiTurnCassette: Cassette = {
372
372
  export const TextConversation: Story = () => (
373
373
  <Replay
374
374
  cassette={textOnlyCassette}
375
- config={{ variant: 'standalone' }}
375
+ config={{ variant: "standalone" }}
376
376
  typingSpeed={10}
377
377
  userMessageDelay={600}
378
378
  >
379
379
  <Chat />
380
380
  </Replay>
381
- )
381
+ );
382
382
  TextConversation.decorators = [
383
383
  (Story) => (
384
384
  <div className="m-auto flex h-screen w-full max-w-3xl flex-col px-4">
385
385
  <Story />
386
386
  </div>
387
387
  ),
388
- ]
388
+ ];
389
389
 
390
390
  /**
391
391
  * Replay with tool calls. The assistant invokes tools with visible
@@ -395,7 +395,7 @@ export const ToolCalls: Story = () => (
395
395
  <Replay
396
396
  cassette={toolCallCassette}
397
397
  config={{
398
- variant: 'standalone',
398
+ variant: "standalone",
399
399
  tools: { expandToolGroupsByDefault: true },
400
400
  }}
401
401
  typingSpeed={10}
@@ -403,14 +403,14 @@ export const ToolCalls: Story = () => (
403
403
  >
404
404
  <Chat />
405
405
  </Replay>
406
- )
406
+ );
407
407
  ToolCalls.decorators = [
408
408
  (Story) => (
409
409
  <div className="m-auto flex h-screen w-full max-w-3xl flex-col px-4">
410
410
  <Story />
411
411
  </div>
412
412
  ),
413
- ]
413
+ ];
414
414
 
415
415
  /**
416
416
  * BEFORE the fix (AGE-1295): simulates the duplicated tool calls that the
@@ -424,7 +424,7 @@ export const BeforeFix_DuplicatedToolCalls: Story = () => (
424
424
  <Replay
425
425
  cassette={beforeFixCassette}
426
426
  config={{
427
- variant: 'standalone',
427
+ variant: "standalone",
428
428
  tools: { expandToolGroupsByDefault: false },
429
429
  }}
430
430
  typingSpeed={0}
@@ -433,14 +433,14 @@ export const BeforeFix_DuplicatedToolCalls: Story = () => (
433
433
  >
434
434
  <Chat />
435
435
  </Replay>
436
- )
436
+ );
437
437
  BeforeFix_DuplicatedToolCalls.decorators = [
438
438
  (Story) => (
439
439
  <div className="m-auto flex h-screen w-full max-w-3xl flex-col px-4">
440
440
  <Story />
441
441
  </div>
442
442
  ),
443
- ]
443
+ ];
444
444
 
445
445
  /**
446
446
  * AFTER the fix (AGE-1295): the converter now deduplicates tool calls, so
@@ -452,7 +452,7 @@ export const AfterFix_DeduplicatedToolCalls: Story = () => (
452
452
  <Replay
453
453
  cassette={interleavedToolCallsCassette}
454
454
  config={{
455
- variant: 'standalone',
455
+ variant: "standalone",
456
456
  tools: { expandToolGroupsByDefault: false },
457
457
  }}
458
458
  typingSpeed={0}
@@ -461,14 +461,14 @@ export const AfterFix_DeduplicatedToolCalls: Story = () => (
461
461
  >
462
462
  <Chat />
463
463
  </Replay>
464
- )
464
+ );
465
465
  AfterFix_DeduplicatedToolCalls.decorators = [
466
466
  (Story) => (
467
467
  <div className="m-auto flex h-screen w-full max-w-3xl flex-col px-4">
468
468
  <Story />
469
469
  </div>
470
470
  ),
471
- ]
471
+ ];
472
472
 
473
473
  /**
474
474
  * Replay with reasoning (chain-of-thought) content. The assistant's
@@ -477,20 +477,20 @@ AfterFix_DeduplicatedToolCalls.decorators = [
477
477
  export const Reasoning: Story = () => (
478
478
  <Replay
479
479
  cassette={reasoningCassette}
480
- config={{ variant: 'standalone' }}
480
+ config={{ variant: "standalone" }}
481
481
  typingSpeed={10}
482
482
  userMessageDelay={600}
483
483
  >
484
484
  <Chat />
485
485
  </Replay>
486
- )
486
+ );
487
487
  Reasoning.decorators = [
488
488
  (Story) => (
489
489
  <div className="m-auto flex h-screen w-full max-w-3xl flex-col px-4">
490
490
  <Story />
491
491
  </div>
492
492
  ),
493
- ]
493
+ ];
494
494
 
495
495
  /**
496
496
  * Multi-turn conversation with multiple user/assistant exchanges,
@@ -499,21 +499,21 @@ Reasoning.decorators = [
499
499
  export const MultiTurn: Story = () => (
500
500
  <Replay
501
501
  cassette={multiTurnCassette}
502
- config={{ variant: 'standalone' }}
502
+ config={{ variant: "standalone" }}
503
503
  typingSpeed={8}
504
504
  userMessageDelay={500}
505
505
  assistantStartDelay={300}
506
506
  >
507
507
  <Chat />
508
508
  </Replay>
509
- )
509
+ );
510
510
  MultiTurn.decorators = [
511
511
  (Story) => (
512
512
  <div className="m-auto flex h-screen w-full max-w-3xl flex-col px-4">
513
513
  <Story />
514
514
  </div>
515
515
  ),
516
- ]
516
+ ];
517
517
 
518
518
  /**
519
519
  * Replay rendered in the widget (modal) variant, showing how replays
@@ -523,7 +523,7 @@ export const WidgetVariant: Story = () => (
523
523
  <Replay
524
524
  cassette={textOnlyCassette}
525
525
  config={{
526
- variant: 'widget',
526
+ variant: "widget",
527
527
  modal: { defaultOpen: true },
528
528
  }}
529
529
  typingSpeed={10}
@@ -531,7 +531,7 @@ export const WidgetVariant: Story = () => (
531
531
  >
532
532
  <Chat />
533
533
  </Replay>
534
- )
534
+ );
535
535
 
536
536
  /**
537
537
  * Fast replay with minimal delays — useful for quick demos or testing.
@@ -539,18 +539,18 @@ export const WidgetVariant: Story = () => (
539
539
  export const FastReplay: Story = () => (
540
540
  <Replay
541
541
  cassette={multiTurnCassette}
542
- config={{ variant: 'standalone' }}
542
+ config={{ variant: "standalone" }}
543
543
  typingSpeed={2}
544
544
  userMessageDelay={200}
545
545
  assistantStartDelay={100}
546
546
  >
547
547
  <Chat />
548
548
  </Replay>
549
- )
549
+ );
550
550
  FastReplay.decorators = [
551
551
  (Story) => (
552
552
  <div className="m-auto flex h-screen w-full max-w-3xl flex-col px-4">
553
553
  <Story />
554
554
  </div>
555
555
  ),
556
- ]
556
+ ];