Skip to content
Merged
7 changes: 6 additions & 1 deletion static/app/gettingStartedDocs/node/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
} from 'sentry/components/onboarding/gettingStartedDoc/types';
import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/types';
import {t, tct} from 'sentry/locale';
import {CopyLLMPromptButton} from 'sentry/views/insights/pages/agents/llmOnboardingInstructions';

function getInstallSnippet({
params,
Expand Down Expand Up @@ -605,14 +606,18 @@ Sentry.init({
{
type: 'text',
text: tct(
'Then follow the [link:manual instrumentation guide] to instrument your AI calls.',
'Then follow the [link:manual instrumentation guide] to instrument your AI calls, or use an AI coding agent to do it for you.',
{
link: (
<ExternalLink href="https://docs.sentry.io/platforms/node/tracing/instrumentation/ai-agents-module/#manual-instrumentation" />
),
}
),
},
{
type: 'custom',
content: <CopyLLMPromptButton />,
},
];

const selected = (params.platformOptions as any)?.integration ?? 'vercel_ai';
Expand Down
7 changes: 6 additions & 1 deletion static/app/gettingStartedDocs/python/agentMonitoring.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type {
} from 'sentry/components/onboarding/gettingStartedDoc/types';
import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/types';
import {t, tct} from 'sentry/locale';
import {CopyLLMPromptButton} from 'sentry/views/insights/pages/agents/llmOnboardingInstructions';

import {getPythonInstallCodeBlock} from './utils';

Expand Down Expand Up @@ -307,14 +308,18 @@ sentry_sdk.init(
{
type: 'text',
text: tct(
'Then follow the [link:manual instrumentation guide] to instrument your AI calls.',
'Then follow the [link:manual instrumentation guide] to instrument your AI calls, or use an AI coding agent to do it for you.',
{
link: (
<ExternalLink href="https://docs.sentry.io/platforms/python/tracing/instrumentation/custom-instrumentation/ai-agents-module/" />
),
}
),
},
{
type: 'custom',
content: <CopyLLMPromptButton />,
},
],
};

Expand Down
195 changes: 195 additions & 0 deletions static/app/views/insights/pages/agents/llmOnboardingInstructions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
import {Button} from 'sentry/components/core/button';
import {IconCopy} from 'sentry/icons';
import {t} from 'sentry/locale';
import {trackAnalytics} from 'sentry/utils/analytics';
import useCopyToClipboard from 'sentry/utils/useCopyToClipboard';
import useOrganization from 'sentry/utils/useOrganization';

export function CopyLLMPromptButton() {
const {copy} = useCopyToClipboard();
const organization = useOrganization();

return (
<Button
size="sm"
icon={<IconCopy />}
onClick={() => {
trackAnalytics('agent-monitoring.copy-llm-prompt-click', {
organization,
});
copy(LLM_ONBOARDING_INSTRUCTIONS, {
successMessage: t('Copied instrumentation prompt to clipboard'),
});
}}
>
{t('Copy Prompt for AI Agent')}
</Button>
);
}

const LLM_ONBOARDING_INSTRUCTIONS = `
# Instrument Sentry AI Agent Monitoring
Follow this decision tree to instrument AI Agent Monitoring.
## 1. Verify Sentry + Tracing
**Search for Sentry initialization:**
- JS/TS: \`Sentry.init\` in entry points, \`@sentry/*\` in package.json
- Python: \`sentry_sdk.init\` in entry points, \`sentry-sdk\` in requirements
**If not found:** Set up Sentry first following the official docs:
- JS/TS: https://docs.sentry.io/platforms/javascript/guides/node/
- Python: https://docs.sentry.io/platforms/python/
**Verify tracing is enabled** (REQUIRED for AI monitoring):
\`\`\`javascript
// JS - must have tracesSampleRate > 0, min SDK version 10.28.0
Sentry.init({ dsn: "...", tracesSampleRate: 1.0, sendDefaultPii: true })
\`\`\`
\`\`\`python
# Python - must have traces_sample_rate > 0
sentry_sdk.init(dsn="...", traces_sample_rate=1.0, send_default_pii=True)
\`\`\`
If missing, add \`tracesSampleRate: 1.0\` / \`traces_sample_rate=1.0\` and \`sendDefaultPii: true\` / \`send_default_pii=True\`.
## 2. Check for Supported AI Libraries
Check in this order - **use the highest-level framework found** (e.g., if using Vercel AI SDK with OpenAI provider, use Vercel integration, not OpenAI):
| Library (check in order) | JS Integration | Python Integration | Python Extra |
|--------------------------|---------------|-------------------|--------------|
| Vercel AI SDK | \`Sentry.vercelAIIntegration()\` | - | - |
| LangGraph | \`Sentry.langGraphIntegration()\` | Auto-enabled | \`sentry-sdk[langgraph]\` |
| LangChain | \`Sentry.langChainIntegration()\` | Auto-enabled | \`sentry-sdk[langchain]\` |
| OpenAI Agents | - | Auto-enabled | - |
| Pydantic AI | - | Auto-enabled | \`sentry-sdk[pydantic_ai]\` |
| LiteLLM | - | \`LiteLLMIntegration()\` | \`sentry-sdk[litellm]\` |
| OpenAI | \`Sentry.openAIIntegration()\` | Auto-enabled | - |
| Anthropic | \`Sentry.anthropicAIIntegration()\` | Auto-enabled | - |
| Google GenAI | \`Sentry.googleGenAIIntegration()\` | \`GoogleGenAIIntegration()\` | \`sentry-sdk[google_genai]\` |
**If supported library found → Step 3A**
**If no supported library → Step 3B**
## 3A. Enable Automatic Integration
### JavaScript
Add to Sentry.init integrations array with \`recordInputs\` and \`recordOutputs\`:
\`\`\`javascript
import * as Sentry from "@sentry/node";
Sentry.init({
dsn: "...",
tracesSampleRate: 1.0,
sendDefaultPii: true,
integrations: [
Sentry.openAIIntegration({ recordInputs: true, recordOutputs: true }),
// OR other integration as needed
],
});
\`\`\`
**Vercel AI SDK Extra Step:** Pass \`experimental_telemetry\` with \`functionId\` to every call:
\`\`\`javascript
const result = await generateText({
model: openai("gpt-4o"),
prompt: "Tell me a joke",
experimental_telemetry: {
isEnabled: true,
functionId: "generate-joke", // Name your functions for better tracing
recordInputs: true,
recordOutputs: true,
},
});
\`\`\`
### Python
Install with extras if needed:
\`\`\`bash
pip install sentry-sdk[langchain] # or [langgraph], [litellm], [google_genai], [pydantic_ai]
\`\`\`
Configure (some integrations auto-enable, some need explicit import):
\`\`\`python
import sentry_sdk
# Only import if NOT auto-enabled (see table above)
from sentry_sdk.integrations.openai_agents import OpenAIAgentsIntegration
sentry_sdk.init(
dsn="...",
traces_sample_rate=1.0,
send_default_pii=True, # Required to capture inputs/outputs
integrations=[
OpenAIAgentsIntegration(), # Only if explicit integration needed
],
)
\`\`\`
**Done.** SDK auto-instruments AI calls.
## 3B. Manual Instrumentation
Create spans with these exact \`op\` values and attributes:
### AI Request (LLM call)
- **op:** \`"gen_ai.request"\`
- **name:** \`"chat <model>"\`
- **Required:** \`gen_ai.request.model\`
- **Recommended:** \`gen_ai.usage.input_tokens\`, \`gen_ai.usage.output_tokens\`
\`\`\`python
with sentry_sdk.start_span(op="gen_ai.request", name=f"chat {model}") as span:
span.set_data("gen_ai.request.model", model)
result = llm.generate(messages)
span.set_data("gen_ai.usage.input_tokens", result.input_tokens)
span.set_data("gen_ai.usage.output_tokens", result.output_tokens)
\`\`\`
### Invoke Agent
- **op:** \`"gen_ai.invoke_agent"\`
- **name:** \`"invoke_agent <AgentName>"\`
- **Required:** \`gen_ai.request.model\`, \`gen_ai.agent.name\`
\`\`\`python
with sentry_sdk.start_span(op="gen_ai.invoke_agent", name=f"invoke_agent {agent_name}") as span:
span.set_data("gen_ai.agent.name", agent_name)
span.set_data("gen_ai.request.model", model)
result = agent.run()
\`\`\`
### Execute Tool
- **op:** \`"gen_ai.execute_tool"\`
- **name:** \`"execute_tool <tool_name>"\`
- **Required:** \`gen_ai.tool.name\`
\`\`\`python
with sentry_sdk.start_span(op="gen_ai.execute_tool", name=f"execute_tool {tool_name}") as span:
span.set_data("gen_ai.tool.name", tool_name)
span.set_data("gen_ai.tool.input", json.dumps(inputs))
result = tool(**inputs)
span.set_data("gen_ai.tool.output", json.dumps(result))
\`\`\`
### Handoff (agent-to-agent)
- **op:** \`"gen_ai.handoff"\`
- **name:** \`"handoff from <A> to <B>"\`
\`\`\`python
with sentry_sdk.start_span(op="gen_ai.handoff", name=f"handoff from {a} to {b}"):
pass
\`\`\`
## Key Rules
1. **All complex data must be JSON-stringified** - span attributes only accept primitives
2. **\`gen_ai.request.model\` is required** on \`gen_ai.request\` and \`gen_ai.invoke_agent\` spans
3. **Nest spans correctly:** \`gen_ai.invoke_agent\` spans should contain \`gen_ai.request\` and \`gen_ai.execute_tool\` spans as children
4. **JS min version:** \`@sentry/[email protected]\` or later
5. **Enable PII:** \`sendDefaultPii: true\` (JS) / \`send_default_pii=True\` (Python) to capture inputs/outputs
`;
108 changes: 66 additions & 42 deletions static/app/views/insights/pages/agents/onboarding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import emptyTraceImg from 'sentry-images/spot/profiling-empty-state.svg';
import {ExternalLink} from '@sentry/scraps/link';

import {Button} from 'sentry/components/core/button';
import {LinkButton} from 'sentry/components/core/button/linkButton';
import {GuidedSteps} from 'sentry/components/guidedSteps/guidedSteps';
import LoadingIndicator from 'sentry/components/loadingIndicator';
import {AuthTokenGeneratorProvider} from 'sentry/components/onboarding/gettingStartedDoc/authTokenGenerator';
Expand Down Expand Up @@ -38,6 +37,7 @@ import useOrganization from 'sentry/utils/useOrganization';
import usePageFilters from 'sentry/utils/usePageFilters';
import useProjects from 'sentry/utils/useProjects';
import {useSpans} from 'sentry/views/insights/common/queries/useDiscover';
import {CopyLLMPromptButton} from 'sentry/views/insights/pages/agents/llmOnboardingInstructions';
import {getHasAiSpansFilter} from 'sentry/views/insights/pages/agents/utils/query';
import {Referrer} from 'sentry/views/insights/pages/agents/utils/referrers';

Expand Down Expand Up @@ -264,28 +264,10 @@ export function Onboarding() {

if (!agentMonitoringPlatforms.has(project.platform as PlatformKey)) {
return (
<OnboardingPanel project={project}>
<DescriptionWrapper>
<p>
{tct(
'Fiddlesticks. Auto instrumentation of AI Agents is not available for your [platform] project. ',
{
platform: currentPlatform?.name || project.slug,
}
)}
</p>
<p>
{tct(
'However, you can still manually instrument your agents using the Sentry SDK tracing API. See [link:custom instrumentation docs] for details.',
{
link: (
<ExternalLink href="https://docs.sentry.io/platforms/python/tracing/instrumentation/custom-instrumentation/ai-agents-module/" />
),
}
)}
</p>
</DescriptionWrapper>
</OnboardingPanel>
<UnsupportedPlatformOnboarding
project={project}
platformName={currentPlatform?.name || project.slug}
/>
);
}

Expand All @@ -296,25 +278,7 @@ export function Onboarding() {
const agentMonitoringDocs = docs?.agentMonitoringOnboarding;

if (!agentMonitoringDocs || !dsn || !projectKeyId) {
return (
<OnboardingPanel project={project}>
<DescriptionWrapper>
<p>
{tct(
"The agent monitoring onboarding checklist isn't available for your [project] project yet, but you can still set up the Sentry SDK to start monitoring your AI agents.",
{project: project.slug}
)}
</p>
<LinkButton
size="sm"
href="https://docs.sentry.io/product/insights/ai/agents/"
external
>
{t('Go to Documentation')}
</LinkButton>
</DescriptionWrapper>
</OnboardingPanel>
);
return <NoDocsOnboarding project={project} />;
}

const docParams: DocsParams<any> = {
Expand Down Expand Up @@ -373,6 +337,66 @@ export function Onboarding() {
);
}

function UnsupportedPlatformOnboarding({
project,
platformName,
}: {
platformName: string;
project: Project;
}) {
return (
<OnboardingPanel project={project}>
<DescriptionWrapper>
<p>
{tct(
'Fiddlesticks. Auto instrumentation of AI Agents is not available for your [platform] project.',
{
platform: platformName,
}
)}
</p>
<p>
{tct(
'You can [link:manually instrument] your agents using the Sentry SDK tracing API, or use an AI coding agent to do it for you.',
{
link: (
<ExternalLink href="https://docs.sentry.io/platforms/python/tracing/instrumentation/custom-instrumentation/ai-agents-module/" />
),
}
)}
</p>
<CopyLLMPromptButton />
</DescriptionWrapper>
</OnboardingPanel>
);
}

function NoDocsOnboarding({project}: {project: Project}) {
return (
<OnboardingPanel project={project}>
<DescriptionWrapper>
<p>
{tct(
"The agent monitoring onboarding checklist isn't available for your [project] project yet.",
{project: project.slug}
)}
</p>
<p>
{tct(
'You can set up the Sentry SDK by following our [link:documentation], or use an AI coding agent to do it for you.',
{
link: (
<ExternalLink href="https://docs.sentry.io/product/insights/ai/agents/getting-started/" />
),
}
)}
</p>
<CopyLLMPromptButton />
</DescriptionWrapper>
</OnboardingPanel>
);
}

const EventWaitingIndicator = styled((p: React.HTMLAttributes<HTMLDivElement>) => (
<div {...p}>
{t("Waiting for this project's first agent events")}
Expand Down
Loading