### Install Frontend Dependencies Source: https://github.com/grafana/grafana-llm-app/blob/main/README.md Installs all necessary frontend dependencies for the project. Run this from the root directory. ```bash npm install ``` -------------------------------- ### Install Grafana LLM App using Grafana CLI Source: https://github.com/grafana/grafana-llm-app/blob/main/packages/grafana-llm-app/README.md Install the LLM app directly using the Grafana CLI command. ```sh grafana cli plugins install grafana-llm-app ``` -------------------------------- ### Curl Example for Vector Search Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/http-endpoints.md Command-line example using curl to send a POST request to the vector search endpoint. Demonstrates setting headers and the JSON payload. ```bash curl -X POST \ http://localhost:3000/api/plugins/grafana-llm-app/resources/vector/search \ -H "Content-Type: application/json" \ -d '{ "collection": "dashboards", "query": "CPU metrics", "topK": 5 }' ``` -------------------------------- ### Install Grafana LLM App Go Client Source: https://github.com/grafana/grafana-llm-app/blob/main/llmclient/README.md Use this command to add the LLM client library to your Go project. ```bash go get github.com/grafana/grafana-llm-app/llmclient ``` -------------------------------- ### Install Grafana LLM App using Environment Variable Source: https://github.com/grafana/grafana-llm-app/blob/main/packages/grafana-llm-app/README.md Use the GF_INSTALL_PLUGINS environment variable to install the LLM app when running Grafana. ```sh GF_INSTALL_PLUGINS=grafana-llm-app ``` -------------------------------- ### Secure Data Example (Frontend) Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/configuration-and-settings.md This example demonstrates how secure data fields are represented. Note that these are not exposed to frontend code and are only accessible by the backend. ```typescript // These are NOT exposed to frontend code; only backend can access const secureData = { openAIKey: "sk-...", ``` ```typescript anthropicKey: "sk-ant-...", ``` ```typescript base64EncodedAccessToken: "..." } ``` -------------------------------- ### Tool Use and Function Calling Example Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/usage-patterns-and-examples.md This TypeScript example shows how to define and execute tools for an LLM. It includes a `ToolExecutor` class that manages tool definitions and handles function calls generated by the model. Use this pattern when your LLM needs to interact with external APIs or perform specific actions. ```typescript import { llm } from "@grafana/llm"; interface ToolResult { toolCallId: string; result: any; } class ToolExecutor { private tools: { [name: string]: (args: any) => Promise } = { search: async (args) => { const { query } = args; return { results: [ { id: "1", title: `Result for ${query}` } ] }; }, getMetric: async (args) => { const { metric, time_range } = args; return { metric, value: 42, unit: "requests/sec" }; } }; async executeToolCall(toolCall: llm.ToolCall): Promise { const fn = this.tools[toolCall.function.name]; if (!fn) { throw new Error(`Unknown tool: ${toolCall.function.name}`); } const args = JSON.parse(toolCall.function.arguments); const result = await fn(args); return { toolCallId: toolCall.id, result }; } async runConversationWithTools( userMessage: string ): Promise { const messages: llm.Message[] = [ { role: "user", content: userMessage } ]; const tools: llm.Tool[] = [ { type: "function", function: { name: "search", description: "Search for information", parameters: { type: "object", properties: { query: { type: "string" } }, required: ["query"] } } }, { type: "function", function: { name: "getMetric", description: "Get a metric value", parameters: { type: "object", properties: { metric: { type: "string" }, time_range: { type: "string" } }, required: ["metric"] } } } ]; // Loop until model finishes (doesn't call a tool) while (true) { const response = await llm.chatCompletions({ model: llm.Model.BASE, messages, tools }); const choice = response.choices[0]; if (!choice.message.tool_calls) { // Model finished without calling tools return choice.message.content || ""; } // Execute tool calls const toolResults: llm.Message[] = []; for (const toolCall of choice.message.tool_calls) { const { toolCallId, result } = await this.executeToolCall(toolCall); toolResults.push({ role: "tool", tool_call_id: toolCallId, content: JSON.stringify(result) }); } // Add assistant message and tool results to conversation messages.push(choice.message); messages.push(...toolResults); } } } // Usage const executor = new ToolExecutor(); const result = await executor.runConversationWithTools( "Search for GPU metrics and tell me the current usage" ); console.log(result); ``` -------------------------------- ### Vector Search Request Example Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/http-endpoints.md Example JSON payload for the POST /vector/search endpoint. Specify collection, query, and optionally topK and filters. ```json { "collection": "dashboards", "query": "CPU usage trends", "topK": 5, "filter": { "environment": { "$eq": "production" } } } ``` -------------------------------- ### Spin Up Grafana Instance with Plugin Source: https://github.com/grafana/grafana-llm-app/blob/main/README.md Starts a Grafana instance using Docker and runs the plugin within it. This command is executed from the root directory. ```bash npm run server ``` -------------------------------- ### OpenAI Configuration Example Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/configuration-and-settings.md Configuration block for OpenAI, Azure OpenAI, or custom OpenAI-compatible providers. Includes URL, API path, and model mapping for Azure. ```json { "openAI": { "url": "https://api.openai.com", "apiPath": "/v1", "organizationId": "", "provider": "openai", "azureModelMapping": [["base", "gpt-4-turbo-mini"]], "disabled": false } } ``` -------------------------------- ### Provider Field Example Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/configuration-and-settings.md Example of setting the LLM provider to 'anthropic'. Use this field to select the LLM service. ```json { "provider": "anthropic" } ``` -------------------------------- ### Example Search Filters Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/vector-api-reference.md Illustrates how to construct metadata filters for vector search queries using common operators like $eq and $in. ```typescript { metric_type: { $eq: "histogram" } } ``` ```typescript { severity: { $in: ["critical", "warning"] } } ``` -------------------------------- ### Configure Vector Database and Embeddings Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/configuration-and-settings.md Enable vector search functionality and configure embedding models and vector stores. This example shows Qdrant as the vector store and OpenAI for embeddings. ```json { "vector": { "enabled": true, "model": "text-embedding-3-small", "embed": { "type": "openai", "openAI": { "url": "https://api.openai.com", "authType": "openai-key-auth" } }, "store": { "type": "qdrant", "qdrant": { "address": "http://localhost:6334", "collectionPrefix": "grafana" } } } } ``` ```json { "vector": { "enabled": true, "model": "text-embedding-3-small", "embed": { "type": "openai", "openAI": { "url": "https://api.openai.com", "authType": "openai-key-auth" } }, "store": { "type": "qdrant", "qdrant": { "address": "http://qdrant:6334", "collectionPrefix": "grafana" } } } } ``` -------------------------------- ### Example MCP Request (HTTP) Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/http-endpoints.md An example of a JSON-RPC 2.0 request sent to the MCP server over an HTTP stream. This request is used to list available tools. ```json { "jsonrpc": "2.0", "id": 1, "method": "tools/list" } ``` -------------------------------- ### Example MCP Response (HTTP) Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/http-endpoints.md An example JSON-RPC 2.0 response from the MCP server, detailing the available tools. This response structure is used when a 'tools/list' method is called. ```json { "jsonrpc": "2.0", "id": 1, "result": { "tools": [ { "name": "search", "description": "Search Grafana resources", "inputSchema": { "type": "object", "properties": { "query": { "type": "string" } } } } ] } } ``` -------------------------------- ### Azure OpenAI Model Mapping Example Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/configuration-and-settings.md Example of Azure OpenAI model mapping within the 'openAI' configuration section. Maps abstract model names to Azure deployment names. ```json { "openAI": { "azureModelMapping": [ ["base", "gpt-4-turbo-mini"], ["large", "gpt-4-turbo"] ] } } ``` -------------------------------- ### Vector Search Filter Syntax Example Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/http-endpoints.md Example JSON for specifying metadata filters in a vector search request. Supports operators like $eq, $gte, and $contains. ```json { "filter": { "status": { "$eq": "active" }, "priority": { "$gte": 5 }, "tags": { "$contains": "production" } } } ``` -------------------------------- ### Vector Search Response Example Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/http-endpoints.md Example JSON response for a successful vector search. Contains a list of results, each with a payload and a similarity score. ```json { "results": [ { "payload": { "dashboardId": "123", "name": "CPU Metrics", "description": "CPU usage over time" }, "score": 0.95 }, { "payload": { "dashboardId": "456", "name": "System Health", "description": "Overall system health including CPU" }, "score": 0.87 } ] } ``` -------------------------------- ### Get Available Tools with MCP Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/mcp-api-reference.md Retrieve the list of available tools using the MCP client. This is a prerequisite for using tools with an LLM. ```typescript const { client } = mcp.useMCPClient(); const tools = await client.listTools(); ``` -------------------------------- ### Interactive Development Workflow Source: https://github.com/grafana/grafana-llm-app/blob/main/packages/grafana-llm-app/TESTING.md Starts Grafana and the Playwright server for interactive development. Tests are run in a separate terminal against the running server. ```bash npm run test:e2e-dev # In another terminal, run tests against the server npm run playwright:test # Stop everything npm run playwright:stop && npm run server:down ``` -------------------------------- ### Streaming Chat Completions with @grafana/llm Source: https://github.com/grafana/grafana-llm-app/blob/main/packages/grafana-llm-app/README.md Example of using the `@grafana/llm` package to stream chat completions from OpenAI. It demonstrates setting up the component, handling loading states, and subscribing to the stream to update the UI. ```typescript import React, { useState } from 'react'; import { useAsync } from 'react-use'; import { llms } from '@grafana/llm'; import { PluginPage } from '@grafana/runtime'; import { Button, Input, Spinner } from '@grafana/ui'; const MyComponent = (): JSX.Element => { const [input, setInput] = React.useState(''); const [message, setMessage] = React.useState(''); const [reply, setReply] = useState(''); const { loading, error } = useAsync(async () => { const enabled = await llms.openai.enabled(); if (!enabled) { return false; } if (message === '') { return; } // Stream the completions. Each element is the next stream chunk. const stream = llms.openai .streamChatCompletions({ model: llms.openai.Model.BASE, messages: [ { role: 'system', content: 'You are a helpful assistant with deep knowledge of the Grafana, Prometheus and general observability ecosystem.' }, { role: 'user', content: message }, ], }) .pipe(llms.openai.accumulateContent()); // Subscribe to the stream and update the state for each returned value. return stream.subscribe(setReply); }, [message]); if (error) { // TODO: handle errors. return null; } return (
setInput(e.currentTarget.value)} placeholder="Enter a message" />

{loading ? : reply}
); }; ``` -------------------------------- ### Use OpenAI Stream Chat Completions Source: https://github.com/grafana/grafana-llm-app/blob/main/packages/grafana-llm-app/src/README.md This example demonstrates how to use the `@grafana/llm` package to stream chat completions from OpenAI. It includes checking if OpenAI is enabled, sending a user message, and accumulating the streamed response. ```typescript import React, { useState } from 'react'; import { useAsync } from 'react-use'; import { scan } from 'rxjs/operators'; import { llms } from '@grafana/llm'; import { PluginPage } from '@grafana/runtime'; import { Button, Input, Spinner } from '@grafana/ui'; const MyComponent = (): JSX.Element => { const [input, setInput] = React.useState(''); const [message, setMessage] = React.useState(''); const [reply, setReply] = useState(''); const { loading, error } = useAsync(async () => { const enabled = await llms.openai.enabled(); if (!enabled) { return false; } if (message === '') { return; } // Stream the completions. Each element is the next stream chunk. const stream = llms.openai .streamChatCompletions({ model: llms.openai.Model.BASE, messages: [ { role: 'system', content: 'You are a helpful assistant with deep knowledge of the Grafana, Prometheus and general observability ecosystem.' }, { role: 'user', content: message }, ], }) .pipe( // Accumulate the stream chunks into a single string. scan((acc, delta) => acc + delta, '') ); // Subscribe to the stream and update the state for each returned value. return stream.subscribe(setReply); }, [message]); if (error) { // TODO: handle errors. return null; } return (
setInput(e.currentTarget.value)} placeholder="Enter a message" />

{loading ? : reply}
); }; ``` -------------------------------- ### Anthropic Configuration Example Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/configuration-and-settings.md Configuration block for the Anthropic Claude API. Specifies the API endpoint URL. ```json { "anthropic": { "url": "https://api.anthropic.com" } } ``` -------------------------------- ### Manual Testing Workflow Source: https://github.com/grafana/grafana-llm-app/blob/main/packages/grafana-llm-app/TESTING.md Steps for manual testing during development. Starts Grafana in the background, runs tests in a Docker container, and then stops Grafana. ```bash npm run server:detach # Run tests in Docker container npm run playwright:run # Clean up npm run server:down ``` -------------------------------- ### Quick Start: Chat Completion with Grafana LLM App Client Source: https://github.com/grafana/grafana-llm-app/blob/main/llmclient/README.md Initialize the client with your Grafana URL and service account token, check provider availability, and make a chat completion request. Ensure your LLM provider is enabled and configured in the Grafana LLM App. ```go package main import ( "context" "fmt" "log" "github.com/grafana/grafana-llm-app/llmclient" "github.com/sashabaranov/go-openai" ) func main() { // Initialize client with Grafana URL and service account token client := llmclient.NewLLMProvider( "https://your-grafana-instance.com", "your-service-account-token", ) ctx := context.Background() // Check if LLM provider is available enabled, err := client.Enabled(ctx) if err != nil { log.Fatal(err) } if !enabled { log.Fatal("LLM provider is not enabled or configured") } // Make a chat completion request req := llmclient.ChatCompletionRequest{ ChatCompletionRequest: openai.ChatCompletionRequest{ Messages: []openai.ChatCompletionMessage{ {Role: "user", Content: "Hello, how are you?"}, }, }, Model: llmclient.ModelBase, } resp, err := client.ChatCompletions(ctx, req) if err != nil { log.Fatal(err) } fmt.Println(resp.Choices[0].Message.Content) } ``` -------------------------------- ### Curl Request for Chat Completions Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/http-endpoints.md Example using curl to send a POST request to the chat completions endpoint. Ensure to set the Content-Type header and provide the request body as JSON. ```bash curl -X POST \ http://localhost:3000/api/plugins/grafana-llm-app/resources/llm/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "base", "messages": [ {"role": "user", "content": "Hello"} ] }' ``` -------------------------------- ### Run End-to-End Tests (Playwright) Source: https://github.com/grafana/grafana-llm-app/blob/main/README.md Executes end-to-end tests using Playwright. This command builds the plugin, starts Docker containers, runs tests, and cleans up afterwards. The workspace must be built first. ```bash npm run test:e2e ``` -------------------------------- ### Build Frontend in Production Mode Source: https://github.com/grafana/grafana-llm-app/blob/main/README.md Builds the frontend plugin in production mode, optimized for deployment. Run this command from the root directory. ```bash npm run build ``` -------------------------------- ### Build Frontend in Development Mode Source: https://github.com/grafana/grafana-llm-app/blob/main/README.md Builds the frontend plugin in development mode and enables watch mode for live updates. Execute from the root directory. ```bash npm run dev ``` -------------------------------- ### Vector Search Error Response Example Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/http-endpoints.md Example JSON error response when the specified collection is not found in the vector store. ```json { "error": "collection dashboards not found in store" } ``` -------------------------------- ### Build Backend Plugin Binaries Source: https://github.com/grafana/grafana-llm-app/blob/main/README.md Builds the backend plugin binaries for Linux, Windows, and Darwin. This command should be executed from the root directory. ```bash npm run backend:build ``` -------------------------------- ### Client Initialization Source: https://github.com/grafana/grafana-llm-app/blob/main/llmclient/README.md Demonstrates how to initialize the LLM provider client using Grafana URL and a service account token. ```APIDOC ## Client Initialization ### Description Creates a new LLM provider client. ### Method `NewLLMProvider(grafanaURL, serviceAccountToken string) LLMProvider` ### Endpoint N/A (Client-side function) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```go client := llmclient.NewLLMProvider( "https://grafana.example.com", "your-service-account-token-here", ) ``` ### Response #### Success Response (200) `LLMProvider` object #### Response Example N/A (Client-side object creation) ``` ```APIDOC ## Client Initialization with Custom HTTP Client ### Description Creates a client with a custom HTTP client for advanced configuration. ### Method `NewLLMProviderWithClient(grafanaURL, serviceAccountToken string, httpClient *http.Client) LLMProvider` ### Endpoint N/A (Client-side function) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```go httpClient := &http.Client{ Timeout: time.Minute * 5, } client := llmclient.NewLLMProviderWithClient( "https://grafana.example.com", "your-service-account-token-here", httpClient, ) ``` ### Response #### Success Response (200) `LLMProvider` object #### Response Example N/A (Client-side object creation) ``` -------------------------------- ### Disabled Field Example Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/configuration-and-settings.md Example of disabling all LLM functionality by setting the 'disabled' field to true. This is useful for temporarily turning off LLM features. ```json { "disabled": false } ``` -------------------------------- ### Provisioning Qdrant Vector Store Source: https://github.com/grafana/grafana-llm-app/blob/main/packages/grafana-llm-app/README.md Configure global and store vector settings to use Qdrant as a vector store. Requires specifying the Qdrant server address and whether to use a secure connection. ```yaml enabled model store: type: qdrant qdrant: address: secure: ``` -------------------------------- ### Advanced Configuration - Custom HTTP Client Source: https://github.com/grafana/grafana-llm-app/blob/main/llmclient/README.md Demonstrates how to configure a custom HTTP client for production use, including timeouts and retry logic. ```APIDOC ## Custom HTTP Client Configuration ### Description For production use, you may want to configure timeouts, retry logic, or other HTTP client settings. ### Code Example ```go import ( "net/http" "time" "github.com/grafana/grafana-llm-app/pkg/llmclient" ) // Configure custom HTTP client httpClient := &http.Client{ Timeout: time.Minute * 2, Transport: &http.Transport{ MaxIdleConns: 100, MaxIdleConnsPerHost: 10, IdleConnTimeout: time.Minute, }, } // Initialize LLM provider with custom client client := llmclient.NewLLMProviderWithClient( "https://grafana.example.com", "service-account-token", httpClient, ) ``` ``` -------------------------------- ### Integrate and Use MCP Tools in LLM Requests Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/usage-patterns-and-examples.md This snippet demonstrates how to set up the MCP client provider, list available MCP tools, convert them to OpenAI format, and make LLM requests that can utilize these tools. It also shows how to handle tool calls and their results. ```typescript import { llm, mcp } from "@grafana/llm"; import { Suspense } from "react"; function ChatWithTools() { return ( Loading MCP tools...}> ); } async function ChatUI() { const { client } = mcp.useMCPClient(); const handleRequest = async (userMessage: string) => { if (!client) { console.log("MCP not available"); return; } // Get available tools const mcpTools = await client.listTools(); const openaiTools = mcp.convertToolsToOpenAI(mcpTools); // Make request with tools const response = await llm.chatCompletions({ model: llm.Model.BASE, messages: [{ role: "user", content: userMessage }], tools: openaiTools }); const message = response.choices[0].message; // Check if model wants to call a tool if (message.tool_calls) { for (const toolCall of message.tool_calls) { const args = JSON.parse(toolCall.function.arguments); const result = await client.callTool( toolCall.function.name, args ); // Handle tool result console.log(`Tool ${toolCall.function.name} returned:`, result); } } else if (message.content) { console.log("Assistant:", message.content); } }; return (
); } ``` -------------------------------- ### Initialize MCP Client Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/mcp-api-reference.md Wrap your application with MCPClientProvider to initialize the MCP client. Provide your application's name and version. ```typescript ``` -------------------------------- ### Get Plugin Settings Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/http-endpoints.md Retrieves the current configuration and enabled status of the Grafana LLM plugin. ```APIDOC ## GET /api/plugins/grafana-llm-app/settings ### Description Get the plugin's current configuration and enabled status. ### Method GET ### Endpoint /api/plugins/grafana-llm-app/settings ### Response #### Success Response (200) - **enabled** (boolean) - Whether plugin is enabled - **jsonData** (object) - Plugin configuration (public fields only) ### Response Example ```json { "enabled": true, "jsonData": { "provider": "openai", "models": { "default": "base", "mapping": { "base": "gpt-4-turbo-mini", "large": "gpt-4-turbo" } }, "mcp": { "disabled": false } } } ``` ### Status Codes - `200` — Success - `404` — Plugin not found ``` -------------------------------- ### Backend: Load Settings Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/configuration-and-settings.md Load application settings in the backend. Handles potential errors during loading and provides access to configured settings. ```go settings, err := loadSettings(appSettings) if err != nil { return nil, err } // Access settings provider := settings.getEffectiveProvider() if settings.OpenAI.apiKey != "" { // OpenAI configured } ``` -------------------------------- ### GrafanaResourcePayload Interface Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/types-reference.md An example of extending SearchResultPayload for Grafana-specific resources. It includes resource type, ID, and name. ```typescript interface GrafanaResourcePayload extends vector.SearchResultPayload { resourceType: "dashboard" | "panel" | "alert"; resourceId: string; name: string; } ``` -------------------------------- ### Provisioning OpenAI API Key Source: https://github.com/grafana/grafana-llm-app/blob/main/packages/grafana-llm-app/README.md Configure the LLM app to use OpenAI by setting the API key via an environment variable and using a provisioning file. ```sh OPENAI_API_KEY=sk-... ``` ```yaml apiVersion: 1 apps: - type: 'grafana-llm-app' disabled: false jsonData: openAI: url: https://api.openai.com secureJsonData: openAIKey: $OPENAI_API_KEY ``` -------------------------------- ### Restart Grafana Container Source: https://github.com/grafana/grafana-llm-app/blob/main/packages/grafana-llm-app/TESTING.md If Grafana is not starting, check its logs and then rebuild and restart the container. This is useful for resolving startup issues. ```bash # Check Grafana logs docker compose logs grafana # Rebuild Grafana container docker compose up --build -d ``` -------------------------------- ### Test Backend Plugin Source: https://github.com/grafana/grafana-llm-app/blob/main/README.md Runs tests for the backend plugin. Ensure you are in the root directory when executing this command. ```bash npm run backend:test ``` -------------------------------- ### Docker Compose Grafana Service Source: https://github.com/grafana/grafana-llm-app/blob/main/packages/grafana-llm-app/TESTING.md Defines the main Grafana instance within the Docker Compose setup, with the plugin mounted. ```yaml services: grafana: # Main Grafana instance with plugin mounted ``` -------------------------------- ### OpenAI Embedder + Qdrant Store Configuration Source: https://github.com/grafana/grafana-llm-app/blob/main/packages/grafana-llm-app/README.md Set up the LLM app with OpenAI for embeddings and Qdrant for data storage. Specify the OpenAI provider details and the Qdrant address. ```yaml apiVersion: 1 apps: - type: grafana-llm-app jsonData: openAI: provider: openai url: https://api.openai.com organizationId: $OPENAI_ORGANIZATION_ID vector: enabled: true model: text-embedding-ada-002 embed: type: openai store: type: qdrant qdrant: address: # e.g. localhost:6334 secureJsonData: openAIKey: $OPENAI_API_KEY ``` -------------------------------- ### Check if MCP is Enabled Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/mcp-api-reference.md Use this function to determine if the Grafana LLM app is installed and MCP is ready before creating an MCP client. ```typescript import { mcp } from "@grafana/llm"; if (await mcp.enabled()) { // Safe to create an MCP client } ``` -------------------------------- ### New Provider Configuration Format Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/configuration-and-settings.md Shows the current top-level 'provider' setting. This format takes precedence over nested provider settings. ```json { "provider": "azure" } ``` -------------------------------- ### Create LLM Provider Client with Custom HTTP Client Source: https://github.com/grafana/grafana-llm-app/blob/main/llmclient/README.md Create a client with a custom HTTP client for advanced configuration, such as setting a timeout. This allows for more control over the underlying HTTP requests. ```go httpClient := &http.Client{ Timeout: time.Minute * 5, } client := llmclient.NewLLMProviderWithClient( "https://grafana.example.com", "your-service-account-token-here", httpClient, ) ``` -------------------------------- ### Run Frontend Tests (Jest) Source: https://github.com/grafana/grafana-llm-app/blob/main/README.md Runs frontend tests using Jest. Requires 'git init' to be run first. This command watches for changes. ```bash npm run test ``` -------------------------------- ### Define Test IDs for Components Source: https://github.com/grafana/grafana-llm-app/blob/main/packages/grafana-llm-app/TESTING.md Example of defining test IDs in a 'testIds.ts' file to be used for locating UI elements in Playwright tests. ```typescript // Add to testIds.ts export const testIds = { myFeature: { container: 'data-testid my-feature-container', button: 'data-testid my-feature-button' } }; ``` -------------------------------- ### Create LLM Provider Client Source: https://github.com/grafana/grafana-llm-app/blob/main/llmclient/README.md Instantiate the LLM client using your Grafana instance URL and a service account token. ```go client := llmclient.NewLLMProvider( "https://grafana.example.com", "your-service-account-token-here", ) ``` -------------------------------- ### Old Provider Configuration Format Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/configuration-and-settings.md Illustrates the previous format where the provider was nested under 'openAI'. This format is supported for backward compatibility. ```json { "openAI": { "provider": "azure" } } ``` -------------------------------- ### enabled Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/mcp-api-reference.md Checks if the Grafana LLM app is installed and MCP is enabled. This function should be called before attempting to create an MCP client to ensure the environment is ready. ```APIDOC ## Function: enabled ### Description Check if the Grafana LLM app is installed and MCP is enabled. ### Returns `Promise` — true if MCP is enabled and ready ### Example ```typescript import { mcp } from "@grafana/llm"; if (await mcp.enabled()) { // Safe to create an MCP client } ``` ``` -------------------------------- ### Configure MCP Toolsets Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/configuration-and-settings.md Configure the Model Context Protocol (MCP) server, including enabling or disabling specific toolsets. Toolsets can be enabled with `true` or `null`, and disabled with `false`. ```json { "mcp": { "disabled": false, "toolsets": { "search": true, "datasource": true, "incident": true, "prometheus": null, "loki": false, "alerting": null, "dashboard": true, "oncall": null, "asserts": null, "sift": null, "pyroscope": null, "navigation": true, "annotations": null, "rendering": null, "admin": false, "clickhouse": null, "cloudwatch": null, "elasticsearch": null, "examples": null, "searchlogs": null, "folder": null } } } ``` -------------------------------- ### Error Response Example Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/http-endpoints.md This JSON structure indicates an error occurred, such as a missing API key configuration. The 'error' field provides a description of the issue. ```json { "error": "OpenAI API key is not configured" } ``` -------------------------------- ### Write Playwright Test Using Test IDs Source: https://github.com/grafana/grafana-llm-app/blob/main/packages/grafana-llm-app/TESTING.md An example of a Playwright test that navigates to a page and asserts the visibility of an element using its test ID. ```typescript test('my feature works', async ({ page }) => { await page.goto('/a/grafana-llm-app'); await expect(page.getByTestId('my-feature-container')).toBeVisible(); }); ``` -------------------------------- ### enabled Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/llm-api-reference.md Checks if the LLM provider is both configured and operational, returning a boolean indicating readiness for use. ```APIDOC ## Function: `enabled` ```typescript async function enabled(): Promise ``` Check if the LLM provider is both configured and operational. **Returns:** `Promise` — true if the provider is ready to use ### Request Example ```typescript import { llm } from "@grafana/llm"; if (await llm.enabled()) { // Safe to call chatCompletions or streamChatCompletions } ``` ``` -------------------------------- ### Custom HTTP Client Configuration Source: https://github.com/grafana/grafana-llm-app/blob/main/llmclient/README.md Configure custom HTTP client settings like timeouts and retry logic for production environments. This allows for more robust network handling. ```go httpClient := &http.Client{ Timeout: time.Minute * 2, Transport: &http.Transport{ MaxIdleConns: 100, MaxIdleConnsPerHost: 10, IdleConnTimeout: time.Minute, }, } client := llmclient.NewLLMProviderWithClient( "https://grafana.example.com", "service-account-token", httpClient, ) ``` -------------------------------- ### Provision LLM Provider Configuration Source: https://github.com/grafana/grafana-llm-app/blob/main/CONTRIBUTING.md Example YAML configuration for provisioning a custom LLM provider within Grafana. This includes basic settings and secure credentials. ```yaml apiVersion: 1 apps: - type: 'grafana-llm-app' disabled: false jsonData: provider: myllm myllm: url: https://api.myllm.com secureJsonData: myllmKey: $MYLLM_API_KEY ``` -------------------------------- ### Run End-to-End Tests Source: https://github.com/grafana/grafana-llm-app/blob/main/CONTRIBUTING.md Execute Playwright-based end-to-end tests for the Grafana LLM App. These commands build the plugin, start Docker containers, run tests, and clean up resources. ```bash # Run e2e tests (builds the plugin, starts containers, runs tests, cleans up) npm run test:e2e ``` ```bash # Run e2e tests with full build (same as above but explicitly builds first) npm run test:e2e-full ``` ```bash # Run e2e tests in CI mode (with optimized Docker builds) npm run test:e2e-ci ``` -------------------------------- ### Get Grafana LLM App Settings Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/http-endpoints.md Retrieves the current configuration and enabled status of the Grafana LLM App plugin. This endpoint is useful for checking plugin status and its configured parameters. ```bash curl http://localhost:3000/api/plugins/grafana-llm-app/settings ``` -------------------------------- ### Define Provider Settings in Go Source: https://github.com/grafana/grafana-llm-app/blob/main/CONTRIBUTING.md Define a struct for provider-specific settings in Go. Ensure API keys are handled securely. ```go // MyLLMSettings contains MyLLM-specific settings type MyLLMSettings struct { // The URL to the provider's API URL string `json:"url"` // apiKey is the provider-specific API key needed to authenticate requests // Stored securely. apiKey string } ``` -------------------------------- ### Check and Resolve Port Conflicts Source: https://github.com/grafana/grafana-llm-app/blob/main/packages/grafana-llm-app/TESTING.md Use these commands to identify processes using specific ports and to stop conflicting services. Ensure ports 3000 and 5000 are free before starting services. ```bash # Check what's using port 3000 or 5000 lsof -i :3000 lsof -i :5000 # Stop conflicting services npm run server:down docker stop $(docker ps -q) ``` -------------------------------- ### Chat Completions Response Example Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/http-endpoints.md This JSON structure represents a successful response from the chat completions endpoint. It includes a unique ID, model information, completion choices, and token usage details. ```json { "id": "chatcmpl-8mZhLo5yrQlLBvNfpRdZAjBL", "object": "chat.completion", "created": 1704067200, "model": "gpt-4-turbo", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "2 + 2 equals 4." }, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 24, "completion_tokens": 7, "total_tokens": 31 } } ``` -------------------------------- ### Basic OpenAI Configuration Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/configuration-and-settings.md Configure the LLM app to use OpenAI. This includes specifying the API URL, path, organization ID, and model mappings. ```json { "provider": "openai", "openAI": { "url": "https://api.openai.com", "apiPath": "/v1", "organizationId": "org-xxxxx" }, "models": { "default": "base", "mapping": { "base": "gpt-4-turbo-mini", "large": "gpt-4-turbo" } }, "mcp": { "disabled": false } } ``` -------------------------------- ### List Mage Targets Source: https://github.com/grafana/grafana-llm-app/blob/main/README.md Lists all available Mage targets for additional backend commands. This command should be run from the ./packages/grafana-llm-app/ directory. ```bash mage -l ``` -------------------------------- ### Chat Completions Request Example Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/http-endpoints.md Use this JSON structure to send a non-streaming chat completions request to the API. It includes model selection, conversation messages, and optional parameters like temperature and tools. ```json { "model": "base", "messages": [ { "role": "system", "content": "You are a helpful assistant." }, { "role": "user", "content": "What is 2+2?" } ], "temperature": 0.7, "max_completion_tokens": 100, "tools": [ { "type": "function", "function": { "name": "calculator", "description": "A calculator function", "parameters": { "type": "object", "properties": { "expression": { "type": "string" } } } } } ] } ``` -------------------------------- ### Mock Backend Service for Health Checks Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/jest-testing-utilities.md Mock the Grafana backend service to test LLM health checks. This involves mocking `getBackendSrv` and its `get` method to return mock settings and health status. ```typescript describe("Health Checks", () => { it("should check if LLM is enabled", async () => { const mockBackend = { get: jest.fn() .mockResolvedValueOnce({ enabled: true }) // settings check .mockResolvedValueOnce({ details: { llmProvider: { configured: true, ok: true }, vector: { enabled: false, ok: false }, version: "1.0.0" } }) }; require("@grafana/runtime").getBackendSrv.mockReturnValue(mockBackend); const enabled = await llm.enabled(); expect(enabled).toBe(true); }); }); ``` -------------------------------- ### Run Linter Source: https://github.com/grafana/grafana-llm-app/blob/main/README.md Runs the linter to check for code style issues. Execute from the root directory. ```bash npm run lint ``` -------------------------------- ### MCP Integration for Tool Ecosystem Access Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/README.md Access Grafana's tool ecosystem through MCP. Use MCPClientProvider to wrap components and use the useMCPClient hook to get the client instance for listing and converting tools. ```typescript // In component: const { client } = mcp.useMCPClient(); const tools = await client.listTools(); const openaiTools = mcp.convertToolsToOpenAI(tools); // Use with LLM const response = await llm.chatCompletions({ messages: [...], tools: openaiTools }); ``` -------------------------------- ### Test Async Operations with Await Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/jest-testing-utilities.md Demonstrates how to test asynchronous functions, specifically 'health' checks, using async/await and Jest mock functions. Ensures that the mock backend's 'get' method is called and its resolved values are correctly asserted. ```typescript describe("Async Operations", () => { it("awaits health checks", async () => { const mockBackend = { get: jest.fn() .mockResolvedValueOnce({ enabled: true }) .mockResolvedValueOnce({ status: "ok", details: { llmProvider: { configured: true, ok: true }, vector: { enabled: true, ok: true }, version: "1.0.0" } }) }; require("@grafana/runtime").getBackendSrv.mockReturnValue(mockBackend); const health = await llm.health(); expect(health.configured).toBe(true); expect(health.ok).toBe(true); }); }); ``` -------------------------------- ### Provisioning Azure OpenAI Source: https://github.com/grafana/grafana-llm-app/blob/main/packages/grafana-llm-app/README.md Configure the LLM app to use Azure OpenAI, including specifying a custom URL and model mappings for different deployments. ```yaml apiVersion: 1 apps: - type: 'grafana-llm-app' disabled: false jsonData: provider: azure openAI: url: https://.openai.azure.com azureModelMapping: - ["base", "gpt-35-turbo"] - ["large", "gpt-4-turbo"] secureJsonData: openAIKey: $OPENAI_API_KEY ``` -------------------------------- ### Backend File Organization Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/README.md Structure of the backend package, detailing Go files for plugin application and services. ```plaintext packages/grafana-llm-app/pkg/plugin/ ├── app.go # Plugin application ├── resources.go # HTTP endpoints ├── stream.go # Streaming support ├── health.go # Health checks ├── settings.go # Configuration (386 lines) ├── llm_provider.go # Provider interface ├── provider.go # Provider factory ├── *_provider.go # Specific providers (OpenAI, Anthropic, Azure, Grafana, Test) └── vector/ # Vector integration ├── service.go # Vector service ├── embed/ # Embedding engines └── store/ # Vector stores (Qdrant) ``` -------------------------------- ### Stream chat completions using @grafana/llm Source: https://github.com/grafana/grafana-llm-app/blob/main/packages/grafana-llm-frontend/README.md This example demonstrates how to stream chat completions from an OpenAI-compatible LLM service within a React component. It uses `openai.streamChatCompletions` and RxJS `scan` operator to accumulate streamed responses. Ensure the LLM service is enabled before making requests. ```typescript import React, { useState } from 'react'; import { useAsync } from 'react-use'; import { scan } from 'rxjs/operators'; import { openai } from '@grafana/llm'; import { PluginPage } from '@grafana/runtime'; import { Button, Input, Spinner } from '@grafana/ui'; const MyComponent = (): JSX.Element => { const [input, setInput] = React.useState(''); const [message, setMessage] = React.useState(''); const [reply, setReply] = useState(''); const { loading, error } = useAsync(async () => { const enabled = await openai.enabled(); if (!enabled) { return false; } if (message === '') { return; } // Stream the completions. Each element is the next stream chunk. const stream = openai .streamChatCompletions({ // model: openai.Model.LARGE, // defaults to BASE, use larger model for longer context and complex tasks messages: [ { role: 'system', content: 'You are a helpful assistant with deep knowledge of the Grafana, Prometheus and general observability ecosystem.' }, { role: 'user', content: message }, ], }) .pipe( // Accumulate the stream chunks into a single string. scan((acc, delta) => acc + delta, '') ); // Subscribe to the stream and update the state for each returned value. return stream.subscribe(setReply); }, [message]); if (error) { // TODO: handle errors. return null; } return (
setInput(e.currentTarget.value)} placeholder="Enter a message" />

{loading ? : reply}
); }; ``` -------------------------------- ### Frontend File Organization Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/README.md Structure of the frontend package, highlighting key files and their purposes. ```plaintext packages/grafana-llm-frontend/src/ ├── index.ts # Main exports ├── llm.ts # Chat completions API (400+ lines) ├── vector.ts # Vector search API ├── mcp.tsx # MCP client integration ├── types.ts # Health check types ├── constants.ts # LLM plugin constants └── jest.ts # Testing utilities ``` -------------------------------- ### Client Class Methods Source: https://github.com/grafana/grafana-llm-app/blob/main/_autodocs/mcp-api-reference.md Methods available on the MCP client instance for interacting with the server, including connecting, listing tools, calling tools, and closing the connection. ```APIDOC ### Class: `Client` Re-exported from `@modelcontextprotocol/sdk/client/index.js`. An MCP client for communicating with the server. **Methods:** - `async connect(transport: Transport): Promise` - `async listTools(cursor?: string): Promise` - `async callTool(name: string, args: any): Promise` - `close(): void` ```