@grafana/assistant 0.0.15 → 0.0.17

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
@@ -36,7 +36,9 @@ function MyComponent() {
36
36
  }
37
37
 
38
38
  return (
39
- <button onClick={() => openAssistant({ prompt: 'Help me analyze data' })}>
39
+ <button onClick={() => openAssistant({
40
+ origin: 'grafana/panel-data-analyzer',
41
+ prompt: 'Help me analyze data' })}>
40
42
  Open Assistant
41
43
  </button>
42
44
  );
@@ -49,10 +51,15 @@ function MyComponent() {
49
51
  import { openAssistant, closeAssistant } from '@grafana/assistant';
50
52
 
51
53
  // Open the assistant with an initial prompt
52
- openAssistant({ prompt: 'Show me CPU usage over the last hour' });
54
+ openAssistant({ origin: 'grafana/some-feature', prompt: 'Show me CPU usage over the last hour' });
55
+
56
+ // Open the assistant with initial prompt and autoSend set to false
57
+ openAssistant({ origin: 'grafana-datasources/prometheus/some-feature', prompt: 'Help me analyze data', autoSend: false })
53
58
 
54
59
  // Open the assistant without an initial prompt
55
- openAssistant({});
60
+ openAssistant({
61
+ origin: 'grafana-slo-app/some-page',
62
+ });
56
63
 
57
64
  // Close the assistant
58
65
  closeAssistant();
@@ -61,16 +68,14 @@ closeAssistant();
61
68
  ### Using Context with the Assistant
62
69
 
63
70
  ```typescript
64
- import { openAssistant, createContext } from '@grafana/assistant';
71
+ import { openAssistant, createAssistantContextItem } from '@grafana/assistant';
65
72
 
66
73
  // Create context items to provide additional information to the assistant
67
- const datasourceContext = createContext('datasource', {
68
- datasourceName: 'My Prometheus',
74
+ const datasourceContext = createAssistantContextItem('datasource', {
69
75
  datasourceUid: 'prometheus-uid',
70
- datasourceType: 'prometheus'
71
76
  });
72
77
 
73
- const dashboardContext = createContext('dashboard', {
78
+ const dashboardContext = createAssistantContextItem('dashboard', {
74
79
  dashboardUid: 'dashboard-uid',
75
80
  dashboardTitle: 'System Overview',
76
81
  folderUid: 'folder-uid',
@@ -79,9 +84,26 @@ const dashboardContext = createContext('dashboard', {
79
84
 
80
85
  // Open the assistant with initial prompt and context
81
86
  openAssistant({
87
+ origin: 'grafana/dashboard-page',
82
88
  prompt: 'Analyze the CPU metrics from this dashboard',
83
89
  context: [datasourceContext, dashboardContext]
84
90
  });
91
+
92
+ // Create hidden context for system instructions (won't show in UI pills)
93
+ const systemInstructions = createAssistantContextItem('structured', {
94
+ hidden: true,
95
+ title: 'System Instructions',
96
+ data: {
97
+ instructions: 'When analyzing metrics, always consider seasonal patterns and anomalies',
98
+ preferences: 'Use clear, technical language and provide actionable insights'
99
+ }
100
+ });
101
+
102
+ // Include hidden context with visible context
103
+ openAssistant({
104
+ prompt: 'What are the trends in this data?',
105
+ context: [datasourceContext, systemInstructions]
106
+ });
85
107
  ```
86
108
 
87
109
  ### Providing Page-Specific Context
@@ -89,10 +111,10 @@ openAssistant({
89
111
  You can register context items that are automatically included when the assistant is opened on pages matching specific URL patterns. The `providePageContext` function returns a setter function that allows you to update the context dynamically:
90
112
 
91
113
  ```typescript
92
- import { providePageContext, createContext } from '@grafana/assistant';
114
+ import { providePageContext, createAssistantContextItem } from '@grafana/assistant';
93
115
 
94
116
  // Create initial context for dashboard pages
95
- const dashboardContext = createContext('structured', {
117
+ const dashboardContext = createAssistantContextItem('structured', {
96
118
  data: {
97
119
  name: 'Dashboard Context',
98
120
  pageType: 'dashboard',
@@ -107,7 +129,7 @@ const setContext = providePageContext('/d/*', [dashboardContext]);
107
129
  // Later, dynamically update the context based on user interactions or data changes
108
130
  setContext([
109
131
  dashboardContext,
110
- createContext('structured', {
132
+ createAssistantContextItem('structured', {
111
133
  data: {
112
134
  name: 'Panel Context',
113
135
  selectedPanel: 'cpu-usage-panel',
@@ -118,6 +140,17 @@ setContext([
118
140
 
119
141
  // Clean up when no longer needed
120
142
  setContext.unregister();
143
+
144
+ // Example: Provide hidden system instructions for explore pages
145
+ providePageContext('/explore', [
146
+ createAssistantContextItem('structured', {
147
+ hidden: true,
148
+ title: 'Additional instructions',
149
+ data: {
150
+ 'System Instructions': 'When working with explore queries, always validate the time range and check for data availability. Suggest using recording rules for expensive queries.',
151
+ },
152
+ }),
153
+ ]);
121
154
  ```
122
155
 
123
156
  ### Using Page Context in React Components
@@ -125,10 +158,10 @@ setContext.unregister();
125
158
  For React components, use the `useProvidePageContext` hook which automatically handles cleanup:
126
159
 
127
160
  ```typescript
128
- import { useProvidePageContext, createContext } from '@grafana/assistant';
161
+ import { useProvidePageContext, createAssistantContextItem } from '@grafana/assistant';
129
162
 
130
163
  function DashboardComponent() {
131
- const dashboardContext = createContext('structured', {
164
+ const dashboardContext = createAssistantContextItem('structured', {
132
165
  data: {
133
166
  name: 'Dashboard Context',
134
167
  pageType: 'dashboard'
@@ -142,7 +175,7 @@ function DashboardComponent() {
142
175
  const handlePanelSelect = (panelId: string) => {
143
176
  setContext([
144
177
  dashboardContext,
145
- createContext('structured', {
178
+ createAssistantContextItem('structured', {
146
179
  data: {
147
180
  name: 'Panel Context',
148
181
  selectedPanel: panelId
@@ -173,22 +206,20 @@ function MyComponent() {
173
206
 
174
207
  ### Creating Context Items
175
208
 
176
- The `createContext` function allows you to create structured context items that provide the assistant with additional information about your Grafana resources.
209
+ The `createAssistantContextItem` function allows you to create structured context items that provide the assistant with additional information about your Grafana resources.
177
210
 
178
211
  ```typescript
179
- import { createContext } from '@grafana/assistant';
212
+ import { createAssistantContextItem } from '@grafana/assistant';
180
213
 
181
214
  // Create a datasource context
182
- const datasourceContext = createContext('datasource', {
183
- datasourceName: 'Production Prometheus',
215
+ const datasourceContext = createAssistantContextItem('datasource', {
184
216
  datasourceUid: 'prom-123',
185
- datasourceType: 'prometheus',
186
217
  title: 'Main Datasource', // Optional custom title
187
218
  icon: 'database' // Optional custom icon
188
219
  });
189
220
 
190
221
  // Create a dashboard context
191
- const dashboardContext = createContext('dashboard', {
222
+ const dashboardContext = createAssistantContextItem('dashboard', {
192
223
  dashboardUid: 'dash-456',
193
224
  dashboardTitle: 'Application Overview',
194
225
  folderUid: 'folder-789',
@@ -196,14 +227,14 @@ const dashboardContext = createContext('dashboard', {
196
227
  });
197
228
 
198
229
  // Create a label context
199
- const labelContext = createContext('label_name', {
230
+ const labelContext = createAssistantContextItem('label_name', {
200
231
  datasourceUid: 'prom-123',
201
232
  datasourceType: 'prometheus',
202
233
  labelName: 'service'
203
234
  });
204
235
 
205
236
  // Create a label value context
206
- const labelValueContext = createContext('label_value', {
237
+ const labelValueContext = createAssistantContextItem('label_value', {
207
238
  datasourceUid: 'prom-123',
208
239
  datasourceType: 'prometheus',
209
240
  labelName: 'service',
@@ -211,13 +242,13 @@ const labelValueContext = createContext('label_value', {
211
242
  });
212
243
 
213
244
  // Create a folder context
214
- const folderContext = createContext('dashboard_folder', {
245
+ const folderContext = createAssistantContextItem('dashboard_folder', {
215
246
  folderUid: 'folder-789',
216
247
  folderTitle: 'Production Dashboards'
217
248
  });
218
249
 
219
250
  // Create structured data context
220
- const structuredContext = createContext('structured', {
251
+ const structuredContext = createAssistantContextItem('structured', {
221
252
  data: {
222
253
  name: 'Custom Data',
223
254
  metrics: ['cpu_usage', 'memory_usage'],
@@ -226,10 +257,172 @@ const structuredContext = createContext('structured', {
226
257
  });
227
258
 
228
259
  // Create generic context
229
- const genericContext = createContext('unknown', {
260
+ const genericContext = createAssistantContextItem('unknown', {
230
261
  id: 'my-context',
231
262
  text: 'Some additional context information'
232
263
  });
264
+
265
+ // Create component context for custom React components
266
+ const componentContext = createAssistantContextItem('component', {
267
+ components: {
268
+ MyCustomComponent: MyCustomComponentImplementation,
269
+ AnotherComponent: AnotherComponentImplementation,
270
+ },
271
+ prompt: `
272
+ - When mentioning specific entities, use the your_app_MyCustomComponent with the syntax: <your_app_MyCustomComponent prop1={'value1'} prop2={'value2'} />
273
+ - Custom components must never be wrapped in code blocks (backticks \` or \`\`\`).
274
+ - Always provide all required props when using custom components.
275
+ `,
276
+ namespace: 'your_app', // Optional: Namespace for your components (defaults to 'components')
277
+ });
278
+
279
+ // Create hidden context (useful for system instructions)
280
+ const hiddenInstructions = createAssistantContextItem('structured', {
281
+ hidden: true, // Won't be shown in UI pills but will be sent to the assistant
282
+ title: 'Page-specific instructions',
283
+ data: {
284
+ instructions: 'Always provide step-by-step explanations',
285
+ context: 'This is a complex system with multiple dependencies'
286
+ }
287
+ });
288
+ ```
289
+
290
+ ### Registering Custom Components for Assistant Usage
291
+
292
+ The `component` context type allows you to register custom React components that the assistant can use in its responses. This is particularly useful for rendering domain-specific UI elements that enhance the user experience.
293
+
294
+ > **⚠️ Important:** Components must be approved by #grafana-assistant before usage. Please reach out to the Grafana Assistant team for review and approval of your custom components before implementing them in production.
295
+
296
+ #### Method 1: Using provideComponents (Recommended)
297
+
298
+ ```typescript
299
+ import { provideComponents } from '@grafana/assistant';
300
+ import MyEntityMention from 'components/MyEntityMentionComponent';
301
+ import MyCustomChart from 'components/MyCustomChartComponent';
302
+
303
+ /**
304
+ * Configure the assistant context for your app plugin.
305
+ * This sets up custom components that will be available to the Grafana Assistant
306
+ * when users are on any page matching the provided pattern.
307
+ */
308
+ export function configureAssistantContext() {
309
+ provideComponents(
310
+ `
311
+ - When mentioning an entity in text, always use the your_app_MyEntityMention component: <your_app_MyEntityMention name={'entity name here'} type={'entity type here'} />
312
+ - For displaying charts, use the your_app_MyCustomChart component: <your_app_MyCustomChart data={chartData} title={'Chart Title'} />
313
+ - Custom components must never be wrapped in code blocks (backticks \` or \`\`\`).
314
+ `,
315
+ 'your_app', // namespace
316
+ {
317
+ MyEntityMention,
318
+ MyCustomChart,
319
+ },
320
+ /.*/ // matches all pages
321
+ );
322
+ }
323
+ ```
324
+
325
+ #### Method 2: Using createAssistantContextItem with providePageContext
326
+
327
+ ```typescript
328
+ import { createAssistantContextItem, providePageContext } from '@grafana/assistant';
329
+ import MyEntityMention from 'components/MyEntityMentionComponent';
330
+ import MyCustomChart from 'components/MyCustomChartComponent';
331
+
332
+ export function configureAssistantContext() {
333
+ providePageContext(/.*/, [
334
+ createAssistantContextItem('component', {
335
+ components: {
336
+ MyEntityMention,
337
+ MyCustomChart,
338
+ },
339
+ prompt: `
340
+ - When mentioning an entity in text, always use the your_app_MyEntityMention component: <your_app_MyEntityMention name={'entity name here'} type={'entity type here'} />
341
+ - For displaying charts, use the your_app_MyCustomChart component: <your_app_MyCustomChart data={chartData} title={'Chart Title'} />
342
+ - Custom components must never be wrapped in code blocks (backticks \` or \`\`\`).
343
+ `,
344
+ namespace: 'your_app', // Optional: defaults to 'components' if not provided
345
+ }),
346
+ ]);
347
+ }
348
+ ```
349
+
350
+ **Key Points for Component Context:**
351
+
352
+ - **Approval Required**: ⚠️ Components must be approved by #grafana-assistant before usage
353
+ - **Components**: A record of component names to their React component implementations
354
+ - **Prompt**: Instructions for the assistant on how and when to use these components
355
+ - **Namespace**: A unique identifier for your app's components (e.g., 'your_app', 'datasource'). Optional - defaults to 'components' if not provided
356
+ - **Component Usage**: Components are referenced in assistant responses as `<namespace_ComponentName prop={'value'} />` (note the underscore format)
357
+ - **No Code Blocks**: Custom components should never be wrapped in markdown code blocks
358
+
359
+ **Example Component Implementation:**
360
+ ```typescript
361
+ interface MyEntityMentionProps {
362
+ name: string;
363
+ type: string;
364
+ env?: string;
365
+ site?: string;
366
+ namespace?: string;
367
+ properties?: string;
368
+ }
369
+
370
+ const MyEntityMention: React.FC<MyEntityMentionProps> = ({ name, type, env, site, namespace, properties }) => {
371
+ return (
372
+ <span
373
+ className="entity-mention"
374
+ data-entity-type={type}
375
+ title={`${type}: ${name}`}
376
+ >
377
+ {name}
378
+ </span>
379
+ );
380
+ };
381
+
382
+ export default MyEntityMention;
383
+ ```
384
+
385
+ ### Using Hidden Context for System Instructions
386
+
387
+ The `hidden` parameter allows you to provide context to the assistant without showing it in the UI pills. This is particularly useful for:
388
+
389
+ - **System instructions**: Provide behavioral guidelines specific to certain pages
390
+ - **Metadata**: Include technical details that might confuse users if shown
391
+ - **Contextual rules**: Add page-specific rules without cluttering the interface
392
+
393
+ Example use cases:
394
+
395
+ ```typescript
396
+ // Provide exploration-specific guidelines
397
+ providePageContext('/explore', [
398
+ createAssistantContextItem('structured', {
399
+ hidden: true,
400
+ title: 'Explore Page Guidelines',
401
+ data: {
402
+ instructions: [
403
+ 'Always validate time ranges before running queries',
404
+ 'Suggest using recording rules for expensive queries',
405
+ 'Warn about queries that might impact performance'
406
+ ],
407
+ queryLimits: {
408
+ maxTimeRange: '24h',
409
+ suggestedSampleInterval: '1m'
410
+ }
411
+ }
412
+ })
413
+ ]);
414
+
415
+ // Add dashboard-specific context
416
+ providePageContext('/d/*', [
417
+ createAssistantContextItem('structured', {
418
+ hidden: true,
419
+ title: 'Dashboard Instructions',
420
+ data: {
421
+ bestPractices: 'Encourage users to use template variables for flexibility',
422
+ performance: 'Suggest panel caching for slow queries'
423
+ }
424
+ })
425
+ ]);
233
426
  ```
234
427
 
235
428
  ### Exposing Functions to the Assistant
@@ -263,6 +456,52 @@ export const getExtensionConfigs = () => [
263
456
  ];
264
457
  ```
265
458
 
459
+ ### Using the OpenAssistantButton Component
460
+
461
+ The `OpenAssistantButton` is a pre-built Button component that provides an easy way to add assistant functionality to your UI with a single button click. It automatically checks availability and hides itself if the Assistant is not available.
462
+
463
+ ```typescript
464
+ import { OpenAssistantButton, createAssistantContextItem } from '@grafana/assistant';
465
+
466
+ function MyDashboard() {
467
+ const dashboardContext = createAssistantContextItem('dashboard', {
468
+ dashboardUid: 'dashboard-123',
469
+ dashboardTitle: 'CPU Metrics Dashboard'
470
+ });
471
+
472
+ return (
473
+ <div>
474
+ <h1>Dashboard</h1>
475
+
476
+ {/* Basic usage */}
477
+ <OpenAssistantButton
478
+ prompt="Help me analyze the CPU usage trends in this dashboard"
479
+ context={[dashboardContext]}
480
+ origin="grafana/dashboard-menu"
481
+ />
482
+
483
+ {/* Icon-only button */}
484
+ <OpenAssistantButton
485
+ prompt="Show me optimization suggestions"
486
+ iconOnlyButton={true}
487
+ name="Get AI suggestions"
488
+ size="md"
489
+ origin="grafana-datasources/loki/query-editor"
490
+ />
491
+
492
+ {/* Button without auto-send */}
493
+ <OpenAssistantButton
494
+ prompt="What patterns do you see in the data?"
495
+ autoSend={false}
496
+ name="Ask Assistant"
497
+ size="lg"
498
+ origin="grafana/panel-viewer"
499
+ />
500
+ </div>
501
+ );
502
+ }
503
+ ```
504
+
266
505
  ## API Reference
267
506
 
268
507
  ### React Hooks
@@ -292,6 +531,47 @@ A React hook for providing page context that automatically cleans up on unmount.
292
531
 
293
532
  **Returns:** A setter function to update the context
294
533
 
534
+ #### `usePageComponents(): Record<string, ComponentImplementation>`
535
+
536
+ A React hook that provides all components available for the current page. This hook automatically updates when the URL changes or when component registrations change.
537
+
538
+ **Returns:** Object containing all components available for the current page, keyed by `namespace_componentName` format.
539
+
540
+ **Example:**
541
+ ```typescript
542
+ import { usePageComponents } from '@grafana/assistant';
543
+
544
+ function MyAssistantComponent() {
545
+ const components = usePageComponents();
546
+
547
+ // Access components registered with namespace 'myapp' and component name 'EntityMention'
548
+ const EntityMentionComponent = components['myapp_EntityMention'];
549
+
550
+ return (
551
+ <div>
552
+ Available components: {Object.keys(components).join(', ')}
553
+ </div>
554
+ );
555
+ }
556
+ ```
557
+
558
+ ### React Components
559
+
560
+ #### `<OpenAssistantButton />`
561
+
562
+ A pre-built React component that renders a button to open the Grafana Assistant with configurable prompt and context.
563
+
564
+ **Parameters:**
565
+ - `prompt: string` - **Required** The initial prompt to display in the assistant
566
+ - `origin: string` - **Required** Origin of the request that opened the assistant. Should be structured using forward slashes with the first part as a namespace. Examples: 'grafana-datasources/prometheus/query-builder', 'grafana-slo-app/slo-editor-overview'
567
+ - `context?: ChatContextItem[]` - Optional context items created with `createAssistantContextItem`
568
+ - `autoSend?: boolean` - Whether to automatically send the initial prompt (defaults to `true`)
569
+ - `title?: string` - Text to display on the button (defaults to `'Analyze with Assistant'`)
570
+ - `size?: 'xs' | 'sm' | 'md' | 'lg'` - Button size (defaults to `'sm'`)
571
+ - `iconOnlyButton?: boolean` - If `true`, renders as an icon-only button with tooltip (defaults to `false`)
572
+
573
+ **Returns:** JSX element or `null` if assistant is not available
574
+
295
575
  ### Availability Functions
296
576
 
297
577
  #### `isAssistantAvailable(): Observable<boolean>`
@@ -308,8 +588,10 @@ Opens the Grafana Assistant sidebar.
308
588
 
309
589
  **Parameters:**
310
590
  - `props: OpenAssistantProps` - Configuration object
591
+ - `origin: string` - Origin of the request that opened the assistant. Should be structured using forward slashes with the first part as a namespace. Examples: 'grafana-datasources/prometheus/query-builder', 'grafana-slo-app/slo-editor-overview'
311
592
  - `prompt?: string` - Optional initial prompt to display in the assistant
312
593
  - `context?: ChatContextItem[]` - Optional context items to provide additional information to the assistant
594
+ - `autoSend?: boolean` - Optional flag to automatically send the initial prompt
313
595
 
314
596
  #### `closeAssistant(): void`
315
597
 
@@ -317,7 +599,7 @@ Closes the Grafana Assistant sidebar.
317
599
 
318
600
  ### Context Functions
319
601
 
320
- #### `createContext<T>(type: T, params: ContextTypeParams<T>): ChatContextItem`
602
+ #### `createAssistantContextItem<T>(type: T, params: ContextTypeParams<T>): ChatContextItem`
321
603
 
322
604
  Creates a context item that can be passed to the assistant to provide additional information.
323
605
 
@@ -329,8 +611,10 @@ Creates a context item that can be passed to the assistant to provide additional
329
611
  - `'label_name'` - Label name context
330
612
  - `'label_value'` - Label value context
331
613
  - `'structured'` - Custom structured data context
614
+ - `'component'` - Custom React components context
332
615
  - `'unknown'` - Generic text context
333
- - `params` - Parameters specific to the context type (see Context Types section)
616
+ - `params` - Parameters specific to the context type (see Context Types section). All context types support:
617
+ - `hidden?: boolean` - If true, the context item will not be shown in the UI pills but will still be sent to the assistant. This is useful for providing system instructions, behavioral guidelines, or other metadata that shouldn't clutter the user interface.
334
618
 
335
619
  **Returns:** A `ChatContextItem` that can be passed to `openAssistant`
336
620
 
@@ -362,6 +646,50 @@ setDashboardContext([...newContext]);
362
646
  setDashboardContext.unregister();
363
647
  ```
364
648
 
649
+ #### `provideComponents(prompt: string, namespace: string, components: Record<string, ComponentImplementation>, urlPattern?: string | RegExp): ((context: ChatContextItem[]) => void) & { unregister: () => void }`
650
+
651
+ A simplified function for providing components to the assistant. This is a convenience wrapper around `providePageContext` specifically for registering components.
652
+
653
+ **Parameters:**
654
+ - `prompt` - Instructions for the assistant on how and when to use these components
655
+ - `namespace` - A unique identifier for your app's components (e.g., 'myapp', 'datasource')
656
+ - `components` - A record of component names to their React component implementations
657
+ - `urlPattern` - Optional URL pattern to match against page URLs (defaults to `/.*/` - matches all pages)
658
+
659
+ **Returns:** A setter function to update the context, with an `unregister` method attached for cleanup
660
+
661
+ **Example:**
662
+ ```typescript
663
+ import { provideComponents } from '@grafana/assistant';
664
+ import MyEntityMention from './components/MyEntityMention';
665
+ import MyCustomChart from './components/MyCustomChart';
666
+
667
+ // Register components for all pages
668
+ const setComponents = provideComponents(
669
+ `
670
+ - When mentioning entities, use the myapp_MyEntityMention component: <myapp_MyEntityMention name={'entity-name'} type={'entity-type'} />
671
+ - For charts, use the myapp_MyCustomChart component: <myapp_MyCustomChart data={chartData} title={'Chart Title'} />
672
+ - Custom components must never be wrapped in code blocks.
673
+ `,
674
+ 'myapp',
675
+ {
676
+ MyEntityMention,
677
+ MyCustomChart,
678
+ }
679
+ );
680
+
681
+ // Register components only for dashboard pages
682
+ const setDashboardComponents = provideComponents(
683
+ 'Use components to enhance dashboard analysis.',
684
+ 'dashboard',
685
+ { MyEntityMention },
686
+ '/d/*'
687
+ );
688
+
689
+ // Cleanup when done
690
+ setComponents.unregister();
691
+ ```
692
+
365
693
  ### Questions System
366
694
 
367
695
  The questions system allows external parties to provide sample prompts with optional context for specific pages. It reuses the existing page context infrastructure but presents a simpler interface focused on questions.
@@ -382,12 +710,12 @@ Registers questions for specific pages based on URL patterns. Returns a setter f
382
710
  const setQuestions = provideQuestions("/d/*", [
383
711
  {
384
712
  prompt: "What metrics are available in this dashboard?",
385
- context: [], // Optional context items created with `createContext`
713
+ context: [], // Optional context items created with `createAssistantContextItem`
386
714
  },
387
715
  {
388
716
  prompt: "How can I optimize the queries in this dashboard?",
389
717
  context: [
390
- createContext("dashboard", {
718
+ createAssistantContextItem("dashboard", {
391
719
  dashboardUid: 'dashboard-uid',
392
720
  dashboardTitle: 'System Overview',
393
721
  folderUid: 'folder-uid',
@@ -470,13 +798,15 @@ function AssistantComponent() {
470
798
  type OpenAssistantProps = {
471
799
  prompt?: string;
472
800
  context?: ChatContextItem[];
801
+ autoSend?: boolean;
473
802
  };
474
803
  ```
475
804
 
476
805
  Configuration object for opening the assistant.
477
806
 
478
807
  - `prompt` - Optional initial prompt to display
479
- - `context` - Optional context items to provide
808
+ - `context` - Optional context items to provide
809
+ - `autoSend` - Optional flag to automatically send the initial prompt
480
810
 
481
811
  #### `ChatContextItem`
482
812
 
@@ -534,11 +864,10 @@ Represents a registered questions mapping.
534
864
 
535
865
  ```typescript
536
866
  interface CreateDatasourceContextParams {
537
- datasourceName: string;
538
867
  datasourceUid: string;
539
- datasourceType: string;
540
868
  title?: string;
541
869
  icon?: IconName;
870
+ hidden?: boolean; // If true, the context item will not be shown in the context pills
542
871
  }
543
872
  ```
544
873
 
@@ -552,6 +881,7 @@ interface CreateDashboardContextParams {
552
881
  folderTitle?: string;
553
882
  title?: string;
554
883
  icon?: IconName;
884
+ hidden?: boolean; // If true, the context item will not be shown in the context pills
555
885
  }
556
886
  ```
557
887
 
@@ -563,6 +893,7 @@ interface CreateFolderContextParams {
563
893
  folderTitle: string;
564
894
  title?: string;
565
895
  icon?: IconName;
896
+ hidden?: boolean; // If true, the context item will not be shown in the context pills
566
897
  }
567
898
  ```
568
899
 
@@ -575,6 +906,7 @@ interface CreateLabelNameContextParams {
575
906
  labelName: string;
576
907
  title?: string;
577
908
  icon?: IconName;
909
+ hidden?: boolean; // If true, the context item will not be shown in the context pills
578
910
  }
579
911
  ```
580
912
 
@@ -588,6 +920,7 @@ interface CreateLabelValueContextParams {
588
920
  labelValue: string;
589
921
  title?: string;
590
922
  icon?: IconName;
923
+ hidden?: boolean; // If true, the context item will not be shown in the context pills
591
924
  }
592
925
  ```
593
926
 
@@ -598,6 +931,20 @@ interface StructuredNodeDataParams {
598
931
  data: Record<string, any>;
599
932
  title?: string;
600
933
  icon?: IconName;
934
+ hidden?: boolean; // If true, the context item will not be shown in the context pills
935
+ }
936
+ ```
937
+
938
+ #### Component Context Parameters
939
+
940
+ ```typescript
941
+ interface CreateComponentContextParams {
942
+ components: Record<string, React.ComponentType<any>>;
943
+ prompt: string;
944
+ namespace?: string; // Optional: defaults to 'components' if not provided
945
+ title?: string;
946
+ icon?: IconName;
947
+ hidden?: boolean; // If true, the context item will not be shown in the context pills
601
948
  }
602
949
  ```
603
950
 
@@ -609,6 +956,7 @@ interface NodeDataParams {
609
956
  text?: string;
610
957
  title?: string;
611
958
  icon?: IconName;
959
+ hidden?: boolean; // If true, the context item will not be shown in the context pills
612
960
  }
613
961
  ```
614
962
 
@@ -689,11 +1037,13 @@ export type LabelNameNodeData;
689
1037
  export type LabelValueNodeData;
690
1038
  export type StructuredNodeData;
691
1039
  export type TreeNode;
1040
+ export type ItemDataType;
692
1041
 
693
- // Enums
694
- export enum ItemDataType;
1042
+ // Component types
1043
+ export type ComponentImplementation;
1044
+ export type NamedComponents;
695
1045
  ```
696
1046
 
697
1047
  ## License
698
1048
 
699
- Apache-2.0
1049
+ Apache-2.0
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+ import { ChatContextItem } from '../context/types';
3
+ import { OpenAssistantProps } from '../sidebar';
4
+ export interface OpenAssistantButtonProps {
5
+ /** Prompt to pass to the openAssistant function. */
6
+ prompt: string;
7
+ /** Origin of the request that opened the assistant. This is used to track the source of the request. Should be a structured string using forward slashes, with the first part as a namespace. Examples: 'grafana-datasources/prometheus/query-builder', 'grafana-slo-app/slo-editor-overview', 'grafana/trace-view-analyzer`. */
8
+ origin: string;
9
+ /** Context to pass to the openAssistant function. Optional, defaults to undefined. Created with `createAssistantContextItem`. */
10
+ context?: ChatContextItem[];
11
+ /** Whether to automatically send the prompt. Optional, defaults to true. */
12
+ autoSend?: boolean;
13
+ /** Text to display on the button. Optional, defaults to 'Analyze with Assistant' */
14
+ title?: string;
15
+ /** Button size, defaults to sm */
16
+ size?: 'xs' | 'sm' | 'md' | 'lg';
17
+ /** If true, the button will be Assistant icon only with name as title. Defaults to false. */
18
+ iconOnlyButton?: boolean;
19
+ }
20
+ /**
21
+ * A button component that opens the Grafana Assistant with configurable prompt and context.
22
+ */
23
+ export declare function OpenAssistantButton(props: OpenAssistantButtonProps): React.JSX.Element | null;
24
+ /**
25
+ * Presentational component separated from OpenAssistantButton to avoid hook dependencies in Storybook.
26
+ * It is not exported for users of the package.
27
+ */
28
+ export declare function OpenAssistantButtonView({ prompt, origin, context, autoSend, title, size, iconOnlyButton, openAssistant, }: OpenAssistantButtonProps & {
29
+ openAssistant: (props: OpenAssistantProps) => void;
30
+ }): React.JSX.Element;
@@ -0,0 +1,9 @@
1
+ import type { Meta, StoryObj } from '@storybook/react';
2
+ import { OpenAssistantButtonView } from './OpenAssistantButton';
3
+ declare const meta: Meta<typeof OpenAssistantButtonView>;
4
+ export default meta;
5
+ type Story = StoryObj<typeof OpenAssistantButtonView>;
6
+ export declare const Default: Story;
7
+ export declare const IconOnly: Story;
8
+ export declare const LargeButton: Story;
9
+ export declare const CustomTitle: Story;
@@ -0,0 +1 @@
1
+ export { OpenAssistantButton, type OpenAssistantButtonProps } from './OpenAssistantButton';
@@ -2,6 +2,7 @@ import { IconName } from '@grafana/ui';
2
2
  import { type ContextItemData } from './types';
3
3
  export interface BaseParams {
4
4
  title?: string;
5
+ hidden?: boolean;
5
6
  img?: string;
6
7
  icon?: IconName;
7
8
  }
@@ -9,9 +10,6 @@ export interface NodeDataParams extends BaseParams {
9
10
  id: string;
10
11
  text?: string;
11
12
  }
12
- export interface StructuredNodeDataParams extends BaseParams {
13
- data: Record<string, any>;
14
- }
15
13
  export declare class NodeData {
16
14
  params: NodeDataParams;
17
15
  id: string;
@@ -19,6 +17,9 @@ export declare class NodeData {
19
17
  constructor(params: NodeDataParams);
20
18
  formatForLLM(codeElementIds?: string[]): ContextItemData;
21
19
  }
20
+ export interface StructuredNodeDataParams extends BaseParams {
21
+ data: Record<string, any>;
22
+ }
22
23
  export declare class StructuredNodeData {
23
24
  params: StructuredNodeDataParams;
24
25
  id: string;
@@ -1,22 +1,5 @@
1
- import { NodeDataParams, StructuredNodeDataParams } from './base';
2
- import { CreateDashboardContextParams, CreateFolderContextParams } from './dashboard';
3
- import { CreateDatasourceContextParams } from './datasource';
4
- import { CreateLabelNameContextParams, CreateLabelValueContextParams } from './label';
5
- import { ChatContextItem, ItemDataType } from './types';
6
- type ContextTypeMap = {
7
- [ItemDataType.Datasource]: CreateDatasourceContextParams;
8
- [ItemDataType.LabelName]: CreateLabelNameContextParams;
9
- [ItemDataType.LabelValue]: CreateLabelValueContextParams;
10
- [ItemDataType.Dashboard]: CreateDashboardContextParams;
11
- [ItemDataType.DashboardFolder]: CreateFolderContextParams;
12
- [ItemDataType.Structured]: StructuredNodeDataParams;
13
- [ItemDataType.Unknown]: NodeDataParams;
14
- };
15
- /**
16
- * @deprecated This function is deprecated and will be removed in a future release because it collides with React's context naming.
17
- * Use createContextItem instead.
18
- */
19
- export declare function createContext<T extends keyof ContextTypeMap>(type: T, params: ContextTypeMap[T]): ChatContextItem;
1
+ import { ContextTypeRegistry } from './factory';
2
+ import { ChatContextItem } from './types';
20
3
  /**
21
4
  * Creates a new chat context item that can be added to conversations.
22
5
  *
@@ -40,16 +23,14 @@ export declare function createContext<T extends keyof ContextTypeMap>(type: T, p
40
23
  * // Create a context that will be passed into the function triggering an assistant open
41
24
  * openAssistant({
42
25
  * ...
26
+ * origin: 'my-feature',
43
27
  * context: [
44
- * createAssistantContext(ItemDataType.Datasource, {
28
+ * createAssistantContextItem('datasource', {
45
29
  * datasourceUid: datasource.uid,
46
- * datasourceName: datasource.name,
47
- * datasourceType: datasource.type,
48
30
  * img: datasource.meta?.info?.logos?.small,
49
31
  * }),
50
32
  * ],
51
33
  * });
52
34
  * ```
53
35
  */
54
- export declare function createContextItem<T extends keyof ContextTypeMap>(type: T, params: ContextTypeMap[T]): ChatContextItem;
55
- export {};
36
+ export declare function createAssistantContextItem<T extends keyof ContextTypeRegistry>(type: T, params: ContextTypeRegistry[T]['params']): ChatContextItem;
@@ -0,0 +1,38 @@
1
+ import { ComponentType } from 'react';
2
+ import { BaseParams, NodeData } from './base';
3
+ import { type ContextItemData } from './types';
4
+ export type ComponentImplementation = ComponentType<any>;
5
+ export type NamedComponents = Record<string, ComponentImplementation>;
6
+ /**
7
+ * Type used to create a component context item.
8
+ */
9
+ export interface CreateComponentContextParams extends BaseParams {
10
+ components: Record<string, ComponentType<any>>;
11
+ prompt: string;
12
+ namespace?: string;
13
+ }
14
+ export declare class ComponentNodeData extends NodeData {
15
+ components: Record<string, ComponentType<any>>;
16
+ prompt: string;
17
+ namespace: string;
18
+ constructor(params: CreateComponentContextParams);
19
+ formatForLLM(codeElementIds?: string[]): ContextItemData;
20
+ }
21
+ /**
22
+ * React hook that provides all components available for the current page.
23
+ * This hook automatically updates when the URL changes or when component registrations change.
24
+ *
25
+ * @returns Object containing all components available for the current page, keyed by namespace.componentName
26
+ */
27
+ export declare function usePageComponents(): Record<string, ComponentImplementation>;
28
+ /**
29
+ * Provide components to the assistant.
30
+ *
31
+ * @param prompt - The prompt to use for the components.
32
+ * @param namespace - The namespace to use for the components.
33
+ * @param components - The components to provide.
34
+ * @param urlPattern - The URL pattern to match for the components.
35
+ */
36
+ export declare function provideComponents(prompt: string, namespace: string, components: Record<string, ComponentImplementation>, urlPattern?: string | RegExp): ((context: import("./types").ChatContextItem[]) => void) & {
37
+ unregister: () => void;
38
+ };
@@ -15,7 +15,6 @@ export declare class DashboardNodeData extends NodeData {
15
15
  dashboardTitle: string;
16
16
  folderUid?: string;
17
17
  folderTitle?: string;
18
- text: string;
19
18
  constructor(params: CreateDashboardContextParams);
20
19
  formatForLLM(codeElementIds?: string[]): ContextItemData;
21
20
  }
@@ -1,15 +1,19 @@
1
1
  import { BaseParams, NodeData } from './base';
2
+ import { DatasourceMeta } from './factory';
2
3
  import { type ContextItemData } from './types';
4
+ /**
5
+ * Type used to create a datasource context item.
6
+ *
7
+ * All required attributes will be inferred from the datasources uid.
8
+ */
3
9
  export interface CreateDatasourceContextParams extends BaseParams {
4
- datasourceName: string;
5
10
  datasourceUid: string;
6
- datasourceType: string;
7
11
  }
8
12
  export declare class DatasourceNodeData extends NodeData {
9
13
  datasourceUid: string;
10
14
  datasourceType: string;
11
15
  datasourceName: string;
12
- text: string;
13
- constructor(params: CreateDatasourceContextParams);
16
+ img?: string;
17
+ constructor(params: CreateDatasourceContextParams & DatasourceMeta);
14
18
  formatForLLM(codeElementIds?: string[]): ContextItemData;
15
19
  }
@@ -1,39 +1,51 @@
1
1
  import { NodeData, NodeDataParams, StructuredNodeData, StructuredNodeDataParams } from './base';
2
+ import { ComponentNodeData, type CreateComponentContextParams } from './component';
2
3
  import { DashboardNodeData, FolderNodeData, type CreateDashboardContextParams, type CreateFolderContextParams } from './dashboard';
3
4
  import { DatasourceNodeData, type CreateDatasourceContextParams } from './datasource';
4
5
  import { LabelNameNodeData, LabelValueNodeData, type CreateLabelNameContextParams, type CreateLabelValueContextParams } from './label';
5
- type ContextTypeMap = {
6
+ /**
7
+ * registry to handle the type mappings between ItemData type, params and node data
8
+ */
9
+ export type ContextTypeRegistry = {
6
10
  datasource: {
7
11
  params: CreateDatasourceContextParams;
8
- return: DatasourceNodeData;
12
+ node: DatasourceNodeData;
9
13
  };
10
14
  label_name: {
11
15
  params: CreateLabelNameContextParams;
12
- return: LabelNameNodeData;
16
+ node: LabelNameNodeData;
13
17
  };
14
18
  label_value: {
15
19
  params: CreateLabelValueContextParams;
16
- return: LabelValueNodeData;
20
+ node: LabelValueNodeData;
17
21
  };
18
22
  dashboard: {
19
23
  params: CreateDashboardContextParams;
20
- return: DashboardNodeData;
24
+ node: DashboardNodeData;
21
25
  };
22
26
  dashboard_folder: {
23
27
  params: CreateFolderContextParams;
24
- return: FolderNodeData;
28
+ node: FolderNodeData;
25
29
  };
26
30
  structured: {
27
31
  params: StructuredNodeDataParams;
28
- return: StructuredNodeData;
32
+ node: StructuredNodeData;
33
+ };
34
+ component: {
35
+ params: CreateComponentContextParams;
36
+ node: ComponentNodeData;
29
37
  };
30
38
  unknown: {
31
39
  params: NodeDataParams;
32
- return: NodeData;
40
+ node: NodeData;
33
41
  };
34
42
  };
43
+ export type DatasourceMeta = {
44
+ datasourceType: string;
45
+ datasourceName: string;
46
+ img?: string;
47
+ };
35
48
  /**
36
49
  * Creates context nodes based on type with full type safety using generics
37
50
  */
38
- export declare function createContextByType<T extends keyof ContextTypeMap>(type: T, params: ContextTypeMap[T]['params']): ContextTypeMap[T]['return'];
39
- export {};
51
+ export declare function createContextByType<T extends keyof ContextTypeRegistry>(type: T, params: ContextTypeRegistry[T]['params']): ContextTypeRegistry[T]['node'];
@@ -1,5 +1,6 @@
1
1
  export * from './base';
2
2
  export * from './chat';
3
+ export * from './component';
3
4
  export * from './dashboard';
4
5
  export * from './datasource';
5
6
  export * from './factory';
@@ -1,8 +1,8 @@
1
1
  import { BaseParams, NodeData } from './base';
2
+ import { DatasourceMeta } from './factory';
2
3
  import { type ContextItemData } from './types';
3
4
  export interface CreateLabelNameContextParams extends BaseParams {
4
5
  datasourceUid: string;
5
- datasourceType: string;
6
6
  labelName: string;
7
7
  }
8
8
  export interface CreateLabelValueContextParams extends CreateLabelNameContextParams {
@@ -11,17 +11,19 @@ export interface CreateLabelValueContextParams extends CreateLabelNameContextPar
11
11
  export declare class LabelNameNodeData extends NodeData {
12
12
  datasourceUid: string;
13
13
  datasourceType: string;
14
+ datasourceName: string;
14
15
  labelName: string;
15
- text: string;
16
- constructor(params: CreateLabelNameContextParams);
16
+ img?: string;
17
+ constructor(params: CreateLabelNameContextParams & DatasourceMeta);
17
18
  formatForLLM(codeElementIds?: string[]): ContextItemData;
18
19
  }
19
20
  export declare class LabelValueNodeData extends NodeData {
20
21
  datasourceUid: string;
21
22
  datasourceType: string;
23
+ datasourceName: string;
22
24
  labelName: string;
23
25
  labelValue: string;
24
- text: string;
25
- constructor(params: CreateLabelValueContextParams);
26
+ img?: string;
27
+ constructor(params: CreateLabelValueContextParams & DatasourceMeta);
26
28
  formatForLLM(codeElementIds?: string[]): ContextItemData;
27
29
  }
@@ -28,4 +28,5 @@ export declare function providePageContext(urlPattern: string | RegExp, initialC
28
28
  export declare function useProvidePageContext(urlPattern: string | RegExp, initialContext?: ChatContextItem[]): (context: ChatContextItem[]) => void;
29
29
  export declare function usePageContext(options?: {
30
30
  allowQuestions: boolean;
31
+ allowComponents: boolean;
31
32
  }): ChatContextItem[];
@@ -1,19 +1,12 @@
1
1
  import { IconName } from '@grafana/ui';
2
+ import { ComponentType } from 'react';
2
3
  export interface BaseItemData {
3
4
  name: string;
4
5
  text: string;
5
6
  }
6
7
  export interface UnknownItemData extends BaseItemData {
7
8
  }
8
- export declare enum ItemDataType {
9
- Unknown = "unknown",
10
- Datasource = "datasource",
11
- LabelName = "label_name",
12
- LabelValue = "label_value",
13
- Dashboard = "dashboard",
14
- DashboardFolder = "dashboard_folder",
15
- Structured = "structured"
16
- }
9
+ export type ItemDataType = 'unknown' | 'datasource' | 'label_name' | 'label_value' | 'dashboard' | 'dashboard_folder' | 'structured' | 'component';
17
10
  export interface ContextItemData {
18
11
  type: ItemDataType;
19
12
  codeElementIds?: string[];
@@ -33,11 +26,14 @@ export interface TreeNode {
33
26
  export interface DatasourceItemData extends BaseItemData {
34
27
  uid: string;
35
28
  type: string;
29
+ img?: string;
36
30
  }
37
31
  export interface LabelNameItemData extends BaseItemData {
38
32
  datasourceUid: string;
39
33
  datasourceType: string;
34
+ datasourceName: string;
40
35
  labelName: string;
36
+ img?: string;
41
37
  }
42
38
  export interface LabelValueItemData extends LabelNameItemData {
43
39
  labelValue: string;
@@ -52,6 +48,11 @@ export interface FolderItemData extends BaseItemData {
52
48
  folderUid: string;
53
49
  folderTitle: string;
54
50
  }
51
+ export interface ComponentItemData extends BaseItemData {
52
+ components: Record<string, ComponentType<any>>;
53
+ prompt: string;
54
+ namespace: string;
55
+ }
55
56
  export interface ChatContextItem {
56
57
  node: TreeNode;
57
58
  occurrences: string[];
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- export { createContext, createContextItem, ChatContextItem, DashboardNodeData, DatasourceNodeData, FolderNodeData, ItemDataType, LabelNameNodeData, LabelValueNodeData, StructuredNodeData, TreeNode, providePageContext, useProvidePageContext, PageContextRegistration, usePageContext, provideQuestions, useProvideQuestions, useQuestions, Question, QuestionRegistration, } from './context/index';
1
+ export { createAssistantContextItem, ChatContextItem, ComponentNodeData, DashboardNodeData, DatasourceNodeData, FolderNodeData, ItemDataType, LabelNameNodeData, LabelValueNodeData, StructuredNodeData, TreeNode, providePageContext, useProvidePageContext, PageContextRegistration, usePageContext, provideQuestions, useProvideQuestions, useQuestions, Question, QuestionRegistration, usePageComponents, provideComponents, ComponentImplementation, NamedComponents, } from './context/index';
2
2
  export * from './functions';
3
3
  export * from './hook';
4
4
  export * from './plugin';
5
5
  export * from './sidebar';
6
+ export * from './components';
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- (()=>{"use strict";var e,t={d:(e,a)=>{for(var n in a)t.o(a,n)&&!t.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:a[n]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},a={};function n(e){let t=5381;for(let a=0;a<e.length;a++)t=(t<<5)+t+e.charCodeAt(a);return(t>>>0).toString(16)}t.r(a),t.d(a,{CALLBACK_EXTENSION_POINT:()=>C,DashboardNodeData:()=>o,DatasourceNodeData:()=>d,FolderNodeData:()=>i,ItemDataType:()=>e,LabelNameNodeData:()=>l,LabelValueNodeData:()=>u,StructuredNodeData:()=>r,closeAssistant:()=>M,createContext:()=>f,createContextItem:()=>h,getExposeAssistantFunctionsConfig:()=>F,isAssistantAvailable:()=>V,newFunctionNamespace:()=>A,openAssistant:()=>k,providePageContext:()=>y,provideQuestions:()=>D,useAssistant:()=>R,usePageContext:()=>N,useProvidePageContext:()=>T,useProvideQuestions:()=>S,useQuestions:()=>I}),function(e){e.Unknown="unknown",e.Datasource="datasource",e.LabelName="label_name",e.LabelValue="label_value",e.Dashboard="dashboard",e.DashboardFolder="dashboard_folder",e.Structured="structured"}(e||(e={}));class s{constructor(e){this.params=e,this.text="",this.id=n(e.id)}formatForLLM(t){var a,n;return{type:e.Unknown,codeElementIds:t,data:{name:null!==(a=this.params.text)&&void 0!==a?a:"",text:null!==(n=this.params.text)&&void 0!==n?n:""}}}}class r{constructor(e){this.params=e,this.id=n(JSON.stringify(e.data))}formatForLLM(t){return{type:e.Structured,codeElementIds:t,data:this.params.data}}}class o extends s{constructor(e){super({...e,id:e.dashboardUid}),this.text="",this.dashboardUid=e.dashboardUid,this.dashboardTitle=e.dashboardTitle,this.folderUid=e.folderUid,this.folderTitle=e.folderTitle,this.text=e.dashboardTitle}formatForLLM(t){return{type:e.Dashboard,codeElementIds:t,data:{name:this.dashboardTitle,dashboardUid:this.dashboardUid,dashboardTitle:this.dashboardTitle,folderUid:this.folderUid,folderTitle:this.folderTitle,text:this.text}}}}class i extends s{constructor(e){super({...e,id:e.folderUid}),this.text="",this.folderUid=e.folderUid,this.folderTitle=e.folderTitle,this.text=e.folderTitle}formatForLLM(t){return{type:e.DashboardFolder,codeElementIds:t,data:{name:this.folderTitle,folderUid:this.folderUid,folderTitle:this.folderTitle,text:this.text}}}}class d extends s{constructor(e){super({...e,id:e.datasourceUid}),this.text="",this.datasourceUid=e.datasourceUid,this.datasourceType=e.datasourceType,this.datasourceName=e.datasourceName,this.text=e.datasourceName}formatForLLM(t){return{type:e.Datasource,codeElementIds:t,data:{name:this.datasourceName,uid:this.datasourceUid,type:this.datasourceType,text:this.text}}}}class l extends s{constructor(e){super({...e,id:`${e.datasourceUid}-${e.labelName}`}),this.text="",this.datasourceUid=e.datasourceUid,this.datasourceType=e.datasourceType,this.labelName=e.labelName,this.text=e.labelName}formatForLLM(t){return{type:e.LabelName,codeElementIds:t,data:{name:this.labelName,datasourceUid:this.datasourceUid,datasourceType:this.datasourceType,labelName:this.labelName,text:this.text}}}}class u extends s{constructor(e){super({...e,id:`${e.datasourceUid}-${e.labelName}-${e.labelValue}`}),this.text="",this.datasourceUid=e.datasourceUid,this.datasourceType=e.datasourceType,this.labelName=e.labelName,this.labelValue=e.labelValue,this.text=e.labelValue}formatForLLM(t){return{type:e.LabelValue,codeElementIds:t,data:{name:this.labelValue,datasourceUid:this.datasourceUid,datasourceType:this.datasourceType,labelName:this.labelName,labelValue:this.labelValue,text:this.text}}}}const c={[e.Datasource]:"database",[e.LabelName]:"database",[e.LabelValue]:"database",[e.Dashboard]:"dashboard",[e.DashboardFolder]:"folder",[e.Unknown]:"circle-mono",[e.Structured]:"gf-grid"};function p(t,a){return t===e.Datasource?a.datasourceName:t===e.LabelName?a.labelName:t===e.LabelValue?a.labelValue:t===e.Dashboard?a.dashboardTitle:t===e.DashboardFolder?a.folderTitle:t===e.Structured?a.data.name:"Given Context"}function f(e,t){var a,n;const f=function(e,t){switch(e){case"datasource":return new d(t);case"label_name":return new l(t);case"label_value":return new u(t);case"dashboard":return new o(t);case"dashboard_folder":return new i(t);case"structured":return new r(t);case"unknown":return new s(t);default:return console.error(`Unknown context type: ${e}`),new s(t)}}(e,t);return{node:{id:f.id,name:null!==(a=t.title)&&void 0!==a?a:p(e,t),img:t.img,icon:null!==(n=t.icon)&&void 0!==n?n:c[e],navigable:!1,selectable:!0,data:f},occurrences:[]}}function h(e,t){return f(e,t)}const m=require("@grafana/runtime"),b=require("react"),v=[],x="grafana-assistant:page-context-sync",g="grafana-assistant:page-context-update",w="grafana-assistant:page-context-remove",E="grafana-assistant:location-changed";let L=!1;function y(e,t){const a=v.findIndex((t=>{return a=t.urlPattern,n=e,"string"==typeof a&&"string"==typeof n?a===n:a instanceof RegExp&&n instanceof RegExp&&a.source===n.source&&a.flags===n.flags;var a,n}));let n;-1!==a?(n=v[a],n.context=[...t]):(n={id:`page-context-${Date.now()}-${Math.random().toString(36).slice(2,11)}`,urlPattern:e,context:[...t]},v.push(n)),window.dispatchEvent(new CustomEvent(g,{detail:n})),window.dispatchEvent(new CustomEvent(x,{detail:{registry:v}}));const s=e=>{const t=v.findIndex((e=>e.id===n.id));-1!==t&&(v[t].context=[...e],window.dispatchEvent(new CustomEvent(g,{detail:v[t]})))};return s.unregister=()=>{const e=v.findIndex((e=>e.id===n.id));-1!==e&&(v.splice(e,1),window.dispatchEvent(new CustomEvent(w,{detail:{id:n.id}})))},s}function T(e,t=[]){const a=(0,b.useRef)(void 0),n=(0,b.useRef)(t);return n.current=t,(0,b.useEffect)((()=>(a.current=y(e,n.current),()=>{var e;null===(e=a.current)||void 0===e||e.unregister()})),[e]),(0,b.useEffect)((()=>{a.current&&a.current(t)}),[t]),(0,b.useCallback)((e=>{var t;null===(t=a.current)||void 0===t||t.call(a,e)}),[])}function N(e={allowQuestions:!1}){const[t,a]=(0,b.useState)([]),n=(0,m.useLocationService)(),s=(0,b.useRef)("");return(0,b.useEffect)((()=>{const e=()=>{const e=function(e,t){if(!e)return[];const a=[];for(const n of t)U(e,n.urlPattern)&&a.push(...n.context);return a}(n.getLocation().pathname,v);a(e)},t=()=>{e()},r=t=>{var a;const s=null===(a=t.detail)||void 0===a?void 0:a.pathname;s&&s===n.getLocation().pathname&&e()},o=n.getLocationObservable().subscribe((t=>{const a=t.pathname;a!==s.current&&(s.current=a,function(e){window.dispatchEvent(new CustomEvent(E,{detail:{pathname:e}}))}(a),e())}));return e(),window.addEventListener(x,t),window.addEventListener(g,t),window.addEventListener(w,t),window.addEventListener(E,r),()=>{o.unsubscribe(),window.removeEventListener(x,t),window.removeEventListener(g,t),window.removeEventListener(w,t),window.removeEventListener(E,r)}}),[n]),e.allowQuestions?t:t.filter((e=>{var t;return"question"!==(null===(t=e.node.data)||void 0===t?void 0:t.type)}))}function U(e,t){if(t instanceof RegExp)return t.test(e);if("string"==typeof t){const a=t.replace(/\*\*/g,"\0DOUBLE_STAR\0").replace(/\*/g,"[^/]*").replace(/\u0000DOUBLE_STAR\u0000/g,".*").replace(/\?/g,".");return new RegExp(`^${a}$`).test(e)}return!1}function D(e,t){const a=e=>e.map(((e,t)=>({node:{id:`question-${t}`,name:e.prompt,navigable:!1,selectable:!0,icon:"question-circle",data:{type:"question",prompt:e.prompt,context:e.context||[]}},occurrences:[]}))),n=y(e,a(t)),s=e=>{n(a(e))};return s.unregister=n.unregister,s}function S(e,t=[]){const a=e=>e.map(((e,t)=>({node:{id:`question-${t}`,name:e.prompt,navigable:!1,selectable:!0,icon:"question-circle",data:{type:"question",prompt:e.prompt,context:e.context||[]}},occurrences:[]}))),n=T(e,a(t));return e=>{n(a(e))}}function I(){const e=N({allowQuestions:!0});return P(e)}L||(window.addEventListener(x,(e=>{var t;const a=null===(t=e.detail)||void 0===t?void 0:t.registry;if(a){const e=new Set(v.map((e=>e.id))),t=a.filter((t=>!e.has(t.id)));v.push(...t)}})),window.addEventListener(g,(e=>{const t=e.detail;if(t){const e=v.findIndex((e=>e.id===t.id));-1!==e?v[e]=t:v.push(t)}})),window.addEventListener(w,(e=>{var t;const a=null===(t=e.detail)||void 0===t?void 0:t.id;if(a){const e=v.findIndex((e=>e.id===a));-1!==e&&v.splice(e,1)}})),L=!0);const P=e=>e.filter((e=>{var t;return"question"===(null===(t=e.node.data)||void 0===t?void 0:t.type)})).map((e=>{var t,a;return{prompt:(null===(t=e.node.data)||void 0===t?void 0:t.prompt)||e.node.name,context:(null===(a=e.node.data)||void 0===a?void 0:a.context)||[]}})),C="grafana-assistant-app/callback/v0-alpha";function A(e,t){return{namespace:e,functions:t}}function F(e){return{title:"callback",targets:[C],fn:()=>e.map((e=>({namespace:e.namespace,functions:e.functions})))}}const O=require("rxjs");function V(){if(!m.getObservablePluginLinks)return(0,O.of)(!1);return(0,m.getObservablePluginLinks)({extensionPointId:"grafana/extension-sidebar/v0-alpha"}).pipe((0,O.map)((e=>e.some((e=>"grafana-assistant-app"===e.pluginId&&"Grafana Assistant"===e.title)))))}const q=require("@grafana/data");class $ extends q.BusEventWithPayload{}$.type="open-extension-sidebar";class _ extends q.BusEventBase{}function k(e){!function(e,t,a){const n=new $({pluginId:"grafana-assistant-app",componentTitle:"Grafana Assistant",props:a});(0,m.getAppEvents)().publish(n)}(0,0,{initialPrompt:e.prompt,initialContext:e.context})}function M(){!function(){const e=new _;(0,m.getAppEvents)().publish(e)}()}function R(){const[e,t]=(0,b.useState)(!1);return(0,b.useEffect)((()=>{const e=V().subscribe((e=>t(e)));return()=>{e.unsubscribe()}}),[]),[e,e?k:void 0,e?M:void 0]}_.type="close-extension-sidebar",module.exports=a})();
1
+ (()=>{"use strict";var e={n:t=>{var n=t&&t.__esModule?()=>t.default:()=>t;return e.d(n,{a:n}),n},d:(t,n)=>{for(var a in n)e.o(n,a)&&!e.o(t,a)&&Object.defineProperty(t,a,{enumerable:!0,get:n[a]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},t={};function n(e){let t=5381;for(let n=0;n<e.length;n++)t=(t<<5)+t+e.charCodeAt(n);return(t>>>0).toString(16)}e.r(t),e.d(t,{CALLBACK_EXTENSION_POINT:()=>I,ComponentNodeData:()=>b,DashboardNodeData:()=>x,DatasourceNodeData:()=>E,FolderNodeData:()=>k,LabelNameNodeData:()=>C,LabelValueNodeData:()=>A,OpenAssistantButton:()=>ut,StructuredNodeData:()=>r,closeAssistant:()=>z,createAssistantContextItem:()=>N,getExposeAssistantFunctionsConfig:()=>P,isAssistantAvailable:()=>j,newFunctionNamespace:()=>O,openAssistant:()=>F,provideComponents:()=>w,providePageContext:()=>h,provideQuestions:()=>L,useAssistant:()=>G,usePageComponents:()=>y,usePageContext:()=>v,useProvidePageContext:()=>m,useProvideQuestions:()=>T,useQuestions:()=>_});class a{constructor(e){this.params=e,this.text="",this.id=n(e.id)}formatForLLM(e){var t,n;return{type:"unknown",codeElementIds:e,data:{name:null!==(t=this.params.text)&&void 0!==t?t:"",text:null!==(n=this.params.text)&&void 0!==n?n:""}}}}class r{constructor(e){this.params=e,this.id=n(JSON.stringify(e.data))}formatForLLM(e){return{type:"structured",codeElementIds:e,data:this.params.data}}}const s=require("@grafana/runtime"),o=require("react");var i=e.n(o);const c=[],u="grafana-assistant:page-context-sync",l="grafana-assistant:page-context-update",d="grafana-assistant:page-context-remove",f="grafana-assistant:location-changed";let p=!1;function h(e,t){const n=c.findIndex((t=>{return n=t.urlPattern,a=e,"string"==typeof n&&"string"==typeof a?n===a:n instanceof RegExp&&a instanceof RegExp&&n.source===a.source&&n.flags===a.flags;var n,a}));let a;-1!==n?(a=c[n],a.context=[...t]):(a={id:`page-context-${Date.now()}-${Math.random().toString(36).slice(2,11)}`,urlPattern:e,context:[...t]},c.push(a)),window.dispatchEvent(new CustomEvent(l,{detail:a})),window.dispatchEvent(new CustomEvent(u,{detail:{registry:c}}));const r=e=>{const t=c.findIndex((e=>e.id===a.id));-1!==t&&(c[t].context=[...e],window.dispatchEvent(new CustomEvent(l,{detail:c[t]})))};return r.unregister=()=>{const e=c.findIndex((e=>e.id===a.id));-1!==e&&(c.splice(e,1),window.dispatchEvent(new CustomEvent(d,{detail:{id:a.id}})))},r}function m(e,t=[]){const n=(0,o.useRef)(void 0),a=(0,o.useRef)(t);return a.current=t,(0,o.useEffect)((()=>(n.current=h(e,a.current),()=>{var e;null===(e=n.current)||void 0===e||e.unregister()})),[e]),(0,o.useEffect)((()=>{n.current&&n.current(t)}),[t]),(0,o.useCallback)((e=>{var t;null===(t=n.current)||void 0===t||t.call(n,e)}),[])}function v(e={allowQuestions:!1,allowComponents:!1}){const[t,n]=(0,o.useState)([]),a=(0,s.useLocationService)(),r=(0,o.useRef)("");(0,o.useEffect)((()=>{const e=()=>{const e=function(e,t){if(!e)return[];const n=[];for(const a of t)g(e,a.urlPattern)&&n.push(...a.context);return n}(a.getLocation().pathname,c);n(e)},t=()=>{e()},s=t=>{var n;const r=null===(n=t.detail)||void 0===n?void 0:n.pathname;r&&r===a.getLocation().pathname&&e()},o=a.getLocationObservable().subscribe((t=>{const n=t.pathname;n!==r.current&&(r.current=n,function(e){window.dispatchEvent(new CustomEvent(f,{detail:{pathname:e}}))}(n),e())}));return e(),window.addEventListener(u,t),window.addEventListener(l,t),window.addEventListener(d,t),window.addEventListener(f,s),()=>{o.unsubscribe(),window.removeEventListener(u,t),window.removeEventListener(l,t),window.removeEventListener(d,t),window.removeEventListener(f,s)}}),[a]);let i=t;return e.allowQuestions||(i=i.filter((e=>{var t;return"question"!==(null===(t=e.node.data)||void 0===t?void 0:t.type)}))),e.allowComponents||(i=i.filter((e=>{var t;return"component"!==(null===(t=e.node.data)||void 0===t?void 0:t.type)}))),i}function g(e,t){if(t instanceof RegExp)return t.test(e);if("string"==typeof t){const n=t.replace(/\*\*/g,"\0DOUBLE_STAR\0").replace(/\*/g,"[^/]*").replace(/\u0000DOUBLE_STAR\u0000/g,".*").replace(/\?/g,".");return new RegExp(`^${n}$`).test(e)}return!1}p||(window.addEventListener(u,(e=>{var t;const n=null===(t=e.detail)||void 0===t?void 0:t.registry;if(n){const e=new Set(c.map((e=>e.id))),t=n.filter((t=>!e.has(t.id)));c.push(...t)}})),window.addEventListener(l,(e=>{const t=e.detail;if(t){const e=c.findIndex((e=>e.id===t.id));-1!==e?c[e]=t:c.push(t)}})),window.addEventListener(d,(e=>{var t;const n=null===(t=e.detail)||void 0===t?void 0:t.id;if(n){const e=c.findIndex((e=>e.id===n));-1!==e&&c.splice(e,1)}})),p=!0);class b extends a{constructor(e){const t=e.namespace||"components";super({...e,id:`${t}-${Object.keys(e.components).join("-")}`}),this.components=e.components,this.prompt=e.prompt,this.namespace=t}formatForLLM(e){return{type:"component",codeElementIds:e,data:{name:`${this.namespace} components`,prompt:this.prompt,namespace:this.namespace}}}}function y(){const e=v({allowComponents:!0,allowQuestions:!1});return(0,o.useMemo)((()=>{const t={};return e.filter((e=>{var t;return null===(t=e.node.data)||void 0===t?void 0:t.components})).forEach((e=>{const n=e.node.data;if(null==n?void 0:n.components){const e=n.namespace||n.name||"components";Object.entries(n.components).forEach((([n,a])=>{t[`${e}_${n}`]=a}))}})),t}),[e])}function w(e,t,n,a=/.*/){return h(a,[N("component",{components:n,prompt:e,namespace:t})])}class x extends a{constructor(e){super({...e,id:e.dashboardUid}),this.dashboardUid=e.dashboardUid,this.dashboardTitle=e.dashboardTitle,this.folderUid=e.folderUid,this.folderTitle=e.folderTitle,this.text=e.dashboardTitle}formatForLLM(e){return{type:"dashboard",codeElementIds:e,data:{name:this.dashboardTitle,dashboardUid:this.dashboardUid,dashboardTitle:this.dashboardTitle,folderUid:this.folderUid,folderTitle:this.folderTitle,text:this.text}}}}class k extends a{constructor(e){super({...e,id:e.folderUid}),this.text="",this.folderUid=e.folderUid,this.folderTitle=e.folderTitle,this.text=e.folderTitle}formatForLLM(e){return{type:"dashboard_folder",codeElementIds:e,data:{name:this.folderTitle,folderUid:this.folderUid,folderTitle:this.folderTitle,text:this.text}}}}class E extends a{constructor(e){super({...e,id:e.datasourceUid}),this.datasourceUid=e.datasourceUid,this.datasourceType=e.datasourceType,this.datasourceName=e.datasourceName,this.img=e.img,this.text=e.datasourceName}formatForLLM(e){return{type:"datasource",codeElementIds:e,data:{name:this.datasourceName,uid:this.datasourceUid,type:this.datasourceType,text:this.text,img:this.img}}}}class C extends a{constructor(e){super({...e,id:`${e.datasourceUid}-${e.labelName}`}),this.datasourceUid=e.datasourceUid,this.datasourceType=e.datasourceType,this.datasourceName=e.datasourceName,this.labelName=e.labelName,this.text=e.labelName,this.img=e.img}formatForLLM(e){return{type:"label_name",codeElementIds:e,data:{name:this.labelName,datasourceUid:this.datasourceUid,datasourceType:this.datasourceType,datasourceName:this.datasourceName,labelName:this.labelName,img:this.img,text:this.text}}}}class A extends a{constructor(e){super({...e,id:`${e.datasourceUid}-${e.labelName}-${e.labelValue}`}),this.datasourceUid=e.datasourceUid,this.datasourceType=e.datasourceType,this.datasourceName=e.datasourceName,this.labelName=e.labelName,this.labelValue=e.labelValue,this.text=e.labelValue,this.img=e.img}formatForLLM(e){return{type:"label_value",codeElementIds:e,data:{name:this.labelValue,datasourceUid:this.datasourceUid,datasourceType:this.datasourceType,datasourceName:this.datasourceName,labelName:this.labelName,labelValue:this.labelValue,text:this.text,img:this.img}}}}function $(e){var t,n,a,r,o;const i=(0,s.getDataSourceSrv)().getInstanceSettings(e);return{datasourceType:null!==(t=null==i?void 0:i.type)&&void 0!==t?t:"unknown",datasourceName:null!==(n=null==i?void 0:i.name)&&void 0!==n?n:e,img:null===(o=null===(r=null===(a=null==i?void 0:i.meta)||void 0===a?void 0:a.info)||void 0===r?void 0:r.logos)||void 0===o?void 0:o.small}}const S={datasource:"database",label_name:"database",label_value:"database",dashboard:"dashboard",dashboard_folder:"folder",unknown:"circle-mono",structured:"gf-grid",component:"gf-grid"};function N(e,t){var n,s,o;const i=function(e,t){switch(e){case"datasource":return new E({...t,...$(t.datasourceUid)});case"label_name":return new C({...t,...$(t.datasourceUid)});case"label_value":return new A({...t,...$(t.datasourceUid)});case"dashboard":return new x(t);case"dashboard_folder":return new k(t);case"structured":return new r(t);case"component":return new b({...t,hidden:!0});case"unknown":return new a(t);default:return console.error(`Unknown context type: ${e}`),new a(t)}}(e,t),c=null!==(n=t.title)&&void 0!==n?n:function(e){var t;return e instanceof r?e.formatForLLM().data.name:null!==(t=e.text)&&void 0!==t?t:"Given Context"}(i),u=null!==(s=t.img)&&void 0!==s?s:function(e){if("img"in e)return e.img}(i);return{node:{id:i.id,name:c,img:u,icon:null!==(o=t.icon)&&void 0!==o?o:S[e],navigable:!1,selectable:!0,data:i},occurrences:[]}}function L(e,t){const n=e=>e.map(((e,t)=>({node:{id:`question-${t}`,name:e.prompt,navigable:!1,selectable:!0,icon:"question-circle",data:{type:"question",prompt:e.prompt,context:e.context||[]}},occurrences:[]}))),a=h(e,n(t)),r=e=>{a(n(e))};return r.unregister=a.unregister,r}function T(e,t=[]){const n=e=>e.map(((e,t)=>({node:{id:`question-${t}`,name:e.prompt,navigable:!1,selectable:!0,icon:"question-circle",data:{type:"question",prompt:e.prompt,context:e.context||[]}},occurrences:[]}))),a=m(e,n(t));return e=>{a(n(e))}}function _(){const e=v({allowQuestions:!0,allowComponents:!1});return U(e)}const U=e=>e.filter((e=>{var t;return"question"===(null===(t=e.node.data)||void 0===t?void 0:t.type)})).map((e=>{var t,n;return{prompt:(null===(t=e.node.data)||void 0===t?void 0:t.prompt)||e.node.name,context:(null===(n=e.node.data)||void 0===n?void 0:n.context)||[]}})),I="grafana-assistant-app/callback/v0-alpha";function O(e,t){return{namespace:e,functions:t}}function P(e){return{title:"callback",targets:[I],fn:()=>e.map((e=>({namespace:e.namespace,functions:e.functions})))}}const R=require("rxjs");function j(){if(!s.getObservablePluginLinks)return(0,R.of)(!1);return(0,s.getObservablePluginLinks)({extensionPointId:"grafana/extension-sidebar/v0-alpha"}).pipe((0,R.map)((e=>e.some((e=>"grafana-assistant-app"===e.pluginId&&"Grafana Assistant"===e.title)))))}const M=require("@grafana/data");class q extends M.BusEventWithPayload{}q.type="open-extension-sidebar";class D extends M.BusEventBase{}function F(e){var t,n;(0,s.reportInteraction)("grafana_assistant_app_opened_sidebar",{from:e.origin,prompt:null!==(t=e.prompt)&&void 0!==t?t:""}),function(e,t,n){const a=new q({pluginId:"grafana-assistant-app",componentTitle:"Grafana Assistant",props:n});(0,s.getAppEvents)().publish(a)}(0,0,{initialPrompt:e.prompt,initialContext:e.context,initialAutoSend:null===(n=e.autoSend)||void 0===n||n})}function z(){!function(){const e=new D;(0,s.getAppEvents)().publish(e)}()}function G(){const[e,t]=(0,o.useState)(!1);return(0,o.useEffect)((()=>{const e=j().subscribe((e=>t(e)));return()=>{e.unsubscribe()}}),[]),[e,e?F:void 0,e?z:void 0]}D.type="close-extension-sidebar";const B=require("@grafana/ui");var V=function(){function e(e){var t=this;this._insertTag=function(e){var n;n=0===t.tags.length?t.insertionPoint?t.insertionPoint.nextSibling:t.prepend?t.container.firstChild:t.before:t.tags[t.tags.length-1].nextSibling,t.container.insertBefore(e,n),t.tags.push(e)},this.isSpeedy=void 0===e.speedy||e.speedy,this.tags=[],this.ctr=0,this.nonce=e.nonce,this.key=e.key,this.container=e.container,this.prepend=e.prepend,this.insertionPoint=e.insertionPoint,this.before=null}var t=e.prototype;return t.hydrate=function(e){e.forEach(this._insertTag)},t.insert=function(e){this.ctr%(this.isSpeedy?65e3:1)==0&&this._insertTag(function(e){var t=document.createElement("style");return t.setAttribute("data-emotion",e.key),void 0!==e.nonce&&t.setAttribute("nonce",e.nonce),t.appendChild(document.createTextNode("")),t.setAttribute("data-s",""),t}(this));var t=this.tags[this.tags.length-1];if(this.isSpeedy){var n=function(e){if(e.sheet)return e.sheet;for(var t=0;t<document.styleSheets.length;t++)if(document.styleSheets[t].ownerNode===e)return document.styleSheets[t]}(t);try{n.insertRule(e,n.cssRules.length)}catch(e){}}else t.appendChild(document.createTextNode(e));this.ctr++},t.flush=function(){this.tags.forEach((function(e){var t;return null==(t=e.parentNode)?void 0:t.removeChild(e)})),this.tags=[],this.ctr=0},e}(),Q=Math.abs,W=String.fromCharCode,H=Object.assign;function J(e){return e.trim()}function K(e,t,n){return e.replace(t,n)}function X(e,t){return e.indexOf(t)}function Z(e,t){return 0|e.charCodeAt(t)}function Y(e,t,n){return e.slice(t,n)}function ee(e){return e.length}function te(e){return e.length}function ne(e,t){return t.push(e),e}var ae=1,re=1,se=0,oe=0,ie=0,ce="";function ue(e,t,n,a,r,s,o){return{value:e,root:t,parent:n,type:a,props:r,children:s,line:ae,column:re,length:o,return:""}}function le(e,t){return H(ue("",null,null,"",null,null,0),e,{length:-e.length},t)}function de(){return ie=oe>0?Z(ce,--oe):0,re--,10===ie&&(re=1,ae--),ie}function fe(){return ie=oe<se?Z(ce,oe++):0,re++,10===ie&&(re=1,ae++),ie}function pe(){return Z(ce,oe)}function he(){return oe}function me(e,t){return Y(ce,e,t)}function ve(e){switch(e){case 0:case 9:case 10:case 13:case 32:return 5;case 33:case 43:case 44:case 47:case 62:case 64:case 126:case 59:case 123:case 125:return 4;case 58:return 3;case 34:case 39:case 40:case 91:return 2;case 41:case 93:return 1}return 0}function ge(e){return ae=re=1,se=ee(ce=e),oe=0,[]}function be(e){return ce="",e}function ye(e){return J(me(oe-1,ke(91===e?e+2:40===e?e+1:e)))}function we(e){for(;(ie=pe())&&ie<33;)fe();return ve(e)>2||ve(ie)>3?"":" "}function xe(e,t){for(;--t&&fe()&&!(ie<48||ie>102||ie>57&&ie<65||ie>70&&ie<97););return me(e,he()+(t<6&&32==pe()&&32==fe()))}function ke(e){for(;fe();)switch(ie){case e:return oe;case 34:case 39:34!==e&&39!==e&&ke(ie);break;case 40:41===e&&ke(e);break;case 92:fe()}return oe}function Ee(e,t){for(;fe()&&e+ie!==57&&(e+ie!==84||47!==pe()););return"/*"+me(t,oe-1)+"*"+W(47===e?e:fe())}function Ce(e){for(;!ve(pe());)fe();return me(e,oe)}var Ae="-ms-",$e="-moz-",Se="-webkit-",Ne="comm",Le="rule",Te="decl",_e="@keyframes";function Ue(e,t){for(var n="",a=te(e),r=0;r<a;r++)n+=t(e[r],r,e,t)||"";return n}function Ie(e,t,n,a){switch(e.type){case"@layer":if(e.children.length)break;case"@import":case Te:return e.return=e.return||e.value;case Ne:return"";case _e:return e.return=e.value+"{"+Ue(e.children,a)+"}";case Le:e.value=e.props.join(",")}return ee(n=Ue(e.children,a))?e.return=e.value+"{"+n+"}":""}function Oe(e){return be(Pe("",null,null,null,[""],e=ge(e),0,[0],e))}function Pe(e,t,n,a,r,s,o,i,c){for(var u=0,l=0,d=o,f=0,p=0,h=0,m=1,v=1,g=1,b=0,y="",w=r,x=s,k=a,E=y;v;)switch(h=b,b=fe()){case 40:if(108!=h&&58==Z(E,d-1)){-1!=X(E+=K(ye(b),"&","&\f"),"&\f")&&(g=-1);break}case 34:case 39:case 91:E+=ye(b);break;case 9:case 10:case 13:case 32:E+=we(h);break;case 92:E+=xe(he()-1,7);continue;case 47:switch(pe()){case 42:case 47:ne(je(Ee(fe(),he()),t,n),c);break;default:E+="/"}break;case 123*m:i[u++]=ee(E)*g;case 125*m:case 59:case 0:switch(b){case 0:case 125:v=0;case 59+l:-1==g&&(E=K(E,/\f/g,"")),p>0&&ee(E)-d&&ne(p>32?Me(E+";",a,n,d-1):Me(K(E," ","")+";",a,n,d-2),c);break;case 59:E+=";";default:if(ne(k=Re(E,t,n,u,l,r,i,y,w=[],x=[],d),s),123===b)if(0===l)Pe(E,t,k,k,w,s,d,i,x);else switch(99===f&&110===Z(E,3)?100:f){case 100:case 108:case 109:case 115:Pe(e,k,k,a&&ne(Re(e,k,k,0,0,r,i,y,r,w=[],d),x),r,x,d,i,a?w:x);break;default:Pe(E,k,k,k,[""],x,0,i,x)}}u=l=p=0,m=g=1,y=E="",d=o;break;case 58:d=1+ee(E),p=h;default:if(m<1)if(123==b)--m;else if(125==b&&0==m++&&125==de())continue;switch(E+=W(b),b*m){case 38:g=l>0?1:(E+="\f",-1);break;case 44:i[u++]=(ee(E)-1)*g,g=1;break;case 64:45===pe()&&(E+=ye(fe())),f=pe(),l=d=ee(y=E+=Ce(he())),b++;break;case 45:45===h&&2==ee(E)&&(m=0)}}return s}function Re(e,t,n,a,r,s,o,i,c,u,l){for(var d=r-1,f=0===r?s:[""],p=te(f),h=0,m=0,v=0;h<a;++h)for(var g=0,b=Y(e,d+1,d=Q(m=o[h])),y=e;g<p;++g)(y=J(m>0?f[g]+" "+b:K(b,/&\f/g,f[g])))&&(c[v++]=y);return ue(e,t,n,0===r?Le:i,c,u,l)}function je(e,t,n){return ue(e,t,n,Ne,W(ie),Y(e,2,-2),0)}function Me(e,t,n,a){return ue(e,t,n,Te,Y(e,0,a),Y(e,a+1,-1),a)}var qe=function(e,t,n){for(var a=0,r=0;a=r,r=pe(),38===a&&12===r&&(t[n]=1),!ve(r);)fe();return me(e,oe)},De=new WeakMap,Fe=function(e){if("rule"===e.type&&e.parent&&!(e.length<1)){for(var t=e.value,n=e.parent,a=e.column===n.column&&e.line===n.line;"rule"!==n.type;)if(!(n=n.parent))return;if((1!==e.props.length||58===t.charCodeAt(0)||De.get(n))&&!a){De.set(e,!0);for(var r=[],s=function(e,t){return be(function(e,t){var n=-1,a=44;do{switch(ve(a)){case 0:38===a&&12===pe()&&(t[n]=1),e[n]+=qe(oe-1,t,n);break;case 2:e[n]+=ye(a);break;case 4:if(44===a){e[++n]=58===pe()?"&\f":"",t[n]=e[n].length;break}default:e[n]+=W(a)}}while(a=fe());return e}(ge(e),t))}(t,r),o=n.props,i=0,c=0;i<s.length;i++)for(var u=0;u<o.length;u++,c++)e.props[c]=r[i]?s[i].replace(/&\f/g,o[u]):o[u]+" "+s[i]}}},ze=function(e){if("decl"===e.type){var t=e.value;108===t.charCodeAt(0)&&98===t.charCodeAt(2)&&(e.return="",e.value="")}};function Ge(e,t){switch(function(e,t){return 45^Z(e,0)?(((t<<2^Z(e,0))<<2^Z(e,1))<<2^Z(e,2))<<2^Z(e,3):0}(e,t)){case 5103:return Se+"print-"+e+e;case 5737:case 4201:case 3177:case 3433:case 1641:case 4457:case 2921:case 5572:case 6356:case 5844:case 3191:case 6645:case 3005:case 6391:case 5879:case 5623:case 6135:case 4599:case 4855:case 4215:case 6389:case 5109:case 5365:case 5621:case 3829:return Se+e+e;case 5349:case 4246:case 4810:case 6968:case 2756:return Se+e+$e+e+Ae+e+e;case 6828:case 4268:return Se+e+Ae+e+e;case 6165:return Se+e+Ae+"flex-"+e+e;case 5187:return Se+e+K(e,/(\w+).+(:[^]+)/,Se+"box-$1$2"+Ae+"flex-$1$2")+e;case 5443:return Se+e+Ae+"flex-item-"+K(e,/flex-|-self/,"")+e;case 4675:return Se+e+Ae+"flex-line-pack"+K(e,/align-content|flex-|-self/,"")+e;case 5548:return Se+e+Ae+K(e,"shrink","negative")+e;case 5292:return Se+e+Ae+K(e,"basis","preferred-size")+e;case 6060:return Se+"box-"+K(e,"-grow","")+Se+e+Ae+K(e,"grow","positive")+e;case 4554:return Se+K(e,/([^-])(transform)/g,"$1"+Se+"$2")+e;case 6187:return K(K(K(e,/(zoom-|grab)/,Se+"$1"),/(image-set)/,Se+"$1"),e,"")+e;case 5495:case 3959:return K(e,/(image-set\([^]*)/,Se+"$1$`$1");case 4968:return K(K(e,/(.+:)(flex-)?(.*)/,Se+"box-pack:$3"+Ae+"flex-pack:$3"),/s.+-b[^;]+/,"justify")+Se+e+e;case 4095:case 3583:case 4068:case 2532:return K(e,/(.+)-inline(.+)/,Se+"$1$2")+e;case 8116:case 7059:case 5753:case 5535:case 5445:case 5701:case 4933:case 4677:case 5533:case 5789:case 5021:case 4765:if(ee(e)-1-t>6)switch(Z(e,t+1)){case 109:if(45!==Z(e,t+4))break;case 102:return K(e,/(.+:)(.+)-([^]+)/,"$1"+Se+"$2-$3$1"+$e+(108==Z(e,t+3)?"$3":"$2-$3"))+e;case 115:return~X(e,"stretch")?Ge(K(e,"stretch","fill-available"),t)+e:e}break;case 4949:if(115!==Z(e,t+1))break;case 6444:switch(Z(e,ee(e)-3-(~X(e,"!important")&&10))){case 107:return K(e,":",":"+Se)+e;case 101:return K(e,/(.+:)([^;!]+)(;|!.+)?/,"$1"+Se+(45===Z(e,14)?"inline-":"")+"box$3$1"+Se+"$2$3$1"+Ae+"$2box$3")+e}break;case 5936:switch(Z(e,t+11)){case 114:return Se+e+Ae+K(e,/[svh]\w+-[tblr]{2}/,"tb")+e;case 108:return Se+e+Ae+K(e,/[svh]\w+-[tblr]{2}/,"tb-rl")+e;case 45:return Se+e+Ae+K(e,/[svh]\w+-[tblr]{2}/,"lr")+e}return Se+e+Ae+e+e}return e}var Be=[function(e,t,n,a){if(e.length>-1&&!e.return)switch(e.type){case Te:e.return=Ge(e.value,e.length);break;case _e:return Ue([le(e,{value:K(e.value,"@","@"+Se)})],a);case Le:if(e.length)return function(e,t){return e.map(t).join("")}(e.props,(function(t){switch(function(e){return(e=/(::plac\w+|:read-\w+)/.exec(e))?e[0]:e}(t)){case":read-only":case":read-write":return Ue([le(e,{props:[K(t,/:(read-\w+)/,":-moz-$1")]})],a);case"::placeholder":return Ue([le(e,{props:[K(t,/:(plac\w+)/,":"+Se+"input-$1")]}),le(e,{props:[K(t,/:(plac\w+)/,":-moz-$1")]}),le(e,{props:[K(t,/:(plac\w+)/,Ae+"input-$1")]})],a)}return""}))}}],Ve={animationIterationCount:1,aspectRatio:1,borderImageOutset:1,borderImageSlice:1,borderImageWidth:1,boxFlex:1,boxFlexGroup:1,boxOrdinalGroup:1,columnCount:1,columns:1,flex:1,flexGrow:1,flexPositive:1,flexShrink:1,flexNegative:1,flexOrder:1,gridRow:1,gridRowEnd:1,gridRowSpan:1,gridRowStart:1,gridColumn:1,gridColumnEnd:1,gridColumnSpan:1,gridColumnStart:1,msGridRow:1,msGridRowSpan:1,msGridColumn:1,msGridColumnSpan:1,fontWeight:1,lineHeight:1,opacity:1,order:1,orphans:1,scale:1,tabSize:1,widows:1,zIndex:1,zoom:1,WebkitLineClamp:1,fillOpacity:1,floodOpacity:1,stopOpacity:1,strokeDasharray:1,strokeDashoffset:1,strokeMiterlimit:1,strokeOpacity:1,strokeWidth:1};function Qe(e){var t=Object.create(null);return function(n){return void 0===t[n]&&(t[n]=e(n)),t[n]}}var We=/[A-Z]|^ms/g,He=/_EMO_([^_]+?)_([^]*?)_EMO_/g,Je=function(e){return 45===e.charCodeAt(1)},Ke=function(e){return null!=e&&"boolean"!=typeof e},Xe=Qe((function(e){return Je(e)?e:e.replace(We,"-$&").toLowerCase()})),Ze=function(e,t){switch(e){case"animation":case"animationName":if("string"==typeof t)return t.replace(He,(function(e,t,n){return et={name:t,styles:n,next:et},t}))}return 1===Ve[e]||Je(e)||"number"!=typeof t||0===t?t:t+"px"};function Ye(e,t,n){if(null==n)return"";var a=n;if(void 0!==a.__emotion_styles)return a;switch(typeof n){case"boolean":return"";case"object":var r=n;if(1===r.anim)return et={name:r.name,styles:r.styles,next:et},r.name;var s=n;if(void 0!==s.styles){var o=s.next;if(void 0!==o)for(;void 0!==o;)et={name:o.name,styles:o.styles,next:et},o=o.next;return s.styles+";"}return function(e,t,n){var a="";if(Array.isArray(n))for(var r=0;r<n.length;r++)a+=Ye(e,t,n[r])+";";else for(var s in n){var o=n[s];if("object"!=typeof o){var i=o;null!=t&&void 0!==t[i]?a+=s+"{"+t[i]+"}":Ke(i)&&(a+=Xe(s)+":"+Ze(s,i)+";")}else if(!Array.isArray(o)||"string"!=typeof o[0]||null!=t&&void 0!==t[o[0]]){var c=Ye(e,t,o);switch(s){case"animation":case"animationName":a+=Xe(s)+":"+c+";";break;default:a+=s+"{"+c+"}"}}else for(var u=0;u<o.length;u++)Ke(o[u])&&(a+=Xe(s)+":"+Ze(s,o[u])+";")}return a}(e,t,n);case"function":if(void 0!==e){var i=et,c=n(e);return et=i,Ye(e,t,c)}}var u=n;if(null==t)return u;var l=t[u];return void 0!==l?l:u}var et,tt=/label:\s*([^\s;{]+)\s*(;|$)/g;function nt(e,t,n){if(1===e.length&&"object"==typeof e[0]&&null!==e[0]&&void 0!==e[0].styles)return e[0];var a=!0,r="";et=void 0;var s=e[0];null==s||void 0===s.raw?(a=!1,r+=Ye(n,t,s)):r+=s[0];for(var o=1;o<e.length;o++)r+=Ye(n,t,e[o]),a&&(r+=s[o]);tt.lastIndex=0;for(var i,c="";null!==(i=tt.exec(r));)c+="-"+i[1];var u=function(e){for(var t,n=0,a=0,r=e.length;r>=4;++a,r-=4)t=1540483477*(65535&(t=255&e.charCodeAt(a)|(255&e.charCodeAt(++a))<<8|(255&e.charCodeAt(++a))<<16|(255&e.charCodeAt(++a))<<24))+(59797*(t>>>16)<<16),n=1540483477*(65535&(t^=t>>>24))+(59797*(t>>>16)<<16)^1540483477*(65535&n)+(59797*(n>>>16)<<16);switch(r){case 3:n^=(255&e.charCodeAt(a+2))<<16;case 2:n^=(255&e.charCodeAt(a+1))<<8;case 1:n=1540483477*(65535&(n^=255&e.charCodeAt(a)))+(59797*(n>>>16)<<16)}return(((n=1540483477*(65535&(n^=n>>>13))+(59797*(n>>>16)<<16))^n>>>15)>>>0).toString(36)}(r)+c;return{name:u,styles:r,next:et}}function at(e,t,n){var a="";return n.split(" ").forEach((function(n){void 0!==e[n]?t.push(e[n]+";"):n&&(a+=n+" ")})),a}function rt(e,t){if(void 0===e.inserted[t.name])return e.insert("",t,e.sheet,!0)}function st(e,t,n){var a=[],r=at(e,a,n);return a.length<2?n:r+t(a)}var ot=function e(t){for(var n="",a=0;a<t.length;a++){var r=t[a];if(null!=r){var s=void 0;switch(typeof r){case"boolean":break;case"object":if(Array.isArray(r))s=e(r);else for(var o in s="",r)r[o]&&o&&(s&&(s+=" "),s+=o);break;default:s=r}s&&(n&&(n+=" "),n+=s)}}return n};var it=function(e){var t=function(e){var t=e.key;if("css"===t){var n=document.querySelectorAll("style[data-emotion]:not([data-s])");Array.prototype.forEach.call(n,(function(e){-1!==e.getAttribute("data-emotion").indexOf(" ")&&(document.head.appendChild(e),e.setAttribute("data-s",""))}))}var a,r,s=e.stylisPlugins||Be,o={},i=[];a=e.container||document.head,Array.prototype.forEach.call(document.querySelectorAll('style[data-emotion^="'+t+' "]'),(function(e){for(var t=e.getAttribute("data-emotion").split(" "),n=1;n<t.length;n++)o[t[n]]=!0;i.push(e)}));var c,u,l,d,f=[Ie,(d=function(e){c.insert(e)},function(e){e.root||(e=e.return)&&d(e)})],p=(u=[Fe,ze].concat(s,f),l=te(u),function(e,t,n,a){for(var r="",s=0;s<l;s++)r+=u[s](e,t,n,a)||"";return r});r=function(e,t,n,a){c=n,Ue(Oe(e?e+"{"+t.styles+"}":t.styles),p),a&&(h.inserted[t.name]=!0)};var h={key:t,sheet:new V({key:t,container:a,nonce:e.nonce,speedy:e.speedy,prepend:e.prepend,insertionPoint:e.insertionPoint}),nonce:e.nonce,inserted:o,registered:{},insert:r};return h.sheet.hydrate(i),h}(e);t.sheet.speedy=function(e){this.isSpeedy=e},t.compat=!0;var n=function(){for(var e=arguments.length,n=new Array(e),a=0;a<e;a++)n[a]=arguments[a];var r=nt(n,t.registered,void 0);return function(e,t){!function(e,t){var n=e.key+"-"+t.name;void 0===e.registered[n]&&(e.registered[n]=t.styles)}(e,t);var n=e.key+"-"+t.name;if(void 0===e.inserted[t.name]){var a=t;do{e.insert(t===a?"."+n:"",a,e.sheet,!0),a=a.next}while(void 0!==a)}}(t,r),t.key+"-"+r.name};return{css:n,cx:function(){for(var e=arguments.length,a=new Array(e),r=0;r<e;r++)a[r]=arguments[r];return st(t.registered,n,ot(a))},injectGlobal:function(){for(var e=arguments.length,n=new Array(e),a=0;a<e;a++)n[a]=arguments[a];var r=nt(n,t.registered);rt(t,r)},keyframes:function(){for(var e=arguments.length,n=new Array(e),a=0;a<e;a++)n[a]=arguments[a];var r=nt(n,t.registered),s="animation-"+r.name;return rt(t,{name:r.name,styles:"@keyframes "+s+"{"+r.styles+"}"}),s},hydrate:function(e){e.forEach((function(e){t.inserted[e]=!0}))},flush:function(){t.registered={},t.inserted={},t.sheet.flush()},sheet:t.sheet,cache:t,getRegisteredStyles:at.bind(null,t.registered),merge:st.bind(null,t.registered,n)}}({key:"css"}),ct=(it.flush,it.hydrate,it.cx,it.merge,it.getRegisteredStyles,it.injectGlobal,it.keyframes,it.css);function ut(e){const[t,n]=G();return t&&n?i().createElement(lt,{...e,openAssistant:n}):null}function lt({prompt:e,origin:t,context:n,autoSend:a=!0,title:r="Analyze with Assistant",size:c="sm",iconOnlyButton:u=!1,openAssistant:l}){const d=(0,B.useStyles2)(dt);return(0,o.useEffect)((()=>{(0,s.reportInteraction)("grafana_assistant_app_open_sidebar_button_displayed",{from:t})}),[t]),i().createElement(i().Fragment,null,u?i().createElement(B.IconButton,{name:"ai-sparkle",onClick:()=>l({prompt:e,context:n,autoSend:a,origin:t}),variant:"secondary",size:c,"aria-label":r,className:d.icon,tooltip:r,"data-testid":"assistant-icon-button"}):i().createElement(B.Button,{icon:"ai-sparkle",onClick:()=>l({prompt:e,context:n,autoSend:a,origin:t}),variant:"secondary",fill:"solid",size:c,title:r,"aria-label":r,className:d.button,"data-testid":"assistant-button"},r))}it.sheet,it.cache;const dt=e=>({button:ct({label:"assistant-button",border:"1px solid transparent",borderImage:"linear-gradient(90deg, rgb(168, 85, 247), rgb(249, 115, 22)) 1"}),icon:ct({label:"assistant-icon",border:"1px solid transparent",backgroundClip:"padding-box",padding:e.spacing(.5),"&:hover":{borderImage:"linear-gradient(90deg, rgb(168, 85, 247), rgb(249, 115, 22)) 1 !important",border:"1px solid transparent",backgroundClip:"padding-box"}})});module.exports=t})();
package/dist/sidebar.d.ts CHANGED
@@ -1,14 +1,18 @@
1
1
  import { ChatContextItem } from './context/types';
2
2
  export type OpenAssistantProps = {
3
+ origin: string;
3
4
  prompt?: string;
4
5
  context?: ChatContextItem[];
6
+ autoSend?: boolean;
5
7
  };
6
8
  /**
7
9
  * Open the Grafana Assistant sidebar with a given initial prompt.
8
10
  *
9
11
  * @param props - The props to pass to the assistant.
12
+ * @param props.origin - The origin of the request that opened the assistant. This is used to track the source of the request. Should be a structured string using forward slashes, with the first part as a namespace. Examples: 'grafana-datasources/prometheus/query-builder', 'grafana-slo-app/slo-editor-overview', 'grafana/trace-view-analyzer`.
10
13
  * @param props.prompt - The initial prompt to display in the assistant.
11
14
  * @param props.context - The initial context to display in the assistant. Created with `createContext`.
15
+ * @param props.autoSend - Whether to automatically send the initial prompt. When true, opens a chat and sends the initial prompt right away. When false, opens chat and updates user message without sending it. Defaults to true.
12
16
  */
13
17
  export declare function openAssistant(props: OpenAssistantProps): void;
14
18
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grafana/assistant",
3
- "version": "0.0.15",
3
+ "version": "0.0.17",
4
4
  "description": "Type definitions and helper functions for Grafana Assistant",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -11,7 +11,10 @@
11
11
  "prebuild": "rm -rf dist",
12
12
  "build": "webpack --config webpack.config.cjs --mode production && tsc --emitDeclarationOnly",
13
13
  "dev": "webpack --config webpack.config.cjs --mode development",
14
- "clean": "rm -rf dist"
14
+ "clean": "rm -rf dist",
15
+ "test": "jest",
16
+ "test:watch": "jest --watch --onlyChanged",
17
+ "test:ci": "jest --passWithNoTests --maxWorkers 4"
15
18
  },
16
19
  "keywords": [
17
20
  "grafana",
@@ -22,6 +25,13 @@
22
25
  "author": "Grafana Labs",
23
26
  "license": "Apache-2.0",
24
27
  "devDependencies": {
28
+ "@storybook/react": "^8.6.14",
29
+ "@testing-library/jest-dom": "6.1.4",
30
+ "@testing-library/react": "14.0.0",
31
+ "@types/jest": "^29.5.0",
32
+ "@types/testing-library__jest-dom": "5.14.8",
33
+ "jest": "^29.5.0",
34
+ "jest-environment-jsdom": "^29.5.0",
25
35
  "react": "18.3.1",
26
36
  "rxjs": "7.8.2",
27
37
  "ts-loader": "^9.0.0",