@gram-ai/elements 1.25.1 → 1.25.2

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 (44) hide show
  1. package/dist/components/Chat/stories/MessageFeedback.stories.d.ts +1 -1
  2. package/dist/contexts/ChatIdContext.d.ts +11 -0
  3. package/dist/contexts/contexts.d.ts +1 -0
  4. package/dist/elements.cjs +1 -1
  5. package/dist/elements.css +1 -1
  6. package/dist/elements.js +7 -6
  7. package/dist/{index-iUSSoKFz.cjs → index-B8nSCdu4.cjs} +11 -11
  8. package/dist/index-B8nSCdu4.cjs.map +1 -0
  9. package/dist/{index-C3UbmFRR.cjs → index-CAtaLV1E.cjs} +63 -54
  10. package/dist/index-CAtaLV1E.cjs.map +1 -0
  11. package/dist/{index-CtyV0c-T.js → index-CJrwma08.js} +3737 -3730
  12. package/dist/index-CJrwma08.js.map +1 -0
  13. package/dist/{index-DxJwZ5Kc.js → index-DLWQ91ow.js} +8439 -8365
  14. package/dist/index-DLWQ91ow.js.map +1 -0
  15. package/dist/index.d.ts +1 -0
  16. package/dist/plugins.cjs +1 -1
  17. package/dist/plugins.js +1 -1
  18. package/dist/{profiler-CijCgLrw.js → profiler-BaG0scxd.js} +2 -2
  19. package/dist/{profiler-CijCgLrw.js.map → profiler-BaG0scxd.js.map} +1 -1
  20. package/dist/{profiler-DAT0DL1W.cjs → profiler-CuqENACf.cjs} +2 -2
  21. package/dist/{profiler-DAT0DL1W.cjs.map → profiler-CuqENACf.cjs.map} +1 -1
  22. package/dist/{startRecording-gmhENmf0.js → startRecording-86bHmd-l.js} +2 -2
  23. package/dist/{startRecording-gmhENmf0.js.map → startRecording-86bHmd-l.js.map} +1 -1
  24. package/dist/{startRecording-DotsE8QT.cjs → startRecording-BiLmoqZa.cjs} +2 -2
  25. package/dist/{startRecording-DotsE8QT.cjs.map → startRecording-BiLmoqZa.cjs.map} +1 -1
  26. package/dist/types/index.d.ts +4 -4
  27. package/package.json +1 -1
  28. package/src/components/Chat/stories/MessageFeedback.stories.tsx +6 -6
  29. package/src/components/Chat/stories/ToolApproval.stories.tsx +10 -10
  30. package/src/components/Chat/stories/Tools.stories.tsx +122 -104
  31. package/src/components/Chat/stories/Variants.stories.tsx +1 -1
  32. package/src/components/ShadowRoot.tsx +5 -1
  33. package/src/components/assistant-ui/message-feedback.tsx +6 -7
  34. package/src/components/assistant-ui/thread.tsx +76 -11
  35. package/src/contexts/ChatIdContext.tsx +21 -0
  36. package/src/contexts/ElementsProvider.tsx +77 -37
  37. package/src/contexts/contexts.ts +2 -0
  38. package/src/hooks/useAuth.ts +1 -2
  39. package/src/index.ts +1 -0
  40. package/src/types/index.ts +4 -4
  41. package/dist/index-C3UbmFRR.cjs.map +0 -1
  42. package/dist/index-CtyV0c-T.js.map +0 -1
  43. package/dist/index-DxJwZ5Kc.js.map +0 -1
  44. package/dist/index-iUSSoKFz.cjs.map +0 -1
@@ -59,6 +59,7 @@ import {
59
59
  useConnectionStatusOptional,
60
60
  } from './ConnectionStatusContext'
61
61
  import { ToolExecutionProvider } from './ToolExecutionContext'
62
+ import { ChatIdContext } from './ChatIdContext'
62
63
 
63
64
  /**
64
65
  * Extracts executable tools from frontend tool definitions.
@@ -93,14 +94,25 @@ export interface ElementsProviderProps {
93
94
  config: ElementsConfig
94
95
  }
95
96
 
96
- const BASE_SYSTEM_PROMPT = `You are a helpful assistant that can answer questions and help with tasks.`
97
+ const BASE_SYSTEM_PROMPT = `You are a helpful assistant that can answer questions and help with tasks.
98
+
99
+ Tool Result Display:
100
+ Some tools have custom visual components that automatically render their results (you'll see a rich card/widget appear). For these, do not repeat the data - just add brief context or a follow-up question if needed.
101
+
102
+ For tools WITHOUT custom components, you should present the data clearly - either as plain text for simple results, or using the UI code block format for structured data like lists of items, categories, or dashboards.`
97
103
 
98
104
  function mergeInternalSystemPromptWith(
99
105
  userSystemPrompt: string | undefined,
100
- plugins: Plugin[]
106
+ plugins: Plugin[],
107
+ toolsWithCustomComponents: string[]
101
108
  ) {
109
+ const customToolsSection =
110
+ toolsWithCustomComponents.length > 0
111
+ ? `\n\nTools with custom visual components (DO NOT render UI widgets for these - they already display rich visuals):\n${toolsWithCustomComponents.map((t) => `- ${t}`).join('\n')}`
112
+ : ''
113
+
102
114
  return `
103
- ${BASE_SYSTEM_PROMPT}
115
+ ${BASE_SYSTEM_PROMPT}${customToolsSection}
104
116
 
105
117
  User-provided System Prompt:
106
118
  ${userSystemPrompt ?? 'None provided'}
@@ -158,9 +170,13 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
158
170
 
159
171
  const plugins = config.plugins ?? recommended
160
172
 
173
+ // Get list of tools that have custom components registered
174
+ const toolsWithCustomComponents = Object.keys(config.tools?.components ?? {})
175
+
161
176
  const systemPrompt = mergeInternalSystemPromptWith(
162
177
  config.systemPrompt,
163
- plugins
178
+ plugins,
179
+ toolsWithCustomComponents
164
180
  )
165
181
 
166
182
  // Initialize error tracking on mount
@@ -176,6 +192,9 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
176
192
  // When history is enabled, the thread adapter manages chat IDs instead
177
193
  const chatIdRef = useRef<string | null>(null)
178
194
 
195
+ // State to expose the current chat ID via context
196
+ const [currentChatId, setCurrentChatId] = useState<string | null>(null)
197
+
179
198
  const { data: mcpTools, mcpHeaders } = useMCPTools({
180
199
  auth,
181
200
  mcp: config.mcp,
@@ -288,6 +307,8 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
288
307
  // chat ID on subsequent tool call requests.
289
308
  if (chatId) {
290
309
  mcpHeaders['Gram-Chat-ID'] = chatId
310
+ // Update the context state so consumers can access the current chat ID
311
+ setCurrentChatId(chatId)
291
312
  }
292
313
 
293
314
  const context = runtimeRef.current?.thread.getModelContext()
@@ -467,6 +488,8 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
467
488
  localIdToUuidMap={localIdToUuidMapRef.current}
468
489
  currentRemoteIdRef={currentRemoteIdRef}
469
490
  executableTools={executableTools}
491
+ currentChatId={currentChatId}
492
+ setCurrentChatId={setCurrentChatId}
470
493
  >
471
494
  {children}
472
495
  </ElementsProviderWithHistory>
@@ -480,6 +503,7 @@ const ElementsProviderInner = ({ children, config }: ElementsProviderProps) => {
480
503
  runtimeRef={runtimeRef}
481
504
  frontendTools={frontendTools}
482
505
  executableTools={executableTools}
506
+ currentChatId={currentChatId}
483
507
  >
484
508
  {children}
485
509
  </ElementsProviderWithoutHistory>
@@ -506,23 +530,28 @@ interface ElementsProviderWithHistoryProps {
506
530
  localIdToUuidMap: Map<string, string>
507
531
  currentRemoteIdRef: React.RefObject<string | null>
508
532
  executableTools: ExecutableToolSet
533
+ currentChatId: string | null
534
+ setCurrentChatId: (chatId: string | null) => void
509
535
  }
510
536
 
511
537
  /**
512
- * Component that syncs the current thread's remoteId to a ref.
538
+ * Component that syncs the current thread's remoteId to a ref and updates the chat ID context.
513
539
  * Must be rendered inside AssistantRuntimeProvider to access the state.
514
540
  */
515
541
  const ThreadIdSync = ({
516
542
  remoteIdRef,
543
+ onChatIdChange,
517
544
  }: {
518
545
  remoteIdRef: React.RefObject<string | null>
546
+ onChatIdChange: (chatId: string | null) => void
519
547
  }) => {
520
548
  const remoteId = useAssistantState(
521
549
  ({ threadListItem }) => threadListItem.remoteId ?? null
522
550
  )
523
551
  useEffect(() => {
524
552
  remoteIdRef.current = remoteId
525
- }, [remoteId, remoteIdRef])
553
+ onChatIdChange(remoteId)
554
+ }, [remoteId, remoteIdRef, onChatIdChange])
526
555
  return null
527
556
  }
528
557
 
@@ -537,6 +566,8 @@ const ElementsProviderWithHistory = ({
537
566
  localIdToUuidMap,
538
567
  currentRemoteIdRef,
539
568
  executableTools,
569
+ currentChatId,
570
+ setCurrentChatId,
540
571
  }: ElementsProviderWithHistoryProps) => {
541
572
  const threadListAdapter = useGramThreadListAdapter({
542
573
  apiUrl,
@@ -582,23 +613,28 @@ const ElementsProviderWithHistory = ({
582
613
 
583
614
  return (
584
615
  <AssistantRuntimeProvider runtime={runtime}>
585
- <ThreadIdSync remoteIdRef={currentRemoteIdRef} />
616
+ <ThreadIdSync
617
+ remoteIdRef={currentRemoteIdRef}
618
+ onChatIdChange={setCurrentChatId}
619
+ />
586
620
  <HistoryProvider>
587
- <ElementsContext.Provider value={contextValue}>
588
- <ToolExecutionProvider tools={executableTools}>
589
- <div
590
- className={cn(
591
- ROOT_SELECTOR,
592
- (contextValue?.config.variant === 'standalone' ||
593
- contextValue?.config.variant === 'sidecar') &&
594
- 'h-full'
595
- )}
596
- >
597
- {children}
598
- </div>
599
- <FrontendTools tools={frontendTools} />
600
- </ToolExecutionProvider>
601
- </ElementsContext.Provider>
621
+ <ChatIdContext.Provider value={{ chatId: currentChatId }}>
622
+ <ElementsContext.Provider value={contextValue}>
623
+ <ToolExecutionProvider tools={executableTools}>
624
+ <div
625
+ className={cn(
626
+ ROOT_SELECTOR,
627
+ (contextValue?.config.variant === 'standalone' ||
628
+ contextValue?.config.variant === 'sidecar') &&
629
+ 'h-full'
630
+ )}
631
+ >
632
+ {children}
633
+ </div>
634
+ <FrontendTools tools={frontendTools} />
635
+ </ToolExecutionProvider>
636
+ </ElementsContext.Provider>
637
+ </ChatIdContext.Provider>
602
638
  </HistoryProvider>
603
639
  </AssistantRuntimeProvider>
604
640
  )
@@ -613,6 +649,7 @@ interface ElementsProviderWithoutHistoryProps {
613
649
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
614
650
  frontendTools: Record<string, AssistantTool | FrontendTool<any, any>>
615
651
  executableTools: ExecutableToolSet
652
+ currentChatId: string | null
616
653
  }
617
654
 
618
655
  const ElementsProviderWithoutHistory = ({
@@ -622,6 +659,7 @@ const ElementsProviderWithoutHistory = ({
622
659
  runtimeRef,
623
660
  frontendTools,
624
661
  executableTools,
662
+ currentChatId,
625
663
  }: ElementsProviderWithoutHistoryProps) => {
626
664
  const runtime = useChatRuntime({ transport })
627
665
 
@@ -632,21 +670,23 @@ const ElementsProviderWithoutHistory = ({
632
670
 
633
671
  return (
634
672
  <AssistantRuntimeProvider runtime={runtime}>
635
- <ElementsContext.Provider value={contextValue}>
636
- <ToolExecutionProvider tools={executableTools}>
637
- <div
638
- className={cn(
639
- ROOT_SELECTOR,
640
- (contextValue?.config.variant === 'standalone' ||
641
- contextValue?.config.variant === 'sidecar') &&
642
- 'h-full'
643
- )}
644
- >
645
- {children}
646
- </div>
647
- <FrontendTools tools={frontendTools} />
648
- </ToolExecutionProvider>
649
- </ElementsContext.Provider>
673
+ <ChatIdContext.Provider value={{ chatId: currentChatId }}>
674
+ <ElementsContext.Provider value={contextValue}>
675
+ <ToolExecutionProvider tools={executableTools}>
676
+ <div
677
+ className={cn(
678
+ ROOT_SELECTOR,
679
+ (contextValue?.config.variant === 'standalone' ||
680
+ contextValue?.config.variant === 'sidecar') &&
681
+ 'h-full'
682
+ )}
683
+ >
684
+ {children}
685
+ </div>
686
+ <FrontendTools tools={frontendTools} />
687
+ </ToolExecutionProvider>
688
+ </ElementsContext.Provider>
689
+ </ChatIdContext.Provider>
650
690
  </AssistantRuntimeProvider>
651
691
  )
652
692
  }
@@ -8,3 +8,5 @@ export const ElementsContext = createContext<ElementsContextType | undefined>(
8
8
 
9
9
  export const ToolApprovalContext =
10
10
  createContext<ToolApprovalContextType | null>(null)
11
+
12
+ export { useChatId } from './ChatIdContext'
@@ -49,11 +49,10 @@ export const useAuth = ({
49
49
  : defaultGetSession
50
50
  }, [auth])
51
51
 
52
- // The session request is only neccessary if we are not using an API key auth
52
+ // The session request is only neccessary if we are not using static session auth
53
53
  // configuration. If a custom session fetcher is provided, we use it,
54
54
  // otherwise we fallback to the default session fetcher
55
55
  const session = useSession({
56
- // We want to check it's NOT API key auth, as the default auth scheme is session auth (if the user hasn't provided an explicit API config, we have a session auth config by default)
57
56
  getSession,
58
57
  projectSlug,
59
58
  })
package/src/index.ts CHANGED
@@ -10,6 +10,7 @@ export { ElementsProvider } from './contexts/ElementsProvider'
10
10
  export { useElements as useGramElements } from './hooks/useElements'
11
11
  export { useElements } from './hooks/useElements'
12
12
  export { useThreadId } from './hooks/useThreadId'
13
+ export { useChatId } from './contexts/ChatIdContext'
13
14
 
14
15
  // Core Components
15
16
  export { Chat } from '@/components/Chat'
@@ -315,7 +315,7 @@ export interface ElementsConfig {
315
315
  * @example
316
316
  * const config: ElementsConfig = {
317
317
  * thread: {
318
- * experimental_showFeedback: true,
318
+ * showFeedback: true,
319
319
  * followUpSuggestions: true,
320
320
  * },
321
321
  * }
@@ -853,7 +853,7 @@ export interface SidecarConfig extends ExpandableConfig {
853
853
  * @example
854
854
  * const config: ElementsConfig = {
855
855
  * thread: {
856
- * experimental_showFeedback: true,
856
+ * showFeedback: true,
857
857
  * followUpSuggestions: true,
858
858
  * },
859
859
  * }
@@ -862,9 +862,9 @@ export interface ThreadConfig {
862
862
  /**
863
863
  * Whether to show feedback buttons (like/dislike) after assistant messages.
864
864
  * When enabled, users can mark conversations as resolved or provide feedback.
865
- * @default false
865
+ * @default true
866
866
  */
867
- experimental_showFeedback?: boolean
867
+ showFeedback?: boolean
868
868
 
869
869
  /**
870
870
  * Whether to show AI-generated follow-up question suggestions after each assistant response.