diff --git a/static/app/gettingStartedDocs/javascript-astro/agentMonitoring.tsx b/static/app/gettingStartedDocs/javascript-astro/agentMonitoring.tsx deleted file mode 100644 index 9d844c93f66c96..00000000000000 --- a/static/app/gettingStartedDocs/javascript-astro/agentMonitoring.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import {getNodeAgentMonitoringOnboarding} from 'sentry/gettingStartedDocs/node/utils'; - -export const agentMonitoring = getNodeAgentMonitoringOnboarding({ - packageName: '@sentry/astro', - configFileName: 'sentry.server.config.js', -}); diff --git a/static/app/gettingStartedDocs/javascript-astro/index.tsx b/static/app/gettingStartedDocs/javascript-astro/index.tsx index a3044121d43c41..37acc842772cb1 100644 --- a/static/app/gettingStartedDocs/javascript-astro/index.tsx +++ b/static/app/gettingStartedDocs/javascript-astro/index.tsx @@ -3,8 +3,8 @@ import {featureFlag} from 'sentry/gettingStartedDocs/javascript/featureFlag'; import {logsFullStack} from 'sentry/gettingStartedDocs/javascript/logs'; import {metricsFullStack} from 'sentry/gettingStartedDocs/javascript/metrics'; import {profilingFullStack} from 'sentry/gettingStartedDocs/javascript/profiling'; +import {getNodeAgentMonitoringOnboarding} from 'sentry/gettingStartedDocs/node/utils'; -import {agentMonitoring} from './agentMonitoring'; import {crashReport} from './crashReport'; import {feedback} from './feedback'; import {mcp} from './mcp'; @@ -32,7 +32,10 @@ const docs: Docs = { docsPlatform: 'astro', packageName: '@sentry/astro', }), - agentMonitoringOnboarding: agentMonitoring, + agentMonitoringOnboarding: getNodeAgentMonitoringOnboarding({ + packageName: '@sentry/astro', + configFileName: 'sentry.server.config.js', + }), mcpOnboarding: mcp, }; diff --git a/static/app/gettingStartedDocs/javascript-nextjs/agentMonitoring.tsx b/static/app/gettingStartedDocs/javascript-nextjs/agentMonitoring.tsx deleted file mode 100644 index 0915f42b47f03c..00000000000000 --- a/static/app/gettingStartedDocs/javascript-nextjs/agentMonitoring.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import {getNodeAgentMonitoringOnboarding} from 'sentry/gettingStartedDocs/node/utils'; - -export const agentMonitoring = getNodeAgentMonitoringOnboarding({ - packageName: '@sentry/nextjs', - configFileName: 'sentry.server.config.ts', -}); diff --git a/static/app/gettingStartedDocs/javascript-nextjs/index.tsx b/static/app/gettingStartedDocs/javascript-nextjs/index.tsx index 228f8b58582e18..37bd7200dd7bdd 100644 --- a/static/app/gettingStartedDocs/javascript-nextjs/index.tsx +++ b/static/app/gettingStartedDocs/javascript-nextjs/index.tsx @@ -3,9 +3,9 @@ import {featureFlag} from 'sentry/gettingStartedDocs/javascript/featureFlag'; import {logsFullStack} from 'sentry/gettingStartedDocs/javascript/logs'; import {metricsFullStack} from 'sentry/gettingStartedDocs/javascript/metrics'; import {profilingFullStack} from 'sentry/gettingStartedDocs/javascript/profiling'; +import {getNodeAgentMonitoringOnboarding} from 'sentry/gettingStartedDocs/node/utils'; import {tct} from 'sentry/locale'; -import {agentMonitoring} from './agentMonitoring'; import {crashReport} from './crashReport'; import {feedback} from './feedback'; import {mcp} from './mcp'; @@ -87,7 +87,10 @@ const docs: Docs = { docsPlatform: 'nextjs', packageName: '@sentry/nextjs', }), - agentMonitoringOnboarding: agentMonitoring, + agentMonitoringOnboarding: getNodeAgentMonitoringOnboarding({ + packageName: '@sentry/nextjs', + configFileName: 'sentry.server.config.ts', + }), mcpOnboarding: mcp, }; diff --git a/static/app/gettingStartedDocs/javascript-nuxt/agentMonitoring.tsx b/static/app/gettingStartedDocs/javascript-nuxt/agentMonitoring.tsx deleted file mode 100644 index f6c3ce07407a85..00000000000000 --- a/static/app/gettingStartedDocs/javascript-nuxt/agentMonitoring.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import {getNodeAgentMonitoringOnboarding} from 'sentry/gettingStartedDocs/node/utils'; - -export const agentMonitoring = getNodeAgentMonitoringOnboarding({ - packageName: '@sentry/nuxt', - configFileName: 'sentry.server.config.ts', -}); diff --git a/static/app/gettingStartedDocs/javascript-nuxt/index.tsx b/static/app/gettingStartedDocs/javascript-nuxt/index.tsx index 890e049eadad82..3f97db92c920d8 100644 --- a/static/app/gettingStartedDocs/javascript-nuxt/index.tsx +++ b/static/app/gettingStartedDocs/javascript-nuxt/index.tsx @@ -3,8 +3,8 @@ import {featureFlag} from 'sentry/gettingStartedDocs/javascript/featureFlag'; import {logsFullStack} from 'sentry/gettingStartedDocs/javascript/logs'; import {metricsFullStack} from 'sentry/gettingStartedDocs/javascript/metrics'; import {profiling} from 'sentry/gettingStartedDocs/javascript/profiling'; +import {getNodeAgentMonitoringOnboarding} from 'sentry/gettingStartedDocs/node/utils'; -import {agentMonitoring} from './agentMonitoring'; import {crashReport} from './crashReport'; import {feedback} from './feedback'; import {mcp} from './mcp'; @@ -31,7 +31,10 @@ const docs: Docs = { docsPlatform: 'nuxt', packageName: '@sentry/nuxt', }), - agentMonitoringOnboarding: agentMonitoring, + agentMonitoringOnboarding: getNodeAgentMonitoringOnboarding({ + packageName: '@sentry/nuxt', + configFileName: 'sentry.server.config.ts', + }), mcpOnboarding: mcp, }; diff --git a/static/app/gettingStartedDocs/javascript-react-router/agentMonitoring.tsx b/static/app/gettingStartedDocs/javascript-react-router/agentMonitoring.tsx deleted file mode 100644 index 86bf4847850222..00000000000000 --- a/static/app/gettingStartedDocs/javascript-react-router/agentMonitoring.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import {getNodeAgentMonitoringOnboarding} from 'sentry/gettingStartedDocs/node/utils'; - -export const agentMonitoring = getNodeAgentMonitoringOnboarding({ - packageName: '@sentry/react-router', - configFileName: 'instrument.server.mjs', -}); diff --git a/static/app/gettingStartedDocs/javascript-react-router/index.tsx b/static/app/gettingStartedDocs/javascript-react-router/index.tsx index 731f4ed878a102..961dcbc2169d6e 100644 --- a/static/app/gettingStartedDocs/javascript-react-router/index.tsx +++ b/static/app/gettingStartedDocs/javascript-react-router/index.tsx @@ -2,8 +2,8 @@ import type {Docs} from 'sentry/components/onboarding/gettingStartedDoc/types'; import {logsFullStack} from 'sentry/gettingStartedDocs/javascript/logs'; import {metricsFullStack} from 'sentry/gettingStartedDocs/javascript/metrics'; import {profilingFullStack} from 'sentry/gettingStartedDocs/javascript/profiling'; +import {getNodeAgentMonitoringOnboarding} from 'sentry/gettingStartedDocs/node/utils'; -import {agentMonitoring} from './agentMonitoring'; import {crashReport} from './crashReport'; import {feedback} from './feedback'; import {mcp} from './mcp'; @@ -24,7 +24,10 @@ const docs: Docs = { nodeProfilingLink: 'https://docs.sentry.io/platforms/javascript/guides/react-router/profiling/node-profiling/', }), - agentMonitoringOnboarding: agentMonitoring, + agentMonitoringOnboarding: getNodeAgentMonitoringOnboarding({ + packageName: '@sentry/react-router', + configFileName: 'instrument.server.mjs', + }), logsOnboarding: logsFullStack({ docsPlatform: 'react-router', packageName: '@sentry/react-router', diff --git a/static/app/gettingStartedDocs/javascript-remix/agentMonitoring.tsx b/static/app/gettingStartedDocs/javascript-remix/agentMonitoring.tsx deleted file mode 100644 index 175d0968066703..00000000000000 --- a/static/app/gettingStartedDocs/javascript-remix/agentMonitoring.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import {getNodeAgentMonitoringOnboarding} from 'sentry/gettingStartedDocs/node/utils'; - -export const agentMonitoring = getNodeAgentMonitoringOnboarding({ - packageName: '@sentry/remix', - configFileName: 'instrument.server.mjs', -}); diff --git a/static/app/gettingStartedDocs/javascript-remix/index.tsx b/static/app/gettingStartedDocs/javascript-remix/index.tsx index f3d2ea8c929b6a..28c45323c69038 100644 --- a/static/app/gettingStartedDocs/javascript-remix/index.tsx +++ b/static/app/gettingStartedDocs/javascript-remix/index.tsx @@ -3,8 +3,8 @@ import {featureFlag} from 'sentry/gettingStartedDocs/javascript/featureFlag'; import {logsFullStack} from 'sentry/gettingStartedDocs/javascript/logs'; import {metricsFullStack} from 'sentry/gettingStartedDocs/javascript/metrics'; import {profilingFullStack} from 'sentry/gettingStartedDocs/javascript/profiling'; +import {getNodeAgentMonitoringOnboarding} from 'sentry/gettingStartedDocs/node/utils'; -import {agentMonitoring} from './agentMonitoring'; import {crashReport} from './crashReport'; import {feedback} from './feedback'; import {mcp} from './mcp'; @@ -28,7 +28,10 @@ const docs: Docs = { docsPlatform: 'remix', packageName: '@sentry/remix', }), - agentMonitoringOnboarding: agentMonitoring, + agentMonitoringOnboarding: getNodeAgentMonitoringOnboarding({ + packageName: '@sentry/remix', + configFileName: 'instrument.server.mjs', + }), logsOnboarding: logsFullStack({ docsPlatform: 'remix', packageName: '@sentry/remix', diff --git a/static/app/gettingStartedDocs/javascript-solidstart/agentMonitoring.tsx b/static/app/gettingStartedDocs/javascript-solidstart/agentMonitoring.tsx deleted file mode 100644 index 073fca29ac73d8..00000000000000 --- a/static/app/gettingStartedDocs/javascript-solidstart/agentMonitoring.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import {getNodeAgentMonitoringOnboarding} from 'sentry/gettingStartedDocs/node/utils'; - -export const agentMonitoring = getNodeAgentMonitoringOnboarding({ - packageName: '@sentry/solidstart', - configFileName: 'instrument.server.mjs', -}); diff --git a/static/app/gettingStartedDocs/javascript-solidstart/index.tsx b/static/app/gettingStartedDocs/javascript-solidstart/index.tsx index c67539a889375f..4c9b5e0181019b 100644 --- a/static/app/gettingStartedDocs/javascript-solidstart/index.tsx +++ b/static/app/gettingStartedDocs/javascript-solidstart/index.tsx @@ -3,8 +3,8 @@ import {featureFlag} from 'sentry/gettingStartedDocs/javascript/featureFlag'; import {logsFullStack} from 'sentry/gettingStartedDocs/javascript/logs'; import {metricsFullStack} from 'sentry/gettingStartedDocs/javascript/metrics'; import {profiling} from 'sentry/gettingStartedDocs/javascript/profiling'; +import {getNodeAgentMonitoringOnboarding} from 'sentry/gettingStartedDocs/node/utils'; -import {agentMonitoring} from './agentMonitoring'; import {crashReport} from './crashReport'; import {feedback} from './feedback'; import {mcp} from './mcp'; @@ -23,7 +23,10 @@ const docs: Docs = { docsLink: 'https://docs.sentry.io/platforms/javascript/guides/solidstart/profiling/browser-profiling/', }), - agentMonitoringOnboarding: agentMonitoring, + agentMonitoringOnboarding: getNodeAgentMonitoringOnboarding({ + packageName: '@sentry/solidstart', + configFileName: 'instrument.server.mjs', + }), logsOnboarding: logsFullStack({ docsPlatform: 'solidstart', packageName: '@sentry/solidstart', diff --git a/static/app/gettingStartedDocs/javascript-sveltekit/agentMonitoring.tsx b/static/app/gettingStartedDocs/javascript-sveltekit/agentMonitoring.tsx deleted file mode 100644 index 763bcc3e2642c9..00000000000000 --- a/static/app/gettingStartedDocs/javascript-sveltekit/agentMonitoring.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import {getNodeAgentMonitoringOnboarding} from 'sentry/gettingStartedDocs/node/utils'; - -export const agentMonitoring = getNodeAgentMonitoringOnboarding({ - packageName: '@sentry/sveltekit', - configFileName: 'instrumentation.server.js', -}); diff --git a/static/app/gettingStartedDocs/javascript-sveltekit/index.tsx b/static/app/gettingStartedDocs/javascript-sveltekit/index.tsx index 25f323597d0b8d..45d893e667a3ba 100644 --- a/static/app/gettingStartedDocs/javascript-sveltekit/index.tsx +++ b/static/app/gettingStartedDocs/javascript-sveltekit/index.tsx @@ -3,8 +3,8 @@ import {featureFlag} from 'sentry/gettingStartedDocs/javascript/featureFlag'; import {logsFullStack} from 'sentry/gettingStartedDocs/javascript/logs'; import {metricsFullStack} from 'sentry/gettingStartedDocs/javascript/metrics'; import {profilingFullStack} from 'sentry/gettingStartedDocs/javascript/profiling'; +import {getNodeAgentMonitoringOnboarding} from 'sentry/gettingStartedDocs/node/utils'; -import {agentMonitoring} from './agentMonitoring'; import {crashReport} from './crashReport'; import {feedback} from './feedback'; import {mcp} from './mcp'; @@ -24,7 +24,10 @@ const docs: Docs = { nodeProfilingLink: 'https://docs.sentry.io/platforms/javascript/guides/sveltekit/profiling/node-profiling/', }), - agentMonitoringOnboarding: agentMonitoring, + agentMonitoringOnboarding: getNodeAgentMonitoringOnboarding({ + packageName: '@sentry/sveltekit', + configFileName: 'instrumentation.server.js', + }), logsOnboarding: logsFullStack({ docsPlatform: 'sveltekit', packageName: '@sentry/sveltekit', diff --git a/static/app/gettingStartedDocs/javascript-tanstackstart-react/agentMonitoring.tsx b/static/app/gettingStartedDocs/javascript-tanstackstart-react/agentMonitoring.tsx deleted file mode 100644 index 8b7fb840c1aeb0..00000000000000 --- a/static/app/gettingStartedDocs/javascript-tanstackstart-react/agentMonitoring.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import {getNodeAgentMonitoringOnboarding} from 'sentry/gettingStartedDocs/node/utils'; - -export const agentMonitoring = getNodeAgentMonitoringOnboarding({ - packageName: '@sentry/tanstackstart-react', - configFileName: 'app/ssr.tsx', -}); diff --git a/static/app/gettingStartedDocs/javascript-tanstackstart-react/index.tsx b/static/app/gettingStartedDocs/javascript-tanstackstart-react/index.tsx index 72d70d5035ca06..fab5cf0a8e7a72 100644 --- a/static/app/gettingStartedDocs/javascript-tanstackstart-react/index.tsx +++ b/static/app/gettingStartedDocs/javascript-tanstackstart-react/index.tsx @@ -2,8 +2,8 @@ import type {Docs} from 'sentry/components/onboarding/gettingStartedDoc/types'; import {logsFullStack} from 'sentry/gettingStartedDocs/javascript/logs'; import {metricsFullStack} from 'sentry/gettingStartedDocs/javascript/metrics'; import {profilingFullStack} from 'sentry/gettingStartedDocs/javascript/profiling'; +import {getNodeAgentMonitoringOnboarding} from 'sentry/gettingStartedDocs/node/utils'; -import {agentMonitoring} from './agentMonitoring'; import {mcp} from './mcp'; import {onboarding} from './onboarding'; @@ -16,7 +16,10 @@ const docs: Docs = { nodeProfilingLink: 'https://docs.sentry.io/platforms/javascript/guides/tanstackstart-react/profiling/node-profiling/', }), - agentMonitoringOnboarding: agentMonitoring, + agentMonitoringOnboarding: getNodeAgentMonitoringOnboarding({ + packageName: '@sentry/tanstackstart-react', + configFileName: 'app/ssr.tsx', + }), logsOnboarding: logsFullStack({ docsPlatform: 'tanstackstart-react', packageName: '@sentry/tanstackstart-react', diff --git a/static/app/gettingStartedDocs/javascript/agentMonitoring.tsx b/static/app/gettingStartedDocs/javascript/agentMonitoring.tsx index 274c9114bfe641..e2a7d7a6518d9a 100644 --- a/static/app/gettingStartedDocs/javascript/agentMonitoring.tsx +++ b/static/app/gettingStartedDocs/javascript/agentMonitoring.tsx @@ -14,7 +14,7 @@ import { import {t, tct} from 'sentry/locale'; import {AgentIntegration} from 'sentry/views/insights/pages/agents/utils/agentIntegrations'; -function getClientSideAgentMonitoringOnboardingConfig({ +function getClientSideConfig({ integration, params, sentryImport, @@ -321,7 +321,7 @@ export function agentMonitoring({ return [ { title: t('Configure'), - content: getClientSideAgentMonitoringOnboardingConfig({ + content: getClientSideConfig({ integration: selected, sentryImport: getImport(packageName, importMode).join('\n'), params, diff --git a/static/app/gettingStartedDocs/node/utils.tsx b/static/app/gettingStartedDocs/node/utils.tsx index 9995b55b1d99fb..47b3643001417b 100644 --- a/static/app/gettingStartedDocs/node/utils.tsx +++ b/static/app/gettingStartedDocs/node/utils.tsx @@ -103,6 +103,48 @@ export function getAgentMonitoringInstallStep( packageName?: `@sentry/${string}`; } = {} ): OnboardingStep[] { + const selected = + (params.platformOptions as any)?.integration ?? AgentIntegration.VERCEL_AI; + + if (selected === AgentIntegration.MASTRA) { + return [ + { + type: StepType.INSTALL, + content: [ + { + type: 'text', + text: tct( + 'Install the [code:@mastra/sentry] package to enable Sentry integration with Mastra.', + { + code: , + } + ), + }, + { + type: 'code', + tabs: [ + { + label: 'npm', + language: 'bash', + code: 'npm install @mastra/sentry', + }, + { + label: 'yarn', + language: 'bash', + code: 'yarn add @mastra/sentry', + }, + { + label: 'pnpm', + language: 'bash', + code: 'pnpm add @mastra/sentry', + }, + ], + }, + ], + }, + ]; + } + return [ { type: StepType.INSTALL, @@ -409,341 +451,105 @@ Sentry.profiler.stopProfiler(); ], }); -const getBrowserAgentMonitoringOnboardingConfiguration = ({ +function getAgentMonitoringConfigStep({ + params, integration, packageName, importMode, + configFileName, }: { integration: AgentIntegration; packageName: `@sentry/${string}`; - importMode?: 'esm' | 'cjs' | 'esm-only'; -}): ContentBlock[] => { - if (integration === AgentIntegration.LANGGRAPH) { - return [ - { - type: 'text', - text: tct( - 'Then follow the [manualSpanCreationDoc:manual custom spans] to instrument your AI calls, or use the [code:instrumentLangGraph] helper:', - { - manualSpanCreationDoc: ( - - ), - code: , - } - ), - }, - { - type: 'code', - tabs: [ - { - label: 'JavaScript', - language: 'javascript', - code: `${getImport(packageName, importMode).join('\n')} -import { ChatOpenAI } from "@langchain/openai"; -import { createReactAgent } from "@langchain/langgraph/prebuilt"; -import { HumanMessage, SystemMessage } from "@langchain/core/messages"; - -const llm = new ChatOpenAI({ - modelName: "gpt-4o", - // WARNING: Never expose API keys in browser code - apiKey: "YOUR_OPENAI_API_KEY", -}); - -const agent = createReactAgent({ llm, tools: [] }); - -Sentry.instrumentLangGraph(agent, { - recordInputs: true, - recordOutputs: true, -}); - -const result = await agent.invoke({ - messages: [ - new SystemMessage("You are a helpful assistant."), - new HumanMessage("Tell me a joke") - ], -}); - -const messages = result.messages; -const lastMessage = messages[messages.length - 1]; -const text = lastMessage.content; - `, - }, - ], - }, - ]; - } - - if (integration === AgentIntegration.LANGCHAIN) { - return [ - { - type: 'text', - text: tct( - 'Then follow the [manualSpanCreationDoc:manual custom spans] to instrument your AI calls, or use the [code:createLangChainCallbackHandler] helper:', - { - manualSpanCreationDoc: ( - - ), - code: , - } - ), - }, - { - type: 'code', - tabs: [ - { - label: 'JavaScript', - language: 'javascript', - code: `${getImport(packageName, importMode).join('\n')} -import { ChatOpenAI } from "@langchain/openai"; -import { HumanMessage, SystemMessage } from "@langchain/core/messages"; - - -// Create a LangChain callback handler -const callbackHandler = Sentry.createLangChainCallbackHandler({ - recordInputs: true, // Optional: record input prompts/messages - recordOutputs: true, // Optional: record output responses -}); - -const chatModel = new ChatOpenAI({ - modelName: "gpt-4o", - // WARNING: Never expose API keys in browser code - apiKey: "YOUR_OPENAI_API_KEY", -}); - -const messages = [ - new SystemMessage("You are a helpful assistant."), - new HumanMessage("Tell me a joke"), -]; - -const response = await chatModel.invoke(messages, { - callbacks: [callbackHandler], -}); -const text = response.content; - `, - }, - ], - }, - ]; - } - - if (integration === AgentIntegration.GOOGLE_GENAI) { - return [ - { - type: 'text', - text: tct( - 'Then follow the [manualSpanCreationDoc:manual custom spans] to instrument your AI calls, or use the [code:instrumentGoogleGenAIClient] helper:', - { - manualSpanCreationDoc: ( - - ), - code: , - } - ), - }, - { - type: 'code', - tabs: [ - { - label: 'JavaScript', - language: 'javascript', - code: `${getImport(packageName, importMode).join('\n')} -import { GoogleGenAI } from "@google/genai"; - -// WARNING: Never expose API keys in browser code -const genAI = new GoogleGenAI("YOUR_GOOGLE_API_KEY"); - -const client = Sentry.instrumentGoogleGenAIClient(genAI, { - recordInputs: true, - recordOutputs: true, -}); - -const response = await client.models.generateContent({ - model: 'gemini-2.5-flash-lite', - contents: 'Why is the sky blue?', -}); - `, - }, - ], - }, - ]; - } - - if (integration === AgentIntegration.ANTHROPIC) { - return [ - { - type: 'text', - text: tct( - 'Then follow the [manualSpanCreationDoc:manual custom spans] to instrument your AI calls, or use the [code:instrumentAnthropicAiClient] helper:', - { - manualSpanCreationDoc: ( - - ), - code: , - } - ), - }, - { - type: 'code', - tabs: [ - { - label: 'JavaScript', - language: 'javascript', - code: `${getImport(packageName, importMode).join('\n')} -import Anthropic from "@anthropic-ai/sdk"; - -const anthropic = new Anthropic(); - -const client = Sentry.instrumentAnthropicAiClient(anthropic, { - recordInputs: true, - recordOutputs: true, -}); - -const msg = await client.messages.create({ - model: "claude-3-5-sonnet", - messages: [{role: "user", content: "Tell me a joke"}], -}); - `, - }, - ], - }, - ]; - } - - if (integration === AgentIntegration.OPENAI) { - return [ - { - type: 'text', - text: tct( - 'Then follow the [manualSpanCreationDoc:manual custom spans] to instrument your AI calls, or use the [code:instrumentOpenAiClient] helper:', - { - manualSpanCreationDoc: ( - - ), - code: , - } - ), - }, - { - type: 'code', - tabs: [ - { - label: 'JavaScript', - language: 'javascript', - code: `${getImport(packageName, importMode).join('\n')} -import OpenAI from "openai"; - -const openai = new OpenAI(); - -const client = Sentry.instrumentOpenAiClient(openai, { - recordInputs: true, - recordOutputs: true, -}); - -const response = await client.responses.create({ - model: "gpt-4o-mini", - input: "Tell me a joke", -}); - `, - }, - ], - }, - ]; - } - - return []; -}; - -export const getNodeAgentMonitoringOnboarding = ({ - packageName = '@sentry/node', - configFileName, - importMode, -}: { + params: DocsParams; configFileName?: string; importMode?: 'esm' | 'cjs' | 'esm-only'; - packageName?: `@sentry/${string}`; -} = {}): OnboardingConfig => ({ - install: params => { - const selected = - (params.platformOptions as any)?.integration ?? AgentIntegration.VERCEL_AI; +}): OnboardingStep[] { + // Meta-frameworks can run on multiple runtimes (Node.js server-side, Browser client-side, etc.). + // We only show Node.js instructions here to keep onboarding simple. + // For other runtimes, we show an alert linking to the docs. + const isMetaFramework = javascriptMetaFrameworks.includes(params.platformKey); - if (selected === AgentIntegration.MASTRA) { - return [ + const manualInstrumentationAlert: ContentBlock[] = isMetaFramework + ? [ { - type: StepType.INSTALL, - content: [ + type: 'alert', + alertType: 'info', + text: tct( + "Below you'll find setup instructions for server-side on Node.js. For other runtimes, like the Browser, the instrumentation needs to be manually enabled. [link:See the docs] for more information.", { - type: 'text', - text: tct( - 'Install the [code:@mastra/sentry] package to enable Sentry integration with Mastra.', - { - code: , - } + link: ( + ), - }, - { - type: 'code', - tabs: [ - { - label: 'npm', - language: 'bash', - code: 'npm install @mastra/sentry', - }, - { - label: 'yarn', - language: 'bash', - code: 'yarn add @mastra/sentry', - }, - { - label: 'pnpm', - language: 'bash', - code: 'pnpm add @mastra/sentry', - }, - ], - }, - ], + } + ), }, - ]; - } + ] + : []; - return getAgentMonitoringInstallStep(params, { - packageName, - }); - }, - configure: params => { - const selected = - (params.platformOptions as any)?.integration ?? AgentIntegration.VERCEL_AI; + const vercelAiExtraInstrumentation: ContentBlock[] = + integration === AgentIntegration.VERCEL_AI + ? [ + { + type: 'text', + text: tct( + 'To correctly capture spans, pass the [code:experimental_telemetry] object to every [code:generateText], [code:generateObject], and [code:streamText] function call. For more details, see the [link:AI SDK Telemetry Metadata docs].', + { + code: , + link: ( + + ), + } + ), + }, + { + type: 'code', + tabs: [ + { + label: 'JavaScript', + language: 'javascript', + code: `const { generateText } = require('ai'); +const { openai } = require('@ai-sdk/openai'); - if (selected === AgentIntegration.MANUAL) { - return getAgentMonitoringManualConfigStep(params, { - packageName, - importMode, - }); - } +const result = await generateText({ + model: openai("gpt-4o"), + prompt: "Tell me a joke", + experimental_telemetry: { + isEnabled: true, + recordInputs: true, + recordOutputs: true, + }, +});`, + }, + ], + }, + ] + : []; - if (selected === AgentIntegration.MASTRA) { - return [ - { - title: t('Configure'), - content: [ - { - type: 'text', - text: tct( - 'Configure Mastra to use Sentry by adding the [code:SentryExporter] to your Mastra observability config. For more details, see the [link:@mastra/sentry package].', - { - code: , - link: ( - - ), - } - ), - }, - { - type: 'code', - tabs: [ - { - label: 'JavaScript', - language: 'javascript', - code: `import { Mastra } from '@mastra/core'; + return [ + { + title: t('Configure'), + content: + integration === AgentIntegration.MASTRA + ? [ + { + type: 'text', + text: tct( + 'Configure Mastra to use Sentry by adding the [code:SentryExporter] to your Mastra observability config. For more details, see the [link:@mastra/sentry package].', + { + code: , + link: ( + + ), + } + ), + }, + { + type: 'code', + tabs: [ + { + label: 'JavaScript', + language: 'javascript', + code: `import { Mastra } from '@mastra/core'; import { SentryExporter } from '@mastra/sentry'; const mastra = new Mastra({ @@ -755,6 +561,7 @@ const mastra = new Mastra({ exporters: [ new SentryExporter({ dsn: '${params.dsn.public}', + // Tracing must be enabled for agent monitoring to work tracesSampleRate: 1.0, }), ], @@ -762,74 +569,28 @@ const mastra = new Mastra({ }, }, });`, - }, - ], - }, - ], - }, - ]; - } - - const isNodeOrMetaPlatform = - params.platformKey.startsWith('node') || - javascriptMetaFrameworks.includes(params.platformKey); - - const vercelAiExtraInstrumentation: ContentBlock[] = [ - { - type: 'text', - text: tct( - 'To correctly capture spans, pass the [code:experimental_telemetry] object to every [code:generateText], [code:generateObject], and [code:streamText] function call. For more details, see the [link:AI SDK Telemetry Metadata docs].', - { - code: , - link: ( - - ), - } - ), - }, - { - type: 'code', - tabs: [ - { - label: 'JavaScript', - language: 'javascript', - code: `const { generateText } = require('ai'); -const { openai } = require('@ai-sdk/openai'); - -const result = await generateText({ - model: openai("gpt-4o"), - prompt: "Tell me a joke", - experimental_telemetry: { - isEnabled: true, - recordInputs: true, - recordOutputs: true, - }, -});`, - }, - ], - }, - ]; - - const nonManualContent: ContentBlock[] = [ - { - type: 'text', - text: isNodeOrMetaPlatform - ? tct( - 'Import and initialize the Sentry SDK - the [integration] will be enabled automatically:', + }, + ], + }, + ] + : [ + ...manualInstrumentationAlert, { - integration: - AGENT_INTEGRATION_LABELS[selected as AgentIntegration] ?? selected, - } - ) - : t('Import and initialize the Sentry SDK:'), - }, - { - type: 'code', - tabs: [ - { - label: configFileName ? configFileName : 'JavaScript', - language: 'javascript', - code: `${getImport(packageName, importMode).join('\n')} + type: 'text', + text: tct( + 'Import and initialize the Sentry SDK - the [integration] will be enabled automatically:', + { + integration: AGENT_INTEGRATION_LABELS[integration] ?? integration, + } + ), + }, + { + type: 'code', + tabs: [ + { + label: configFileName ?? 'JavaScript', + language: 'javascript', + code: `${getImport(packageName, importMode).join('\n')} Sentry.init({ dsn: "${params.dsn.public}", @@ -839,120 +600,92 @@ Sentry.init({ // see https://docs.sentry.io/platforms/javascript/data-management/data-collected/ for more info sendDefaultPii: true, });`, - }, - ], - }, - ...(selected === AgentIntegration.VERCEL_AI ? vercelAiExtraInstrumentation : []), - ]; - - return [ - { - title: t('Configure'), - content: isNodeOrMetaPlatform - ? nonManualContent - : [ - ...nonManualContent, - ...getBrowserAgentMonitoringOnboardingConfiguration({ - integration: selected, - packageName, - importMode, - }), + }, + ], + }, + ...vercelAiExtraInstrumentation, ], - }, - ]; - }, - verify: params => { - const isNodePlatform = - params.platformKey.startsWith('node') || - javascriptMetaFrameworks.includes(params.platformKey as any); - - const content: ContentBlock[] = [ - { - type: 'text', - text: t('Verify that your instrumentation works by simply calling your LLM.'), - }, - ]; + }, + ]; +} - if (!isNodePlatform) { - return [ - { - type: StepType.VERIFY, - content, - }, - ]; - } +function getAgentMonitoringVerifyStep(params: DocsParams): OnboardingStep[] { + const content: ContentBlock[] = [ + { + type: 'text', + text: t('Verify that your instrumentation works by simply calling your LLM.'), + }, + ]; - const selected = - (params.platformOptions as any)?.integration ?? AgentIntegration.VERCEL_AI; + const selected = + (params.platformOptions as any)?.integration ?? AgentIntegration.VERCEL_AI; - if (selected === AgentIntegration.ANTHROPIC) { - content.push({ - type: 'code', - tabs: [ - { - label: 'JavaScript', - language: 'javascript', - code: ` -const Anthropic = require("@anthropic-ai/sdk"); + if (selected === AgentIntegration.ANTHROPIC) { + content.push({ + type: 'code', + tabs: [ + { + label: 'JavaScript', + language: 'javascript', + code: `const Anthropic = require("@anthropic-ai/sdk"); const client = new Anthropic(); const msg = await client.messages.create({ - messages: [{role: "user", content: "Tell me a joke"}], + messages: [{ role: "user", content: "Tell me a joke" }], model: "claude-sonnet-4-5-20250929", -}); -`, - }, - ], - }); - } - if (selected === AgentIntegration.OPENAI) { - content.push({ - type: 'code', - tabs: [ - { - label: 'JavaScript', - language: 'javascript', - code: ` -const OpenAI = require("openai"); +});`, + }, + ], + }); + } + + if (selected === AgentIntegration.OPENAI) { + content.push({ + type: 'code', + tabs: [ + { + label: 'JavaScript', + language: 'javascript', + code: `const OpenAI = require("openai"); const client = new OpenAI(); const response = await client.responses.create({ model: "gpt-4o-mini", input: "Tell me a joke", });`, - }, - ], - }); - } - if (selected === AgentIntegration.GOOGLE_GENAI) { - content.push({ - type: 'code', - tabs: [ - { - label: 'JavaScript', - language: 'javascript', - code: ` -const GoogleGenAI = require("@google/genai").GoogleGenAI; + }, + ], + }); + } + + if (selected === AgentIntegration.GOOGLE_GENAI) { + content.push({ + type: 'code', + tabs: [ + { + label: 'JavaScript', + language: 'javascript', + code: `const GoogleGenAI = require("@google/genai").GoogleGenAI; const GEMINI_API_KEY = process.env.GEMINI_API_KEY; -const ai = new GoogleGenAI({apiKey: GEMINI_API_KEY}); +const ai = new GoogleGenAI({ apiKey: GEMINI_API_KEY }); const response = await ai.models.generateContent({ model: 'gemini-2.5-flash-lite', contents: 'Why is the sky blue?', });`, - }, - ], - }); - } - if (selected === AgentIntegration.LANGCHAIN) { - content.push({ - type: 'code', - tabs: [ - { - label: 'JavaScript', - language: 'javascript', - code: ` -const { ChatOpenAI } = require("@langchain/openai"); + }, + ], + }); + } + + if (selected === AgentIntegration.LANGCHAIN) { + content.push({ + type: 'code', + tabs: [ + { + label: 'JavaScript', + language: 'javascript', + code: `const { ChatOpenAI } = require("@langchain/openai"); const { HumanMessage, SystemMessage } = require("@langchain/core/messages"); const chatModel = new ChatOpenAI({ @@ -967,19 +700,19 @@ const messages = [ const response = await chatModel.invoke(messages); const text = response.content;`, - }, - ], - }); - } - if (selected === AgentIntegration.LANGGRAPH) { - content.push({ - type: 'code', - tabs: [ - { - label: 'JavaScript', - language: 'javascript', - code: ` -const { ChatOpenAI } = require("@langchain/openai"); + }, + ], + }); + } + + if (selected === AgentIntegration.LANGGRAPH) { + content.push({ + type: 'code', + tabs: [ + { + label: 'JavaScript', + language: 'javascript', + code: `const { ChatOpenAI } = require("@langchain/openai"); const { createReactAgent } = require("@langchain/langgraph/prebuilt"); const { HumanMessage, SystemMessage } = require("@langchain/core/messages"); @@ -1000,18 +733,19 @@ const result = await agent.invoke({ const messages = result.messages; const lastMessage = messages[messages.length - 1]; const text = lastMessage.content;`, - }, - ], - }); - } - if (selected === AgentIntegration.MASTRA) { - content.push({ - type: 'code', - tabs: [ - { - label: 'JavaScript', - language: 'javascript', - code: `import { Agent } from '@mastra/core/agent'; + }, + ], + }); + } + + if (selected === AgentIntegration.MASTRA) { + content.push({ + type: 'code', + tabs: [ + { + label: 'JavaScript', + language: 'javascript', + code: `import { Agent } from '@mastra/core/agent'; // This agent needs to be registered in your Mastra config const agent = new Agent({ @@ -1022,18 +756,52 @@ const agent = new Agent({ }); const result = await agent.generate([{ role: "user", content: "Hello!" }]);`, - }, - ], + }, + ], + }); + } + + return [ + { + type: StepType.VERIFY, + content, + }, + ]; +} + +export const getNodeAgentMonitoringOnboarding = ({ + packageName = '@sentry/node', + configFileName, + importMode, +}: { + configFileName?: string; + importMode?: 'esm' | 'cjs' | 'esm-only'; + packageName?: `@sentry/${string}`; +} = {}): OnboardingConfig => ({ + install: params => + getAgentMonitoringInstallStep(params, { + packageName, + }), + configure: params => { + const selected = + (params.platformOptions as any)?.integration ?? AgentIntegration.VERCEL_AI; + + if (selected === AgentIntegration.MANUAL) { + return getAgentMonitoringManualConfigStep(params, { + packageName, + importMode, }); } - return [ - { - type: StepType.VERIFY, - content, - }, - ]; + return getAgentMonitoringConfigStep({ + params, + integration: selected, + packageName, + importMode, + configFileName, + }); }, + verify: getAgentMonitoringVerifyStep, }); export const getNodeMcpOnboarding = ({ diff --git a/static/app/views/insights/pages/agents/onboarding.tsx b/static/app/views/insights/pages/agents/onboarding.tsx index 9ae4150680fe65..44b6725862fa0b 100644 --- a/static/app/views/insights/pages/agents/onboarding.tsx +++ b/static/app/views/insights/pages/agents/onboarding.tsx @@ -23,7 +23,10 @@ import {useUrlPlatformOptions} from 'sentry/components/onboarding/platformOption import Panel from 'sentry/components/panels/panel'; import PanelBody from 'sentry/components/panels/panelBody'; import {SetupTitle} from 'sentry/components/updatedEmptyState'; -import {agentMonitoringPlatforms} from 'sentry/data/platformCategories'; +import { + agentMonitoringPlatforms, + javascriptMetaFrameworks, +} from 'sentry/data/platformCategories'; import platforms, {otherPlatform} from 'sentry/data/platforms'; import {t, tct} from 'sentry/locale'; import ConfigStore from 'sentry/stores/configStore'; @@ -32,7 +35,10 @@ import pulsingIndicatorStyles from 'sentry/styles/pulsingIndicator'; import {space} from 'sentry/styles/space'; import type {PlatformKey, Project} from 'sentry/types/project'; import {getSelectedProjectList} from 'sentry/utils/project/useSelectedProjectsHaveField'; +import {decodeInteger} from 'sentry/utils/queryString'; import useApi from 'sentry/utils/useApi'; +import {useLocation} from 'sentry/utils/useLocation'; +import {useNavigate} from 'sentry/utils/useNavigate'; import useOrganization from 'sentry/utils/useOrganization'; import usePageFilters from 'sentry/utils/usePageFilters'; import useProjects from 'sentry/utils/useProjects'; @@ -48,18 +54,6 @@ import { PYTHON_AGENT_INTEGRATIONS, } from './utils/agentIntegrations'; -// Full-stack JS frameworks that support server-side agent SDKs. -const fullStackJsPlatforms = [ - 'javascript-astro', - 'javascript-nextjs', - 'javascript-nuxt', - 'javascript-react-router', - 'javascript-remix', - 'javascript-solidstart', - 'javascript-sveltekit', - 'javascript-tanstackstart-react', -]; - const serverSideNodeIntegrations = new Set([ AgentIntegration.VERCEL_AI, AgentIntegration.MASTRA, @@ -222,6 +216,8 @@ export function Onboarding() { const {isSelfHosted, urlPrefix} = useLegacyStore(ConfigStore); const project = useOnboardingProject(); const organization = useOrganization(); + const location = useLocation(); + const navigate = useNavigate(); const currentPlatform = project?.platform ? platforms.find(p => p.id === project.platform) @@ -236,7 +232,9 @@ export function Onboarding() { // Local integration options for Agent Monitoring only const isPythonPlatform = (project?.platform ?? '').startsWith('python'); const isNodePlatform = (project?.platform ?? '').startsWith('node'); - const isFullStackJsPlatform = fullStackJsPlatforms.includes(project?.platform ?? ''); + const isFullStackJsPlatform = javascriptMetaFrameworks.includes( + project?.platform ?? 'other' + ); const hasServerSideNode = isNodePlatform || isFullStackJsPlatform; const integrationOptions = { @@ -258,6 +256,7 @@ export function Onboarding() { })), }, }; + const selectedPlatformOptions = useUrlPlatformOptions(integrationOptions); const {isPending: isLoadingRegistry, data: registryData} = @@ -325,13 +324,24 @@ export function Onboarding() { {introduction && {introduction}} - + { + navigate({ + pathname: location.pathname, + query: { + ...location.query, + guidedStep: step, + }, + }); + }} + > {steps - // Only show non-optional steps + // Only show non-collapsible steps .filter(step => !step.collapsible) .map((step, index) => (