@gram-ai/elements 1.13.10 → 1.15.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.
package/README.md CHANGED
@@ -97,374 +97,32 @@ export const App = () => {
97
97
 
98
98
  ## Configuration
99
99
 
100
- The `ElementsConfig` object accepts the following configuration options:
101
-
102
- ### Top-Level Configuration
103
-
104
- | Property | Type | Required | Status | Default | Description |
105
- | -------------- | ---------------------------------------------------------- | -------- | -------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
106
- | `systemPrompt` | `string` | No | ✅ Implemented | `undefined` | The system prompt to use for the Elements library |
107
- | `projectSlug` | `string` | Yes | ✅ Implemented | - | The project slug to use for the Elements library |
108
- | `mcp` | `string` | Yes | ✅ Implemented | - | The Gram Server URL. Can be retrieved from `https://app.getgram.ai/{team}/{project}/mcp/{mcp_slug}` |
109
- | `chatEndpoint` | `string` | No | ✅ Implemented | `'/chat/completions'` | The path of your backend's chat endpoint |
110
- | `environment` | `Record<string, unknown>` | No | ✅ Implemented | `undefined` | Custom environment variable overrides for the MCP server. See [Gram documentation](https://www.speakeasy.com/docs/gram/host-mcp/public-private-servers#pass-through-authentication) for pass-through authentication |
111
- | `variant` | `'widget' \| 'sidecar' \| 'standalone'` | No | ✅ Implemented | `'widget'` | The layout variant for the chat interface. `widget` is a popup modal, `sidecar` is a side panel, `standalone` is a full-page experience |
112
- | `plugins` | [`Plugin[]`](#plugins) | No | ✅ Implemented | `[]` | Array of plugins to extend rendering capabilities. See [Plugins section](#plugins) for details |
113
- | `components` | [`ComponentOverrides`](#component-overrides) | No | ✅ Implemented | `undefined` | Override default UI components with custom implementations. See [Component Overrides section](#component-overrides) for details |
114
- | `theme` | [`ThemeConfig`](#theme-configuration-themeconfig) | No | ✅ Implemented | `undefined` | Visual appearance configuration options |
115
- | `welcome` | [`WelcomeConfig`](#welcome-configuration-welcomeconfig) | Yes | ✅ Implemented | - | Configuration for the welcome message and initial suggestions |
116
- | `composer` | [`ComposerConfig`](#composer-configuration-composerconfig) | No | ✅ Implemented | `undefined` | Configuration for the composer input |
117
- | `modal` | [`ModalConfig`](#modal-configuration-modalconfig) | No | ✅ Implemented | `undefined` | Configuration for the modal window (does not apply if variant is `'standalone'`) |
118
- | `sidecar` | [`SidecarConfig`](#sidecar-configuration-sidecarconfig) | No | ✅ Implemented | `undefined` | Configuration for the sidecar panel (only applies if variant is `'sidecar'`) |
119
- | `model` | [`ModelConfig`](#model-configuration-modelconfig) | No | ✅ Implemented | `undefined` | LLM model configuration |
120
- | `tools` | [`ToolsConfig`](#tools-configuration-toolsconfig) | No | ✅ Implemented | `undefined` | Configuration for custom tool components |
121
-
122
- ### Welcome Configuration (`WelcomeConfig`)
123
-
124
- | Property | Type | Required | Status | Default | Description |
125
- | ------------- | ------------------------------------ | -------- | -------------- | ----------- | --------------------------------------------------------------- |
126
- | `title` | `string` | Yes | ✅ Implemented | - | The welcome message title to display when the thread is empty |
127
- | `subtitle` | `string` | Yes | ✅ Implemented | - | The subtitle to display when the thread is empty |
128
- | `suggestions` | [`Suggestion[]`](#suggestion-object) | No | ✅ Implemented | `undefined` | Array of suggestion prompts to display when the thread is empty |
129
-
130
- #### Suggestion Object
131
-
132
- | Property | Type | Required | Status | Description |
133
- | -------- | -------- | -------- | -------------- | ---------------------------------------------- |
134
- | `title` | `string` | Yes | ✅ Implemented | The title of the suggestion |
135
- | `label` | `string` | Yes | ✅ Implemented | The label text for the suggestion |
136
- | `action` | `string` | Yes | ✅ Implemented | The prompt text that will be sent when clicked |
137
-
138
- ### Composer Configuration (`ComposerConfig`)
139
-
140
- | Property | Type | Required | Status | Default | Description |
141
- | ------------- | -------------------------------------------------------------------------------- | -------- | ---------------------- | --------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
142
- | `placeholder` | `string` | No | ✅ Implemented | `'Send a message...'` | The placeholder text for the composer input |
143
- | `attachments` | `boolean \| `[`AttachmentsConfig`](#attachments-configuration-attachmentsconfig) | No | ⚠️ Not yet implemented | `true` | Configuration for file attachments. Set to `false` to disable, `true` for defaults, or provide an object for fine-grained control |
144
-
145
- #### Attachments Configuration (`AttachmentsConfig`)
146
-
147
- | Property | Type | Required | Status | Default | Description |
148
- | ---------- | ---------- | -------- | ---------------------- | ----------- | --------------------------------------------------------------------------- |
149
- | `accept` | `string[]` | No | ⚠️ Not yet implemented | `undefined` | Accepted file types (MIME types or extensions), e.g., `['image/*', '.pdf']` |
150
- | `maxCount` | `number` | No | ⚠️ Not yet implemented | `10` | Maximum number of files that can be attached at once |
151
- | `maxSize` | `number` | No | ⚠️ Not yet implemented | `104857600` | Maximum file size in bytes (default: 100MB) |
152
-
153
- ### Modal Configuration (`ModalConfig`)
154
-
155
- | Property | Type | Required | Status | Default | Description |
156
- | ------------- | ----------------------------------------------------------------------------------- | -------- | -------------- | ---------------- | ------------------------------------------------------------ |
157
- | `defaultOpen` | `boolean` | No | ✅ Implemented | `false` | Whether to open the modal window by default |
158
- | `title` | `string` | No | ✅ Implemented | `'Chat'` | The title displayed in the modal header |
159
- | `position` | `'bottom-right' \| 'bottom-left' \| 'top-right' \| 'top-left'` | No | ✅ Implemented | `'bottom-right'` | The position of the modal trigger button |
160
- | `icon` | `(state: 'open' \| 'closed' \| undefined) => ReactNode` | No | ✅ Implemented | `undefined` | Custom icon component function that receives the modal state |
161
- | `expandable` | `boolean` | No | ✅ Implemented | `false` | Whether the modal can be expanded to full screen |
162
- | `dimensions` | `{ default: ModalDimension, expanded?: Pick<ModalDimension, 'width' \| 'height'> }` | No | ✅ Implemented | `undefined` | The dimensions for default and expanded states of the modal |
163
-
164
- #### Modal Dimension Object
165
-
166
- | Property | Type | Description |
167
- | ----------- | ------------------------ | -------------------------------------- |
168
- | `width` | `number \| '${number}%'` | Width of the modal |
169
- | `height` | `number \| '${number}%'` | Height of the modal |
170
- | `maxHeight` | `number \| '${number}%'` | Maximum height of the modal (optional) |
171
-
172
- ### Sidecar Configuration (`SidecarConfig`)
173
-
174
- | Property | Type | Required | Status | Default | Description |
175
- | --------------- | ---------------------------------- | -------- | -------------- | --------- | -------------------------------------------- |
176
- | `title` | `string` | No | ✅ Implemented | `'Chat'` | The title displayed in the sidecar header |
177
- | `width` | `string \| number \| '${number}%'` | No | ✅ Implemented | `'400px'` | The width of the sidecar panel |
178
- | `expandedWidth` | `string \| number \| '${number}%'` | No | ✅ Implemented | `'800px'` | The width of the sidecar panel when expanded |
179
-
180
- ### Theme Configuration (`ThemeConfig`)
181
-
182
- | Property | Type | Required | Status | Default | Description |
183
- | ------------- | ------------------------------------- | -------- | -------------- | ---------- | --------------------------------------------------------------------------------------- |
184
- | `colorScheme` | `'light' \| 'dark' \| 'system'` | No | ✅ Implemented | `'light'` | The color scheme to use for the UI |
185
- | `density` | `'compact' \| 'normal' \| 'spacious'` | No | ✅ Implemented | `'normal'` | Determines the overall spacing. `compact` reduces padding, `spacious` increases padding |
186
- | `radius` | `'round' \| 'soft' \| 'sharp'` | No | ✅ Implemented | `'soft'` | Determines the overall roundness. `round` is large radius, `sharp` is minimal radius |
187
-
188
- ### Model Configuration (`ModelConfig`)
189
-
190
- | Property | Type | Required | Status | Default | Description |
191
- | ----------------- | ---------------------------- | -------- | -------------- | ------------------------------- | ------------------------------------------------ |
192
- | `showModelPicker` | `boolean` | No | ✅ Implemented | `false` | Whether to show the model picker in the composer |
193
- | `defaultModel` | [`Model`](#available-models) | No | ✅ Implemented | `'anthropic/claude-sonnet-4.5'` | The default model to use |
194
-
195
- #### Available Models
196
-
197
- The following models are currently supported:
198
-
199
- - `anthropic/claude-sonnet-4.5`
200
- - `anthropic/claude-haiku-4.5`
201
- - `anthropic/claude-sonnet-4`
202
- - `anthropic/claude-opus-4.5`
203
- - `openai/gpt-4o`
204
- - `openai/gpt-4o-mini`
205
- - `openai/gpt-5.1-codex`
206
- - `openai/gpt-5`
207
- - `openai/gpt-5.1`
208
- - `openai/gpt-4.1`
209
- - `anthropic/claude-3.7-sonnet`
210
- - `anthropic/claude-opus-4`
211
- - `google/gemini-2.5-pro-preview`
212
- - `google/gemini-3-pro-preview`
213
- - `moonshotai/kimi-k2`
214
- - `mistralai/mistral-medium-3`
215
- - `mistralai/mistral-medium-3.1`
216
- - `mistralai/codestral-2501`
217
-
218
- ### Tools Configuration (`ToolsConfig`)
219
-
220
- | Property | Type | Required | Status | Default | Description |
221
- | ------------ | ---------------------------------------------- | -------- | -------------- | ----------- | ------------------------------------------------------------------------------------------ |
222
- | `components` | `Record<string, ToolCallMessagePartComponent>` | No | ✅ Implemented | `undefined` | Override default React components for specific tool results. Tool names must match exactly |
223
-
224
- ## Component Overrides
225
-
226
- The `components` property in `ElementsConfig` allows you to override default UI components with your own custom implementations. This provides fine-grained control over the appearance and behavior of different parts of the chat interface.
227
-
228
- ### Available Component Overrides
229
-
230
- | Component | Type | Description |
231
- | ------------------ | ------------------------------- | ------------------------------------------------------------ |
232
- | `Composer` | `ComponentType` | The composer input area where users type messages |
233
- | `UserMessage` | `ComponentType` | The entire user message bubble/container |
234
- | `EditComposer` | `ComponentType` | The composer shown when editing a user message |
235
- | `AssistantMessage` | `ComponentType` | The entire assistant message bubble/container |
236
- | `ThreadWelcome` | `ComponentType` | The welcome screen shown when the thread is empty |
237
- | `Text` | `TextMessagePartComponent` | Text content within messages (supports Markdown by default) |
238
- | `Image` | `ImageMessagePartComponent` | Image attachments within messages |
239
- | `ToolFallback` | `ToolCallMessagePartComponent` | Default component for tool results without custom components |
240
- | `Reasoning` | `ReasoningMessagePartComponent` | Individual reasoning steps shown in assistant messages |
241
- | `ReasoningGroup` | `ReasoningGroupComponent` | Container for grouped reasoning steps |
242
- | `ToolGroup` | `ComponentType` | Container for grouped tool calls |
243
-
244
- ### Component Override Examples
245
-
246
- #### Basic Text Override
247
-
248
- Override how text is rendered in assistant messages:
100
+ For complete configuration options and TypeScript type definitions, see the [API documentation](./docs/interfaces/ElementsConfig.md).
249
101
 
250
- ```typescript
251
- import { ElementsConfig } from '@gram-ai/elements'
252
- import { useAssistantState } from '@assistant-ui/react'
253
-
254
- const config: ElementsConfig = {
255
- projectSlug: 'my-project',
256
- mcp: 'https://app.getgram.ai/mcp/my-mcp-slug',
257
- welcome: {
258
- title: 'Hello!',
259
- subtitle: 'How can I help you today?',
260
- },
261
- components: {
262
- Text: () => {
263
- const message = useAssistantState(({ message }) => message)
264
- const text = message.parts
265
- .map((part) => (part.type === 'text' ? part.text : ''))
266
- .join('')
267
-
268
- return (
269
- <div className="custom-text">
270
- {text}
271
- </div>
272
- )
273
- },
274
- },
275
- }
276
- ```
277
-
278
- #### Custom Welcome Screen
279
-
280
- Override the welcome screen with your own design:
102
+ ### Quick Configuration Example
281
103
 
282
104
  ```typescript
283
- import { ElementsConfig } from '@gram-ai/elements'
284
-
285
- const CustomWelcome = () => {
286
- return (
287
- <div className="flex flex-col items-center justify-center h-full">
288
- <h1 className="text-4xl font-bold mb-4">Welcome to My AI Assistant!</h1>
289
- <p className="text-gray-600">Start chatting below</p>
290
- </div>
291
- )
292
- }
105
+ import { GramElementsProvider, Chat, type ElementsConfig } from '@gram-ai/elements'
106
+ import '@gram-ai/elements/elements.css'
293
107
 
294
108
  const config: ElementsConfig = {
295
- projectSlug: 'my-project',
296
- mcp: 'https://app.getgram.ai/mcp/my-mcp-slug',
109
+ projectSlug: 'your-project',
110
+ mcp: 'https://app.getgram.ai/mcp/your-mcp-slug',
111
+ chatEndpoint: '/chat/completions',
112
+ variant: 'widget', // 'widget' | 'sidecar' | 'standalone'
297
113
  welcome: {
298
114
  title: 'Hello!',
299
115
  subtitle: 'How can I help you today?',
300
116
  },
301
- components: {
302
- ThreadWelcome: CustomWelcome,
303
- },
304
117
  }
305
- ```
306
118
 
307
- #### Custom Message Containers
308
-
309
- Override the entire message container for more control:
310
-
311
- ```typescript
312
- import { ElementsConfig } from '@gram-ai/elements'
313
- import { MessagePrimitive } from '@assistant-ui/react'
314
-
315
- const CustomUserMessage = () => {
119
+ export const App = () => {
316
120
  return (
317
- <MessagePrimitive.Root>
318
- <div className="my-custom-user-message">
319
- <div className="message-avatar">👤</div>
320
- <div className="message-content">
321
- <MessagePrimitive.Parts />
322
- </div>
323
- </div>
324
- </MessagePrimitive.Root>
121
+ <GramElementsProvider config={config}>
122
+ <Chat />
123
+ </GramElementsProvider>
325
124
  )
326
125
  }
327
-
328
- const config: ElementsConfig = {
329
- projectSlug: 'my-project',
330
- mcp: 'https://app.getgram.ai/mcp/my-mcp-slug',
331
- welcome: {
332
- title: 'Hello!',
333
- subtitle: 'How can I help you today?',
334
- },
335
- components: {
336
- UserMessage: CustomUserMessage,
337
- },
338
- }
339
- ```
340
-
341
- #### Combining Multiple Overrides
342
-
343
- You can override multiple components at once:
344
-
345
- ```typescript
346
- import { ElementsConfig } from '@gram-ai/elements'
347
- import {
348
- CustomComposer,
349
- CustomUserMessage,
350
- CustomAssistantMessage,
351
- CustomText,
352
- } from './components'
353
-
354
- const config: ElementsConfig = {
355
- projectSlug: 'my-project',
356
- mcp: 'https://app.getgram.ai/mcp/my-mcp-slug',
357
- welcome: {
358
- title: 'Hello!',
359
- subtitle: 'How can I help you today?',
360
- },
361
- components: {
362
- Composer: CustomComposer,
363
- UserMessage: CustomUserMessage,
364
- AssistantMessage: CustomAssistantMessage,
365
- Text: CustomText,
366
- },
367
- }
368
- ```
369
-
370
- ### Notes on Component Overrides
371
-
372
- - Component overrides give you full control over rendering, but you're responsible for maintaining the expected behavior
373
- - When overriding message containers (`UserMessage`, `AssistantMessage`), make sure to include `MessagePrimitive.Root` and `MessagePrimitive.Parts` to maintain compatibility with the assistant-ui runtime
374
- - For text content overrides, the default `Text` component supports Markdown rendering. If you override it, you'll need to implement your own Markdown support if needed
375
- - Component overrides are applied globally across your chat interface
376
- - For building custom components from scratch, refer to the [assistant-ui Context API documentation](https://www.assistant-ui.com/docs/guides/context-api) which provides detailed information about the state management system, available actions, and hooks like `useAssistantState`, `useAssistantApi`, and `useAssistantEvent`
377
-
378
- ### Configuration Examples
379
-
380
- #### Minimal Configuration
381
-
382
- ```typescript
383
- import { ElementsConfig } from '@gram-ai/elements'
384
-
385
- const config: ElementsConfig = {
386
- projectSlug: 'my-project',
387
- mcp: 'https://app.getgram.ai/mcp/my-mcp-slug',
388
- welcome: {
389
- title: 'Welcome!',
390
- subtitle: 'How can I assist you today?',
391
- },
392
- }
393
- ```
394
-
395
- #### Full Configuration with All Options
396
-
397
- ```typescript
398
- import { ElementsConfig } from '@gram-ai/elements'
399
- import { recommended } from '@gram-ai/elements/plugins'
400
- import { WeatherComponent } from './components/WeatherComponent'
401
- import { CustomText } from './components/CustomText'
402
-
403
- const config: ElementsConfig = {
404
- systemPrompt: 'You are a helpful AI assistant.',
405
- projectSlug: 'my-project',
406
- mcp: 'https://app.getgram.ai/mcp/my-mcp-slug',
407
- chatEndpoint: '/api/chat',
408
- variant: 'widget',
409
- plugins: recommended,
410
- components: {
411
- Text: CustomText,
412
- },
413
- theme: {
414
- colorScheme: 'system',
415
- density: 'normal',
416
- radius: 'soft',
417
- },
418
- environment: {
419
- API_KEY: 'your-api-key',
420
- BASE_URL: 'https://api.example.com',
421
- },
422
- welcome: {
423
- title: 'Hello!',
424
- subtitle: 'How can I help you today?',
425
- suggestions: [
426
- {
427
- title: 'Get Weather',
428
- label: 'Check current weather',
429
- action: 'What is the weather like today?',
430
- },
431
- {
432
- title: 'Summarize',
433
- label: 'Summarize a document',
434
- action: 'Can you summarize this document for me?',
435
- },
436
- ],
437
- },
438
- composer: {
439
- placeholder: 'Type your message...',
440
- },
441
- modal: {
442
- defaultOpen: false,
443
- title: 'AI Assistant',
444
- position: 'bottom-right',
445
- expandable: true,
446
- dimensions: {
447
- default: {
448
- width: 400,
449
- height: 600,
450
- maxHeight: '90%',
451
- },
452
- expanded: {
453
- width: '90%',
454
- height: '90%',
455
- },
456
- },
457
- },
458
- model: {
459
- showModelPicker: true,
460
- defaultModel: 'anthropic/claude-sonnet-4.5',
461
- },
462
- tools: {
463
- components: {
464
- get_current_weather: WeatherComponent,
465
- },
466
- },
467
- }
468
126
  ```
469
127
 
470
128
  ## Plugins
@@ -0,0 +1,4 @@
1
+ import { AssistantTool } from '@assistant-ui/react';
2
+ export declare function FrontendTools({ tools: frontendTools, }: {
3
+ tools: Record<string, AssistantTool>;
4
+ }): import("react/jsx-runtime").JSX.Element;