@gram-ai/elements 1.25.1 → 1.26.0

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 (177) hide show
  1. package/dist/components/Chat/stories/Charts.stories.d.ts +37 -0
  2. package/dist/components/Chat/stories/GenerativeUI.stories.d.ts +17 -0
  3. package/dist/components/Chat/stories/MessageFeedback.stories.d.ts +1 -1
  4. package/dist/components/ui/button.d.ts +1 -1
  5. package/dist/components/ui/buttonVariants.d.ts +1 -1
  6. package/dist/components/ui/charts.stories.d.ts +43 -0
  7. package/dist/components/ui/generative-ui.stories.d.ts +53 -0
  8. package/dist/contexts/ChatIdContext.d.ts +11 -0
  9. package/dist/contexts/contexts.d.ts +1 -0
  10. package/dist/elements.cjs +1 -1
  11. package/dist/elements.css +1 -1
  12. package/dist/elements.js +7 -6
  13. package/dist/index-BJnv49-A.js +37057 -0
  14. package/dist/index-BJnv49-A.js.map +1 -0
  15. package/dist/index-BpJstUh1.cjs +280 -0
  16. package/dist/index-BpJstUh1.cjs.map +1 -0
  17. package/dist/index-CUitXazZ.js +30426 -0
  18. package/dist/index-CUitXazZ.js.map +1 -0
  19. package/dist/index-ChW-CSuu.cjs +147 -0
  20. package/dist/index-ChW-CSuu.cjs.map +1 -0
  21. package/dist/index.d.ts +1 -0
  22. package/dist/plugins/chart/catalog.d.ts +123 -0
  23. package/dist/plugins/chart/index.d.ts +1 -1
  24. package/dist/plugins/chart/ui/area-chart.d.ts +16 -0
  25. package/dist/plugins/chart/ui/bar-chart.d.ts +16 -0
  26. package/dist/plugins/chart/ui/donut-chart.d.ts +17 -0
  27. package/dist/plugins/chart/ui/index.d.ts +7 -0
  28. package/dist/plugins/chart/ui/line-chart.d.ts +17 -0
  29. package/dist/plugins/chart/ui/pie-chart.d.ts +15 -0
  30. package/dist/plugins/chart/ui/radar-chart.d.ts +14 -0
  31. package/dist/plugins/chart/ui/scatter-chart.d.ts +18 -0
  32. package/dist/plugins/components/MacOSWindowFrame.d.ts +13 -0
  33. package/dist/plugins/components/PluginLoadingState.d.ts +1 -1
  34. package/dist/plugins/generative-ui/catalog.d.ts +293 -0
  35. package/dist/plugins/generative-ui/ui/accordion-wrapper.d.ts +18 -0
  36. package/dist/plugins/generative-ui/ui/accordion.d.ts +7 -0
  37. package/dist/plugins/generative-ui/ui/action-button.d.ts +10 -0
  38. package/dist/plugins/generative-ui/ui/alert-wrapper.d.ts +9 -0
  39. package/dist/plugins/generative-ui/ui/alert.d.ts +9 -0
  40. package/dist/plugins/generative-ui/ui/avatar-wrapper.d.ts +9 -0
  41. package/dist/plugins/generative-ui/ui/avatar.d.ts +11 -0
  42. package/dist/plugins/generative-ui/ui/badge.d.ts +12 -0
  43. package/dist/plugins/generative-ui/ui/button-wrapper.d.ts +15 -0
  44. package/dist/plugins/generative-ui/ui/button.d.ts +10 -0
  45. package/dist/plugins/generative-ui/ui/card-wrapper.d.ts +10 -0
  46. package/dist/plugins/generative-ui/ui/card.d.ts +9 -0
  47. package/dist/plugins/generative-ui/ui/checkbox-wrapper.d.ts +10 -0
  48. package/dist/plugins/generative-ui/ui/checkbox.d.ts +4 -0
  49. package/dist/plugins/generative-ui/ui/data-table.d.ts +10 -0
  50. package/dist/plugins/generative-ui/ui/dialog.d.ts +17 -0
  51. package/dist/plugins/generative-ui/ui/dropdown-menu.d.ts +25 -0
  52. package/dist/plugins/generative-ui/ui/grid.d.ts +6 -0
  53. package/dist/plugins/generative-ui/ui/index.d.ts +40 -0
  54. package/dist/plugins/generative-ui/ui/input-wrapper.d.ts +11 -0
  55. package/dist/plugins/generative-ui/ui/input.d.ts +3 -0
  56. package/dist/plugins/generative-ui/ui/label.d.ts +4 -0
  57. package/dist/plugins/generative-ui/ui/list.d.ts +6 -0
  58. package/dist/plugins/generative-ui/ui/metric.d.ts +7 -0
  59. package/dist/plugins/generative-ui/ui/pagination.d.ts +13 -0
  60. package/dist/plugins/generative-ui/ui/popover.d.ts +10 -0
  61. package/dist/plugins/generative-ui/ui/progress.d.ts +10 -0
  62. package/dist/plugins/generative-ui/ui/radio-group.d.ts +5 -0
  63. package/dist/plugins/generative-ui/ui/select-wrapper.d.ts +13 -0
  64. package/dist/plugins/generative-ui/ui/select.d.ts +15 -0
  65. package/dist/plugins/generative-ui/ui/separator.d.ts +4 -0
  66. package/dist/plugins/generative-ui/ui/skeleton-wrapper.d.ts +9 -0
  67. package/dist/plugins/generative-ui/ui/skeleton.d.ts +2 -0
  68. package/dist/plugins/generative-ui/ui/stack.d.ts +8 -0
  69. package/dist/plugins/generative-ui/ui/switch.d.ts +6 -0
  70. package/dist/plugins/generative-ui/ui/table.d.ts +10 -0
  71. package/dist/plugins/generative-ui/ui/tabs-wrapper.d.ts +21 -0
  72. package/dist/plugins/generative-ui/ui/tabs.d.ts +11 -0
  73. package/dist/plugins/generative-ui/ui/text.d.ts +7 -0
  74. package/dist/plugins/generative-ui/ui/textarea.d.ts +3 -0
  75. package/dist/plugins/generative-ui/ui/tooltip.d.ts +7 -0
  76. package/dist/plugins.cjs +1 -1
  77. package/dist/plugins.js +1 -1
  78. package/dist/{profiler-CijCgLrw.js → profiler-D4Tw5ecI.js} +2 -2
  79. package/dist/{profiler-CijCgLrw.js.map → profiler-D4Tw5ecI.js.map} +1 -1
  80. package/dist/{profiler-DAT0DL1W.cjs → profiler-DCWYDZ1F.cjs} +2 -2
  81. package/dist/{profiler-DAT0DL1W.cjs.map → profiler-DCWYDZ1F.cjs.map} +1 -1
  82. package/dist/{startRecording-DotsE8QT.cjs → startRecording-3sTskM3H.cjs} +2 -2
  83. package/dist/{startRecording-DotsE8QT.cjs.map → startRecording-3sTskM3H.cjs.map} +1 -1
  84. package/dist/{startRecording-gmhENmf0.js → startRecording-BHhcCWQE.js} +2 -2
  85. package/dist/{startRecording-gmhENmf0.js.map → startRecording-BHhcCWQE.js.map} +1 -1
  86. package/dist/types/index.d.ts +4 -4
  87. package/package.json +4 -1
  88. package/src/components/Chat/stories/Charts.stories.tsx +260 -0
  89. package/src/components/Chat/stories/ConnectionConfiguration.stories.tsx +6 -6
  90. package/src/components/Chat/stories/GenerativeUI.stories.tsx +113 -0
  91. package/src/components/Chat/stories/MessageFeedback.stories.tsx +6 -6
  92. package/src/components/Chat/stories/ToolApproval.stories.tsx +10 -10
  93. package/src/components/Chat/stories/Tools.stories.tsx +122 -104
  94. package/src/components/Chat/stories/Variants.stories.tsx +1 -1
  95. package/src/components/Replay.stories.tsx +1 -1
  96. package/src/components/Replay.tsx +18 -13
  97. package/src/components/ShadowRoot.tsx +5 -1
  98. package/src/components/assistant-ui/message-feedback.tsx +6 -7
  99. package/src/components/assistant-ui/thread.tsx +76 -11
  100. package/src/components/ui/charts.stories.tsx +246 -0
  101. package/src/components/ui/generative-ui.stories.tsx +557 -0
  102. package/src/components/ui/generative-ui.tsx +60 -360
  103. package/src/components/ui/tool-ui.stories.tsx +6 -3
  104. package/src/contexts/ChatIdContext.tsx +21 -0
  105. package/src/contexts/ElementsProvider.tsx +77 -37
  106. package/src/contexts/contexts.ts +2 -0
  107. package/src/hooks/useAuth.ts +18 -3
  108. package/src/hooks/useFollowOnSuggestions.ts +6 -1
  109. package/src/index.ts +1 -0
  110. package/src/plugins/chart/catalog.ts +141 -0
  111. package/src/plugins/chart/component.tsx +79 -125
  112. package/src/plugins/chart/index.ts +141 -89
  113. package/src/plugins/chart/ui/area-chart.tsx +133 -0
  114. package/src/plugins/chart/ui/bar-chart.tsx +137 -0
  115. package/src/plugins/chart/ui/donut-chart.tsx +167 -0
  116. package/src/plugins/chart/ui/index.ts +7 -0
  117. package/src/plugins/chart/ui/line-chart.tsx +135 -0
  118. package/src/plugins/chart/ui/pie-chart.tsx +148 -0
  119. package/src/plugins/chart/ui/radar-chart.tsx +105 -0
  120. package/src/plugins/chart/ui/scatter-chart.tsx +132 -0
  121. package/src/plugins/components/MacOSWindowFrame.tsx +55 -0
  122. package/src/plugins/components/PluginLoadingState.tsx +9 -13
  123. package/src/plugins/generative-ui/catalog.ts +277 -0
  124. package/src/plugins/generative-ui/component.tsx +112 -21
  125. package/src/plugins/generative-ui/index.ts +20 -141
  126. package/src/plugins/generative-ui/ui/accordion-wrapper.tsx +57 -0
  127. package/src/plugins/generative-ui/ui/accordion.tsx +66 -0
  128. package/src/plugins/generative-ui/ui/action-button.tsx +68 -0
  129. package/src/plugins/generative-ui/ui/alert-wrapper.tsx +26 -0
  130. package/src/plugins/generative-ui/ui/alert.tsx +66 -0
  131. package/src/plugins/generative-ui/ui/avatar-wrapper.tsx +22 -0
  132. package/src/plugins/generative-ui/ui/avatar.tsx +109 -0
  133. package/src/plugins/generative-ui/ui/badge.tsx +65 -0
  134. package/src/plugins/generative-ui/ui/button-wrapper.tsx +32 -0
  135. package/src/plugins/generative-ui/ui/button.tsx +65 -0
  136. package/src/plugins/generative-ui/ui/card-wrapper.tsx +36 -0
  137. package/src/plugins/generative-ui/ui/card.tsx +92 -0
  138. package/src/plugins/generative-ui/ui/checkbox-wrapper.tsx +39 -0
  139. package/src/plugins/generative-ui/ui/checkbox.tsx +32 -0
  140. package/src/plugins/generative-ui/ui/data-table.tsx +53 -0
  141. package/src/plugins/generative-ui/ui/dialog.tsx +158 -0
  142. package/src/plugins/generative-ui/ui/dropdown-menu.tsx +257 -0
  143. package/src/plugins/generative-ui/ui/grid.tsx +29 -0
  144. package/src/plugins/generative-ui/ui/index.ts +43 -0
  145. package/src/plugins/generative-ui/ui/input-wrapper.tsx +38 -0
  146. package/src/plugins/generative-ui/ui/input.tsx +21 -0
  147. package/src/plugins/generative-ui/ui/label.tsx +24 -0
  148. package/src/plugins/generative-ui/ui/list.tsx +34 -0
  149. package/src/plugins/generative-ui/ui/metric.tsx +53 -0
  150. package/src/plugins/generative-ui/ui/pagination.tsx +127 -0
  151. package/src/plugins/generative-ui/ui/popover.tsx +89 -0
  152. package/src/plugins/generative-ui/ui/progress.tsx +57 -0
  153. package/src/plugins/generative-ui/ui/radio-group.tsx +45 -0
  154. package/src/plugins/generative-ui/ui/select-wrapper.tsx +41 -0
  155. package/src/plugins/generative-ui/ui/select.tsx +190 -0
  156. package/src/plugins/generative-ui/ui/separator.tsx +28 -0
  157. package/src/plugins/generative-ui/ui/skeleton-wrapper.tsx +30 -0
  158. package/src/plugins/generative-ui/ui/skeleton.tsx +13 -0
  159. package/src/plugins/generative-ui/ui/stack.tsx +54 -0
  160. package/src/plugins/generative-ui/ui/switch.tsx +35 -0
  161. package/src/plugins/generative-ui/ui/table.tsx +116 -0
  162. package/src/plugins/generative-ui/ui/tabs-wrapper.tsx +51 -0
  163. package/src/plugins/generative-ui/ui/tabs.tsx +92 -0
  164. package/src/plugins/generative-ui/ui/text.tsx +33 -0
  165. package/src/plugins/generative-ui/ui/textarea.tsx +18 -0
  166. package/src/plugins/generative-ui/ui/tooltip.tsx +57 -0
  167. package/src/types/index.ts +4 -4
  168. package/dist/components/Chat/stories/Plugins.stories.d.ts +0 -12
  169. package/dist/index-C3UbmFRR.cjs +0 -178
  170. package/dist/index-C3UbmFRR.cjs.map +0 -1
  171. package/dist/index-CtyV0c-T.js +0 -27225
  172. package/dist/index-CtyV0c-T.js.map +0 -1
  173. package/dist/index-DxJwZ5Kc.js +0 -39975
  174. package/dist/index-DxJwZ5Kc.js.map +0 -1
  175. package/dist/index-iUSSoKFz.cjs +0 -251
  176. package/dist/index-iUSSoKFz.cjs.map +0 -1
  177. package/src/components/Chat/stories/Plugins.stories.tsx +0 -158
@@ -0,0 +1,113 @@
1
+ import type { Meta, StoryFn } from '@storybook/react-vite'
2
+ import { Chat } from '..'
3
+
4
+ const meta: Meta<typeof Chat> = {
5
+ title: 'Chat/Plugins/Generative UI',
6
+ component: Chat,
7
+ parameters: {
8
+ layout: 'fullscreen',
9
+ },
10
+ } satisfies Meta<typeof Chat>
11
+
12
+ export default meta
13
+
14
+ type Story = StoryFn<typeof Chat>
15
+
16
+ /**
17
+ * E-commerce store assistant with natural task-focused prompts.
18
+ */
19
+ export const StoreAssistant: Story = () => <Chat />
20
+ StoreAssistant.parameters = {
21
+ elements: {
22
+ config: {
23
+ variant: 'standalone',
24
+ welcome: {
25
+ title: 'Store Assistant',
26
+ subtitle: 'How can I help you today?',
27
+ suggestions: [
28
+ {
29
+ title: 'My Orders',
30
+ label: 'View recent orders',
31
+ prompt: 'Show me my current orders',
32
+ },
33
+ {
34
+ title: 'Browse Products',
35
+ label: "See what's available",
36
+ prompt: 'What products do you have?',
37
+ },
38
+ {
39
+ title: 'Find Deals',
40
+ label: 'Best prices',
41
+ prompt: 'What are the best deals right now?',
42
+ },
43
+ ],
44
+ },
45
+ },
46
+ },
47
+ }
48
+
49
+ /**
50
+ * Shopping assistant for product discovery.
51
+ */
52
+ export const ShoppingAssistant: Story = () => <Chat />
53
+ ShoppingAssistant.parameters = {
54
+ elements: {
55
+ config: {
56
+ variant: 'standalone',
57
+ welcome: {
58
+ title: 'Shopping Assistant',
59
+ subtitle: 'Find the perfect product',
60
+ suggestions: [
61
+ {
62
+ title: 'New Arrivals',
63
+ label: 'Latest products',
64
+ prompt: 'Show me the newest products',
65
+ },
66
+ {
67
+ title: 'Gift Ideas',
68
+ label: 'Under $50',
69
+ prompt: 'I need a gift under $50, what do you recommend?',
70
+ },
71
+ {
72
+ title: 'Compare Options',
73
+ label: 'Help me decide',
74
+ prompt: 'Can you compare your top 3 products for me?',
75
+ },
76
+ ],
77
+ },
78
+ },
79
+ },
80
+ }
81
+
82
+ /**
83
+ * Store management assistant.
84
+ */
85
+ export const StoreManager: Story = () => <Chat />
86
+ StoreManager.parameters = {
87
+ elements: {
88
+ config: {
89
+ variant: 'standalone',
90
+ welcome: {
91
+ title: 'Store Manager',
92
+ subtitle: 'Manage your store',
93
+ suggestions: [
94
+ {
95
+ title: 'Stock Check',
96
+ label: 'Inventory status',
97
+ prompt: 'Which products are running low on stock?',
98
+ },
99
+ {
100
+ title: 'Sales Summary',
101
+ label: 'How are we doing?',
102
+ prompt: 'How are sales looking this month?',
103
+ },
104
+ {
105
+ title: 'Top Sellers',
106
+ label: 'Best performers',
107
+ prompt: 'What are our best selling products?',
108
+ },
109
+ ],
110
+ },
111
+ },
112
+ },
113
+ }
@@ -1,7 +1,7 @@
1
- import { Chat } from '..'
2
- import type { Meta, StoryFn } from '@storybook/react-vite'
3
1
  import { MessageFeedback } from '@/components/assistant-ui/message-feedback'
2
+ import type { Meta, StoryFn } from '@storybook/react-vite'
4
3
  import { LazyMotion, domAnimation } from 'motion/react'
4
+ import { Chat } from '..'
5
5
 
6
6
  const meta: Meta<typeof Chat> = {
7
7
  title: 'Chat/Message Feedback',
@@ -25,7 +25,7 @@ Default.parameters = {
25
25
  config: {
26
26
  variant: 'standalone',
27
27
  thread: {
28
- experimental_showFeedback: true,
28
+ showFeedback: true,
29
29
  },
30
30
  welcome: {
31
31
  title: 'Message Feedback Demo',
@@ -59,7 +59,7 @@ Widget.parameters = {
59
59
  variant: 'widget',
60
60
  modal: { defaultOpen: true },
61
61
  thread: {
62
- experimental_showFeedback: true,
62
+ showFeedback: true,
63
63
  },
64
64
  welcome: {
65
65
  title: 'Message Feedback Demo',
@@ -91,7 +91,7 @@ Sidecar.parameters = {
91
91
  config: {
92
92
  variant: 'sidecar',
93
93
  thread: {
94
- experimental_showFeedback: true,
94
+ showFeedback: true,
95
95
  },
96
96
  welcome: {
97
97
  title: 'Message Feedback Demo',
@@ -122,7 +122,7 @@ WithFollowUpSuggestions.parameters = {
122
122
  systemPrompt:
123
123
  'You are a helpful customer support assistant. Keep ALL responses extremely brief - 1-2 sentences only. No lists, no elaboration.',
124
124
  thread: {
125
- experimental_showFeedback: true,
125
+ showFeedback: true,
126
126
  followUpSuggestions: true,
127
127
  },
128
128
  welcome: {
@@ -24,13 +24,13 @@ SingleTool.parameters = {
24
24
  suggestions: [
25
25
  {
26
26
  title: 'Call a tool requiring approval',
27
- label: 'Get a salutation',
28
- prompt: 'Get a salutation',
27
+ label: 'Add to cart',
28
+ prompt: 'List products and add the first one to my cart',
29
29
  },
30
30
  ],
31
31
  },
32
32
  tools: {
33
- toolsRequiringApproval: ['kitchen_sink_get_salutation'],
33
+ toolsRequiringApproval: ['ecommerce_api_add_to_cart'],
34
34
  },
35
35
  },
36
36
  },
@@ -45,14 +45,14 @@ SingleToolWithFunction.parameters = {
45
45
  variant: 'standalone',
46
46
  tools: {
47
47
  toolsRequiringApproval: ({ toolName }: { toolName: string }) =>
48
- toolName.endsWith('salutation'),
48
+ toolName.includes('order') || toolName.includes('cart'),
49
49
  },
50
50
  welcome: {
51
51
  suggestions: [
52
52
  {
53
53
  title: 'Call a tool requiring approval',
54
- label: 'Get a salutation',
55
- prompt: 'Get a salutation',
54
+ label: 'Create an order',
55
+ prompt: 'List products and create an order for the first one',
56
56
  },
57
57
  ],
58
58
  },
@@ -70,16 +70,16 @@ MultipleGroupedTools.parameters = {
70
70
  suggestions: [
71
71
  {
72
72
  title: 'Call both tools requiring approval',
73
- label: 'Call both tools requiring approval',
73
+ label: 'Add to cart and create order',
74
74
  prompt:
75
- 'Call both kitchen_sink_get_salutation and kitchen_sink_get_get_card_details',
75
+ 'List products, add the first one to my cart, and then create an order',
76
76
  },
77
77
  ],
78
78
  },
79
79
  tools: {
80
80
  toolsRequiringApproval: [
81
- 'kitchen_sink_get_salutation',
82
- 'kitchen_sink_get_get_card_details',
81
+ 'ecommerce_api_add_to_cart',
82
+ 'ecommerce_api_create_order',
83
83
  ],
84
84
  },
85
85
  },
@@ -1,8 +1,9 @@
1
1
  import { ToolCallMessagePartProps } from '@assistant-ui/react'
2
2
  import type { Meta, StoryFn } from '@storybook/react-vite'
3
- import React from 'react'
3
+ import React, { useState, useCallback } from 'react'
4
4
  import z from 'zod'
5
5
  import { Chat } from '..'
6
+ import { useToolExecution } from '../../../contexts/ToolExecutionContext'
6
7
  import { defineFrontendTool } from '../../../lib/tools'
7
8
 
8
9
  const meta: Meta<typeof Chat> = {
@@ -17,128 +18,145 @@ export default meta
17
18
 
18
19
  type Story = StoryFn<typeof Chat>
19
20
 
20
- const CardPinRevealComponent = ({
21
- result,
22
- argsText,
23
- }: ToolCallMessagePartProps) => {
24
- const [isFlipped, setIsFlipped] = React.useState(false)
21
+ const ProductCardComponent = ({ result }: ToolCallMessagePartProps) => {
22
+ const { executeTool, isToolAvailable } = useToolExecution()
23
+ const [isLoading, setIsLoading] = useState(false)
24
+ const [addedToCart, setAddedToCart] = useState(false)
25
+
26
+ // Parse the result to get product details
27
+ let product = {
28
+ id: '',
29
+ name: 'Loading...',
30
+ description: '',
31
+ price: 0,
32
+ category: '',
33
+ rating: 0,
34
+ reviewCount: 0,
35
+ imageUrl: '',
36
+ inStock: true,
37
+ }
25
38
 
26
- // Parse the result to get the pin
27
- let pin = '****'
28
39
  try {
29
40
  if (result) {
30
41
  const parsed = typeof result === 'string' ? JSON.parse(result) : result
31
42
  if (parsed?.content?.[0]?.text) {
32
43
  const content = JSON.parse(parsed.content[0].text)
33
- pin = content.pin || '****'
34
- } else if (parsed?.pin) {
35
- pin = parsed.pin
44
+ product = { ...product, ...content }
45
+ } else if (parsed?.name) {
46
+ product = { ...product, ...parsed }
36
47
  }
37
48
  }
38
49
  } catch {
39
50
  // Fallback to default
40
51
  }
41
52
 
42
- const args = JSON.parse(argsText || '{}')
43
- const cardNumber = args?.queryParameters?.cardNumber || '4532 •••• •••• 1234'
44
- const cardHolder = 'JOHN DOE'
45
- const expiry = '12/25'
46
- const cvv = '123'
53
+ const canAddToCart = isToolAvailable('ecommerce_api_add_to_cart')
47
54
 
48
- if (!cardNumber) {
49
- return null
50
- }
55
+ const handleAddToCart = useCallback(async () => {
56
+ if (!product.id || !canAddToCart) return
51
57
 
52
- return (
53
- <div className="my-4 perspective-[1000px]">
54
- <div
55
- className={`relative h-48 w-80 cursor-pointer transition-transform duration-700 [transform-style:preserve-3d] ${
56
- isFlipped ? 'transform-[rotateY(180deg)]' : ''
57
- }`}
58
- onClick={() => setIsFlipped(!isFlipped)}
59
- >
60
- {/* Front of card */}
61
- <div className="absolute inset-0 backface-hidden">
62
- <div className="relative h-full w-full overflow-hidden rounded-xl bg-gradient-to-br from-indigo-600 via-purple-600 to-pink-500 p-6 text-white shadow-2xl">
63
- {/* Card pattern overlay */}
64
- <div className="absolute inset-0 opacity-10">
65
- <div className="absolute -top-10 -right-10 h-40 w-40 rounded-full bg-white"></div>
66
- <div className="absolute -bottom-10 -left-10 h-32 w-32 rounded-full bg-white"></div>
67
- </div>
58
+ setIsLoading(true)
59
+ try {
60
+ // HTTP tools from OpenAPI expect body content wrapped in a 'body' field
61
+ const toolResult = await executeTool('ecommerce_api_add_to_cart', {
62
+ body: {
63
+ productId: product.id,
64
+ quantity: 1,
65
+ },
66
+ })
68
67
 
69
- {/* Card content */}
70
- <div className="relative z-10 flex h-full flex-col justify-between">
71
- <div className="flex items-center justify-between">
72
- <div className="text-2xl font-bold">VISA</div>
73
- <div className="h-8 w-12 rounded bg-white/20"></div>
74
- </div>
68
+ if (toolResult.success) {
69
+ setAddedToCart(true)
70
+ } else {
71
+ console.error('[ProductCard] Tool failed:', toolResult.error)
72
+ }
73
+ } catch (err) {
74
+ console.error('[ProductCard] Exception:', err)
75
+ } finally {
76
+ setIsLoading(false)
77
+ }
78
+ }, [product.id, canAddToCart, executeTool])
75
79
 
76
- <div className="space-y-2">
77
- <div className="font-mono text-2xl tracking-wider">
78
- {cardNumber}
79
- </div>
80
- <div className="flex items-center justify-between text-sm">
81
- <div>
82
- <div className="text-xs opacity-70">CARDHOLDER</div>
83
- <div className="font-semibold">{cardHolder}</div>
84
- </div>
85
- <div>
86
- <div className="text-xs opacity-70">EXPIRES</div>
87
- <div className="font-semibold">{expiry}</div>
88
- </div>
89
- </div>
90
- </div>
80
+ return (
81
+ <div className="my-4 w-80">
82
+ <div className="overflow-hidden rounded-xl bg-white shadow-lg dark:bg-slate-800">
83
+ {/* Product Image */}
84
+ <div className="relative h-48 bg-gradient-to-br from-indigo-100 to-purple-100 dark:from-indigo-900 dark:to-purple-900">
85
+ {product.imageUrl ? (
86
+ <img
87
+ src={product.imageUrl}
88
+ alt={product.name}
89
+ className="h-full w-full object-cover"
90
+ />
91
+ ) : (
92
+ <div className="flex h-full items-center justify-center">
93
+ <span className="text-6xl">📦</span>
91
94
  </div>
92
-
93
- {/* Click hint */}
94
- <div className="absolute right-2 bottom-2 text-xs opacity-50">
95
- Click to flip
95
+ )}
96
+ {!product.inStock && (
97
+ <div className="absolute top-2 right-2 rounded-full bg-red-500 px-2 py-1 text-xs font-semibold text-white">
98
+ Out of Stock
96
99
  </div>
97
- </div>
100
+ )}
98
101
  </div>
99
102
 
100
- {/* Back of card */}
101
- <div className="absolute inset-0 transform-[rotateY(180deg)] backface-hidden">
102
- <div className="relative h-full w-full overflow-hidden rounded-xl bg-gradient-to-br from-slate-800 via-slate-700 to-slate-900 p-6 text-white shadow-2xl">
103
- {/* Magnetic strip */}
104
- <div className="absolute top-8 right-0 left-0 h-12 bg-black"></div>
105
-
106
- {/* Card content */}
107
- <div className="relative z-10 flex h-full flex-col justify-between">
108
- <div className="mt-16 space-y-4">
109
- <div className="flex items-center gap-2">
110
- <div className="h-8 flex-1 rounded bg-white/10 px-3 py-2 text-right font-mono text-sm">
111
- {cvv}
112
- </div>
113
- <div className="text-xs opacity-70">CVV</div>
114
- </div>
115
-
116
- {/* PIN Display */}
117
- <div className="mt-6 space-y-2">
118
- <div className="text-xs opacity-70">PIN</div>
119
- <div className="flex items-center gap-3">
120
- <div className="flex h-16 w-16 items-center justify-center rounded-lg bg-gradient-to-br from-yellow-400 to-orange-500 shadow-lg">
121
- <span className="text-2xl font-bold text-white">
122
- {pin}
123
- </span>
124
- </div>
125
- <div className="text-xs opacity-60">
126
- Keep this PIN secure
127
- </div>
128
- </div>
129
- </div>
130
- </div>
103
+ {/* Product Details */}
104
+ <div className="p-4">
105
+ <div className="mb-1 text-xs font-medium tracking-wide text-indigo-500 uppercase dark:text-indigo-400">
106
+ {product.category}
107
+ </div>
108
+ <h3 className="mb-2 text-lg font-bold text-slate-900 dark:text-white">
109
+ {product.name}
110
+ </h3>
111
+ <p className="mb-3 line-clamp-2 text-sm text-slate-600 dark:text-slate-300">
112
+ {product.description}
113
+ </p>
131
114
 
132
- <div className="flex items-center justify-between text-xs opacity-50">
133
- <div>VISA</div>
134
- <div>{cardNumber}</div>
135
- </div>
115
+ {/* Rating */}
116
+ <div className="mb-3 flex items-center gap-1">
117
+ <div className="flex">
118
+ {[1, 2, 3, 4, 5].map((star) => (
119
+ <span
120
+ key={star}
121
+ className={
122
+ star <= Math.round(product.rating)
123
+ ? 'text-yellow-400'
124
+ : 'text-slate-300'
125
+ }
126
+ >
127
+
128
+ </span>
129
+ ))}
136
130
  </div>
131
+ <span className="text-sm text-slate-500">
132
+ ({product.reviewCount} reviews)
133
+ </span>
134
+ </div>
137
135
 
138
- {/* Click hint */}
139
- <div className="absolute bottom-2 left-2 text-xs opacity-50">
140
- Click to flip back
141
- </div>
136
+ {/* Price and Add to Cart */}
137
+ <div className="flex items-center justify-between">
138
+ <span className="text-2xl font-bold text-slate-900 dark:text-white">
139
+ ${product.price?.toFixed(2)}
140
+ </span>
141
+ <button
142
+ onClick={handleAddToCart}
143
+ disabled={
144
+ isLoading || addedToCart || !canAddToCart || !product.inStock
145
+ }
146
+ className={`rounded-lg px-4 py-2 text-sm font-semibold text-white transition-colors ${
147
+ addedToCart
148
+ ? 'bg-green-500'
149
+ : isLoading
150
+ ? 'bg-indigo-400'
151
+ : 'bg-indigo-600 hover:bg-indigo-700'
152
+ } disabled:cursor-not-allowed disabled:opacity-50`}
153
+ >
154
+ {addedToCart
155
+ ? '✓ Added'
156
+ : isLoading
157
+ ? 'Adding...'
158
+ : 'Add to Cart'}
159
+ </button>
142
160
  </div>
143
161
  </div>
144
162
  </div>
@@ -154,15 +172,15 @@ CustomToolComponent.parameters = {
154
172
  welcome: {
155
173
  suggestions: [
156
174
  {
157
- title: 'Get card details',
158
- label: 'for your card',
159
- prompt: 'Get card details for your card number 4532 •••• •••• 1234',
175
+ title: 'Get product details',
176
+ label: 'View a product',
177
+ prompt: 'List products and then show me details for the first one',
160
178
  },
161
179
  ],
162
180
  },
163
181
  tools: {
164
182
  components: {
165
- kitchen_sink_get_get_card_details: CardPinRevealComponent,
183
+ ecommerce_api_get_product: ProductCardComponent,
166
184
  },
167
185
  },
168
186
  },
@@ -61,7 +61,7 @@ StandaloneWithHistory.parameters = {
61
61
  history: { enabled: true, showThreadList: true },
62
62
  model: { showModelPicker: true },
63
63
  tools: {
64
- toolsRequiringApproval: ['kitchen_sink_get_salutation'],
64
+ toolsRequiringApproval: ['ecommerce_api_create_order'],
65
65
  },
66
66
  },
67
67
  },
@@ -5,7 +5,7 @@ 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: 'Replay',
8
+ title: 'Misc/Replay',
9
9
  component: Replay,
10
10
  parameters: {
11
11
  layout: 'fullscreen',
@@ -20,6 +20,7 @@
20
20
  */
21
21
 
22
22
  import { ROOT_SELECTOR } from '@/constants/tailwind'
23
+ import { ChatIdContext } from '@/contexts/ChatIdContext'
23
24
  import { ElementsContext } from '@/contexts/contexts'
24
25
  import { ReplayContext } from '@/contexts/ReplayContext'
25
26
  import { ToolApprovalProvider } from '@/contexts/ToolApprovalContext'
@@ -110,24 +111,28 @@ export const Replay = ({
110
111
 
111
112
  const replayCtx = useMemo(() => ({ isReplay: true }), [])
112
113
 
114
+ const chatIdValue = useMemo(() => ({ chatId: 'replay' }), [])
115
+
113
116
  return (
114
117
  <QueryClientProvider client={replayQueryClient}>
115
118
  <AssistantRuntimeProvider runtime={runtime}>
116
119
  <ReplayContext.Provider value={replayCtx}>
117
120
  <ElementsContext.Provider value={contextValue}>
118
- <ToolApprovalProvider>
119
- <div
120
- className={cn(
121
- ROOT_SELECTOR,
122
- (config.variant === 'standalone' ||
123
- config.variant === 'sidecar') &&
124
- 'h-full min-h-0 flex-1'
125
- )}
126
- >
127
- {children}
128
- </div>
129
- <ReplayController cassette={cassette} options={replayOptions} />
130
- </ToolApprovalProvider>
121
+ <ChatIdContext.Provider value={chatIdValue}>
122
+ <ToolApprovalProvider>
123
+ <div
124
+ className={cn(
125
+ ROOT_SELECTOR,
126
+ (config.variant === 'standalone' ||
127
+ config.variant === 'sidecar') &&
128
+ 'h-full min-h-0 flex-1'
129
+ )}
130
+ >
131
+ {children}
132
+ </div>
133
+ <ReplayController cassette={cassette} options={replayOptions} />
134
+ </ToolApprovalProvider>
135
+ </ChatIdContext.Provider>
131
136
  </ElementsContext.Provider>
132
137
  </ReplayContext.Provider>
133
138
  </AssistantRuntimeProvider>
@@ -69,7 +69,11 @@ export const ShadowRoot = ({
69
69
  }, [shadowRoot, elementsStyles])
70
70
 
71
71
  return (
72
- <div ref={hostRef} className={hostClassName} style={hostStyle}>
72
+ <div
73
+ ref={hostRef}
74
+ className={hostClassName}
75
+ style={{ isolation: 'isolate', ...hostStyle }}
76
+ >
73
77
  {shadowRoot
74
78
  ? createPortal(
75
79
  <div
@@ -1,16 +1,15 @@
1
- import { X, Heart } from 'lucide-react'
2
- import * as m from 'motion/react-m'
3
- import { useState, type FC } from 'react'
4
- import { AnimatePresence } from 'motion/react'
5
-
6
- import { cn } from '@/lib/utils'
7
- import { EASE_OUT_QUINT } from '@/lib/easing'
8
1
  import {
9
2
  Tooltip,
10
3
  TooltipContent,
11
4
  TooltipProvider,
12
5
  TooltipTrigger,
13
6
  } from '@/components/ui/tooltip'
7
+ import { EASE_OUT_QUINT } from '@/lib/easing'
8
+ import { cn } from '@/lib/utils'
9
+ import { Heart, X } from 'lucide-react'
10
+ import { AnimatePresence } from 'motion/react'
11
+ import * as m from 'motion/react-m'
12
+ import { useState, type FC } from 'react'
14
13
 
15
14
  export type FeedbackType = 'dislike' | 'like'
16
15