Add Sentry AI agent monitoring with telemetry configuration (#15301)

This PR implements Sentry's AI agent monitoring by:

- Configuring vercelAIIntegration with recordInputs and recordOutputs
options
- Adding sendDefaultPii to Sentry.init() for better debugging
- Creating a shared AI_TELEMETRY_CONFIG constant to DRY up the telemetry
configuration
- Adding experimental_telemetry to all AI SDK calls (generateText,
generateObject, streamText)

All AI operations are now fully monitored in Sentry with complete
input/output recording for debugging and performance analysis.

Note: Currently on Sentry v9.26.0, which is compatible with this
implementation. No breaking changes from the v9-to-v10 migration guide
were found in the codebase.
This commit is contained in:
Félix Malfait
2025-10-23 18:06:28 +02:00
committed by GitHub
parent 7edfe4bc7a
commit bbe16c23bc
10 changed files with 552 additions and 403 deletions
@@ -15,6 +15,7 @@ import { getAppPath } from 'twenty-shared/utils';
import { In } from 'typeorm';
import { getAllSelectableFields } from 'src/engine/api/utils/get-all-selectable-fields.utils';
import { AI_TELEMETRY_CONFIG } from 'src/engine/core-modules/ai/constants/ai-telemetry.const';
import { AIBillingService } from 'src/engine/core-modules/ai/services/ai-billing.service';
import { AiModelRegistryService } from 'src/engine/core-modules/ai/services/ai-model-registry.service';
import { WorkspaceDomainsService } from 'src/engine/core-modules/domain/workspace-domains/services/workspace-domains.service';
@@ -131,6 +132,7 @@ export class AgentExecutionService implements AgentExecutionContext {
messages: convertToModelMessages(messages),
stopWhen: stepCountIs(AGENT_CONFIG.MAX_STEPS),
providerOptions,
experimental_telemetry: AI_TELEMETRY_CONFIG,
experimental_repairToolCall: async ({
toolCall,
tools: toolsForRepair,
@@ -2,6 +2,7 @@ import { Injectable, Logger } from '@nestjs/common';
import { generateText } from 'ai';
import { AI_TELEMETRY_CONFIG } from 'src/engine/core-modules/ai/constants/ai-telemetry.const';
import { AiModelRegistryService } from 'src/engine/core-modules/ai/services/ai-model-registry.service';
@Injectable()
@@ -25,6 +26,7 @@ export class AgentTitleGenerationService {
const result = await generateText({
model: defaultModel.model,
prompt: `Generate a concise, descriptive title (maximum 60 characters) for a chat thread based on the following message. The title should capture the main topic or purpose of the conversation. Return only the title, nothing else. Message: "${messageContent}"`,
experimental_telemetry: AI_TELEMETRY_CONFIG,
});
return this.cleanTitle(result.text);
@@ -1,6 +1,8 @@
import { generateObject, type LanguageModel, NoSuchToolError } from 'ai';
import { type z } from 'zod';
import { AI_TELEMETRY_CONFIG } from 'src/engine/core-modules/ai/constants/ai-telemetry.const';
type ToolCall = {
type: 'tool-call';
toolCallId: string;
@@ -57,6 +59,7 @@ export const repairToolCall = async ({
`- Object structures must match the schema shape`,
`- Array items must follow the specified format`,
].join('\n'),
experimental_telemetry: AI_TELEMETRY_CONFIG,
});
return {
@@ -10,6 +10,7 @@ import {
import { Repository } from 'typeorm';
import { z } from 'zod';
import { AI_TELEMETRY_CONFIG } from 'src/engine/core-modules/ai/constants/ai-telemetry.const';
import { ModelId } from 'src/engine/core-modules/ai/constants/ai-models.const';
import { AiModelRegistryService } from 'src/engine/core-modules/ai/services/ai-model-registry.service';
import { AgentEntity } from 'src/engine/metadata-modules/agent/agent.entity';
@@ -82,6 +83,7 @@ export class AiRouterService {
prompt: userPrompt,
schema: routerDecisionSchema,
temperature: 0.1,
experimental_telemetry: AI_TELEMETRY_CONFIG,
});
return availableAgents.find(