@grafana/assistant 0.0.7 → 0.0.9
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 +79 -0
- package/dist/context/index.d.ts +1 -0
- package/dist/context/page.d.ts +29 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +7 -8
package/README.md
CHANGED
|
@@ -84,6 +84,48 @@ openAssistant({
|
|
|
84
84
|
});
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
+
### Providing Page-Specific Context
|
|
88
|
+
|
|
89
|
+
You can register context items that are automatically included when the assistant is opened on pages matching specific URL patterns. The `providePageContext` function works like `useState` - it returns a setter function that allows you to update the context dynamically:
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import { providePageContext, createContext } from '@grafana/assistant';
|
|
93
|
+
|
|
94
|
+
// Create initial context for dashboard pages
|
|
95
|
+
const dashboardContext = createContext('structured', {
|
|
96
|
+
data: {
|
|
97
|
+
name: 'Dashboard Context',
|
|
98
|
+
pageType: 'dashboard',
|
|
99
|
+
capabilities: ['view', 'edit', 'share'],
|
|
100
|
+
help: 'Use the assistant to analyze dashboard data, create queries, or troubleshoot issues.'
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Register context for all dashboard pages and get a setter function
|
|
105
|
+
const setContext = providePageContext('/d/*', [dashboardContext]);
|
|
106
|
+
|
|
107
|
+
// Later, dynamically update the context based on user interactions or data changes
|
|
108
|
+
setContext([
|
|
109
|
+
dashboardContext,
|
|
110
|
+
createContext('structured', {
|
|
111
|
+
data: {
|
|
112
|
+
name: 'Panel Context',
|
|
113
|
+
selectedPanel: 'cpu-usage-panel',
|
|
114
|
+
panelType: 'graph'
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
]);
|
|
118
|
+
|
|
119
|
+
// The context will automatically be included when openAssistant is called from dashboard pages
|
|
120
|
+
openAssistant({
|
|
121
|
+
prompt: 'Help me analyze this dashboard'
|
|
122
|
+
// Current context is automatically included
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Clean up when no longer needed
|
|
126
|
+
setContext.unregister();
|
|
127
|
+
```
|
|
128
|
+
|
|
87
129
|
### Creating Context Items
|
|
88
130
|
|
|
89
131
|
The `createContext` function allows you to create structured context items that provide the assistant with additional information about your Grafana resources.
|
|
@@ -230,6 +272,36 @@ Creates a context item that can be passed to the assistant to provide additional
|
|
|
230
272
|
|
|
231
273
|
**Returns:** A `ChatContextItem` that can be passed to `openAssistant`
|
|
232
274
|
|
|
275
|
+
#### `providePageContext(urlPattern: string | RegExp, initialContext: ChatContextItem[]): ((context: ChatContextItem[]) => void) & { unregister: () => void }`
|
|
276
|
+
|
|
277
|
+
Registers context items for specific pages based on URL patterns. Returns a setter function to update the context dynamically, similar to `useState`. The context will be automatically included when the assistant is opened on pages matching the pattern.
|
|
278
|
+
|
|
279
|
+
**Parameters:**
|
|
280
|
+
- `urlPattern` - URL pattern (string with wildcards or RegExp) to match against page URLs
|
|
281
|
+
- String patterns support `*` (match any characters) and `**` (match any path segments)
|
|
282
|
+
- RegExp patterns provide full regex matching capabilities
|
|
283
|
+
- `initialContext` - Initial array of `ChatContextItem` to provide when the pattern matches
|
|
284
|
+
|
|
285
|
+
**Returns:** A setter function to update the context, with an `unregister` method attached for cleanup
|
|
286
|
+
|
|
287
|
+
**Examples:**
|
|
288
|
+
```typescript
|
|
289
|
+
// String patterns - returns setter function
|
|
290
|
+
const setDashboardContext = providePageContext('/d/*', initialContext); // Match any dashboard
|
|
291
|
+
const setExploreContext = providePageContext('/explore**', initialContext); // Match explore and subpaths
|
|
292
|
+
|
|
293
|
+
// RegExp patterns
|
|
294
|
+
const setSpecificContext = providePageContext(/^\/d\/[a-zA-Z0-9]+$/, initialContext); // Match specific dashboard format
|
|
295
|
+
|
|
296
|
+
// Update context dynamically
|
|
297
|
+
setDashboardContext([...newContext]);
|
|
298
|
+
|
|
299
|
+
// Cleanup when done
|
|
300
|
+
setDashboardContext.unregister();
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
|
|
233
305
|
### Sidebar Types
|
|
234
306
|
|
|
235
307
|
#### `OpenAssistantProps`
|
|
@@ -238,11 +310,16 @@ Creates a context item that can be passed to the assistant to provide additional
|
|
|
238
310
|
type OpenAssistantProps = {
|
|
239
311
|
prompt?: string;
|
|
240
312
|
context?: ChatContextItem[];
|
|
313
|
+
includePageContext?: boolean;
|
|
241
314
|
};
|
|
242
315
|
```
|
|
243
316
|
|
|
244
317
|
Configuration object for opening the assistant.
|
|
245
318
|
|
|
319
|
+
- `prompt` - Optional initial prompt to display
|
|
320
|
+
- `context` - Optional context items to provide
|
|
321
|
+
- `includePageContext` - Whether to automatically include page context for the current URL (defaults to true)
|
|
322
|
+
|
|
246
323
|
#### `ChatContextItem`
|
|
247
324
|
|
|
248
325
|
```typescript
|
|
@@ -254,6 +331,8 @@ type ChatContextItem = {
|
|
|
254
331
|
|
|
255
332
|
A context item that provides structured information to the assistant.
|
|
256
333
|
|
|
334
|
+
|
|
335
|
+
|
|
257
336
|
### Context Types
|
|
258
337
|
|
|
259
338
|
#### Datasource Context Parameters
|
package/dist/context/index.d.ts
CHANGED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ChatContextItem } from './types';
|
|
2
|
+
export interface PageContextRegistration {
|
|
3
|
+
id: string;
|
|
4
|
+
urlPattern: string | RegExp;
|
|
5
|
+
context: ChatContextItem[];
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Registers context items for specific pages based on URL patterns.
|
|
9
|
+
* Returns a setter function to update the context dynamically, similar to useState.
|
|
10
|
+
*
|
|
11
|
+
* If a registration with the same URL pattern already exists, it will be replaced.
|
|
12
|
+
*
|
|
13
|
+
* @param urlPattern - URL pattern (string or RegExp) to match against page URLs
|
|
14
|
+
* @param initialContext - Initial array of ChatContextItem to provide when the pattern matches
|
|
15
|
+
* @returns A setter function to update the context, with an unregister method attached
|
|
16
|
+
*/
|
|
17
|
+
export declare function providePageContext(urlPattern: string | RegExp, initialContext: ChatContextItem[]): ((context: ChatContextItem[]) => void) & {
|
|
18
|
+
unregister: () => void;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* React hook for providing page context that automatically cleans up on unmount.
|
|
22
|
+
* This is the recommended way to use page context in React components.
|
|
23
|
+
*
|
|
24
|
+
* @param urlPattern - URL pattern (string or RegExp) to match against page URLs
|
|
25
|
+
* @param initialContext - Initial array of ChatContextItem to provide when the pattern matches
|
|
26
|
+
* @returns A setter function to update the context
|
|
27
|
+
*/
|
|
28
|
+
export declare function useProvidePageContext(urlPattern: string | RegExp, initialContext?: ChatContextItem[]): (context: ChatContextItem[]) => void;
|
|
29
|
+
export declare function usePageContext(): ChatContextItem[];
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { createContext, DashboardNodeData, DatasourceNodeData, FolderNodeData, ItemDataType, LabelNameNodeData, LabelValueNodeData, StructuredNodeData, TreeNode, } from './context/index';
|
|
1
|
+
export { createContext, DashboardNodeData, DatasourceNodeData, FolderNodeData, ItemDataType, LabelNameNodeData, LabelValueNodeData, StructuredNodeData, TreeNode, providePageContext, PageContextRegistration, usePageContext, } from './context/index';
|
|
2
2
|
export * from './functions';
|
|
3
3
|
export * from './hook';
|
|
4
4
|
export * from './plugin';
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(()=>{"use strict";var e,
|
|
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:()=>N,DashboardNodeData:()=>o,DatasourceNodeData:()=>i,FolderNodeData:()=>d,ItemDataType:()=>e,LabelNameNodeData:()=>l,LabelValueNodeData:()=>c,StructuredNodeData:()=>r,closeAssistant:()=>V,createContext:()=>f,getExposeAssistantFunctionsConfig:()=>D,isAssistantAvailable:()=>S,newFunctionNamespace:()=>U,openAssistant:()=>A,providePageContext:()=>y,useAssistant:()=>M,usePageContext:()=>x}),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.id=n(e.id)}formatForLLM(t){return{type:e.Unknown,codeElementIds:t,data:{name:this.params.text}}}}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.dashboardUid=e.dashboardUid,this.dashboardTitle=e.dashboardTitle,this.folderUid=e.folderUid,this.folderTitle=e.folderTitle}formatForLLM(t){return{type:e.Dashboard,codeElementIds:t,data:{name:this.dashboardTitle,dashboardUid:this.dashboardUid,dashboardTitle:this.dashboardTitle,folderUid:this.folderUid,folderTitle:this.folderTitle}}}}class d extends s{constructor(e){super({...e,id:e.folderUid}),this.folderUid=e.folderUid,this.folderTitle=e.folderTitle}formatForLLM(t){return{type:e.DashboardFolder,codeElementIds:t,data:{name:this.folderTitle,folderUid:this.folderUid,folderTitle:this.folderTitle}}}}class i extends s{constructor(e){super({...e,id:e.datasourceUid}),this.datasourceUid=e.datasourceUid,this.datasourceType=e.datasourceType,this.datasourceName=e.datasourceName}formatForLLM(t){return{type:e.Datasource,codeElementIds:t,data:{name:this.datasourceName,uid:this.datasourceUid,type:this.datasourceType}}}}class l extends s{constructor(e){super({...e,id:`${e.datasourceUid}-${e.labelName}`}),this.datasourceUid=e.datasourceUid,this.datasourceType=e.datasourceType,this.labelName=e.labelName}formatForLLM(t){return{type:e.LabelName,codeElementIds:t,data:{name:this.labelName,datasourceUid:this.datasourceUid,datasourceType:this.datasourceType,labelName:this.labelName}}}}class c extends s{constructor(e){super({...e,id:`${e.datasourceUid}-${e.labelName}-${e.labelValue}`}),this.datasourceUid=e.datasourceUid,this.datasourceType=e.datasourceType,this.labelName=e.labelName,this.labelValue=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}}}}const u={[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 i(t);case"label_name":return new l(t);case"label_value":return new c(t);case"dashboard":return new o(t);case"dashboard_folder":return new d(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),icon:null!==(n=t.icon)&&void 0!==n?n:u[e],navigable:!1,selectable:!0,data:f},occurrences:[]}}const h=require("@grafana/runtime"),b=require("react"),m=[],v="grafana-assistant:page-context-sync",w="grafana-assistant:page-context-update",g="grafana-assistant:page-context-remove",L="grafana-assistant:location-changed";let E=!1;function y(e,t){const a=m.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=m[a],n.context=[...t]):(n={id:`page-context-${Date.now()}-${Math.random().toString(36).substr(2,9)}`,urlPattern:e,context:[...t]},m.push(n)),window.dispatchEvent(new CustomEvent(w,{detail:n})),window.dispatchEvent(new CustomEvent(v,{detail:{registry:m}}));const s=e=>{const t=m.findIndex((e=>e.id===n.id));-1!==t&&(m[t].context=[...e],window.dispatchEvent(new CustomEvent(w,{detail:m[t]})))};return s.unregister=()=>{const e=m.findIndex((e=>e.id===n.id));-1!==e&&(m.splice(e,1),window.dispatchEvent(new CustomEvent(g,{detail:{id:n.id}})))},s}function x(){const[e,t]=(0,b.useState)([]),a=(0,h.useLocationService)(),n=(0,b.useRef)("");return(0,b.useEffect)((()=>{const e=()=>{const e=function(e,t){if(!e)return[];const a=[];for(const n of t)T(e,n.urlPattern)&&a.push(...n.context);return a}(a.getLocation().pathname,m);t(e)},s=()=>{e()},r=t=>{var n;const s=null===(n=t.detail)||void 0===n?void 0:n.pathname;s&&s===a.getLocation().pathname&&e()},o=a.getLocationObservable().subscribe((t=>{const a=t.pathname;a!==n.current&&(n.current=a,function(e){window.dispatchEvent(new CustomEvent(L,{detail:{pathname:e}}))}(a),e())}));return e(),window.addEventListener(v,s),window.addEventListener(w,s),window.addEventListener(g,s),window.addEventListener(L,r),()=>{o.unsubscribe(),window.removeEventListener(v,s),window.removeEventListener(w,s),window.removeEventListener(g,s),window.removeEventListener(L,r)}}),[a]),e}function T(e,t){if(t instanceof RegExp)return t.test(e);if("string"==typeof t){const a=t.replace(/\*\*/g,".*").replace(/\*/g,"[^/]*").replace(/\?/g,".");return new RegExp(`^${a}$`).test(e)}return!1}E||(window.addEventListener(v,(e=>{var t;const a=null===(t=e.detail)||void 0===t?void 0:t.registry;if(a){const e=new Set(m.map((e=>e.id))),t=a.filter((t=>!e.has(t.id)));m.push(...t)}})),window.addEventListener(w,(e=>{const t=e.detail;if(t){const e=m.findIndex((e=>e.id===t.id));-1!==e?m[e]=t:m.push(t)}})),window.addEventListener(g,(e=>{var t;const a=null===(t=e.detail)||void 0===t?void 0:t.id;if(a){const e=m.findIndex((e=>e.id===a));-1!==e&&m.splice(e,1)}})),E=!0);const N="grafana-assistant-app/callback/v0-alpha";function U(e,t){return{namespace:e,functions:t}}function D(e){return{title:"callback",targets:[N],fn:()=>e.map((e=>({namespace:e.namespace,functions:e.functions})))}}const I=require("rxjs");function S(){return(0,h.getObservablePluginLinks)({extensionPointId:"grafana/extension-sidebar/v0-alpha"}).pipe((0,I.map)((e=>e.some((e=>"grafana-assistant-app"===e.pluginId&&"Grafana Assistant"===e.title)))))}const C=require("@grafana/data");class F extends C.BusEventWithPayload{}F.type="open-extension-sidebar";class P extends C.BusEventBase{}function A(e){!function(e,t,a){const n=new F({pluginId:"grafana-assistant-app",componentTitle:"Grafana Assistant",props:a});(0,h.getAppEvents)().publish(n)}(0,0,{initialPrompt:e.prompt,initialContext:e.context})}function V(){!function(){const e=new P;(0,h.getAppEvents)().publish(e)}()}function M(){const[e,t]=(0,b.useState)(!1);return(0,b.useEffect)((()=>{const e=S().subscribe((e=>t(e)));return()=>{e.unsubscribe()}}),[]),[e,e?A:void 0,e?V:void 0]}P.type="close-extension-sidebar",module.exports=a})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@grafana/assistant",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.9",
|
|
4
4
|
"description": "Type definitions and helper functions for Grafana Assistant",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -9,10 +9,9 @@
|
|
|
9
9
|
],
|
|
10
10
|
"scripts": {
|
|
11
11
|
"prebuild": "rm -rf dist",
|
|
12
|
-
"build:dev": "webpack --config webpack.config.cjs --mode development && tsc --emitDeclarationOnly",
|
|
13
12
|
"build": "webpack --config webpack.config.cjs --mode production && tsc --emitDeclarationOnly",
|
|
14
|
-
"
|
|
15
|
-
"
|
|
13
|
+
"dev": "webpack --config webpack.config.cjs --mode development",
|
|
14
|
+
"clean": "rm -rf dist"
|
|
16
15
|
},
|
|
17
16
|
"keywords": [
|
|
18
17
|
"grafana",
|
|
@@ -25,7 +24,7 @@
|
|
|
25
24
|
"dependencies": {},
|
|
26
25
|
"devDependencies": {
|
|
27
26
|
"react": "18.3.1",
|
|
28
|
-
"rxjs": "7.8.
|
|
27
|
+
"rxjs": "7.8.2",
|
|
29
28
|
"ts-loader": "^9.0.0",
|
|
30
29
|
"typescript": "^5.0.0",
|
|
31
30
|
"webpack": "^5.0.0",
|
|
@@ -37,9 +36,9 @@
|
|
|
37
36
|
"peerDependencies": {
|
|
38
37
|
"react": ">=18.0.0",
|
|
39
38
|
"rxjs": ">=7.0.0",
|
|
40
|
-
"@grafana/data": ">=12.
|
|
41
|
-
"@grafana/runtime": ">=12.
|
|
39
|
+
"@grafana/data": ">=12.1.0",
|
|
40
|
+
"@grafana/runtime": ">=12.1.0",
|
|
42
41
|
"@grafana/scenes": ">=5.41.0",
|
|
43
|
-
"@grafana/ui": ">=12.
|
|
42
|
+
"@grafana/ui": ">=12.1.0"
|
|
44
43
|
}
|
|
45
44
|
}
|