@sentry/core 10.48.0 → 10.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/fetch.js +36 -17
- package/build/cjs/fetch.js.map +1 -1
- package/build/cjs/index.js +9 -5
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/integrations/conversationId.js +11 -0
- package/build/cjs/integrations/conversationId.js.map +1 -1
- package/build/cjs/integrations/express/index.js +44 -7
- package/build/cjs/integrations/express/index.js.map +1 -1
- package/build/cjs/integrations/express/patch-layer.js +7 -1
- package/build/cjs/integrations/express/patch-layer.js.map +1 -1
- package/build/cjs/integrations/express/types.js.map +1 -1
- package/build/cjs/integrations/requestdata.js.map +1 -1
- package/build/cjs/tracing/ai/gen-ai-attributes.js +0 -30
- package/build/cjs/tracing/ai/gen-ai-attributes.js.map +1 -1
- package/build/cjs/tracing/ai/utils.js +24 -0
- package/build/cjs/tracing/ai/utils.js.map +1 -1
- package/build/cjs/tracing/anthropic-ai/index.js +5 -5
- package/build/cjs/tracing/anthropic-ai/index.js.map +1 -1
- package/build/cjs/tracing/anthropic-ai/utils.js +4 -2
- package/build/cjs/tracing/anthropic-ai/utils.js.map +1 -1
- package/build/cjs/tracing/google-genai/index.js +16 -5
- package/build/cjs/tracing/google-genai/index.js.map +1 -1
- package/build/cjs/tracing/langchain/index.js +3 -0
- package/build/cjs/tracing/langchain/index.js.map +1 -1
- package/build/cjs/tracing/langchain/utils.js +12 -4
- package/build/cjs/tracing/langchain/utils.js.map +1 -1
- package/build/cjs/tracing/langgraph/index.js +4 -3
- package/build/cjs/tracing/langgraph/index.js.map +1 -1
- package/build/cjs/tracing/openai/index.js +12 -5
- package/build/cjs/tracing/openai/index.js.map +1 -1
- package/build/cjs/tracing/utils.js +3 -37
- package/build/cjs/tracing/utils.js.map +1 -1
- package/build/cjs/tracing/vercel-ai/constants.js +15 -23
- package/build/cjs/tracing/vercel-ai/constants.js.map +1 -1
- package/build/cjs/tracing/vercel-ai/index.js +32 -45
- package/build/cjs/tracing/vercel-ai/index.js.map +1 -1
- package/build/cjs/tracing/vercel-ai/utils.js +11 -39
- package/build/cjs/tracing/vercel-ai/utils.js.map +1 -1
- package/build/cjs/tracing/vercel-ai/vercel-ai-attributes.js +4 -1
- package/build/cjs/tracing/vercel-ai/vercel-ai-attributes.js.map +1 -1
- package/build/cjs/utils/browser.js +2 -3
- package/build/cjs/utils/browser.js.map +1 -1
- package/build/cjs/utils/version.js +1 -1
- package/build/cjs/utils/weakRef.js +62 -0
- package/build/cjs/utils/weakRef.js.map +1 -0
- package/build/esm/fetch.js +36 -17
- package/build/esm/fetch.js.map +1 -1
- package/build/esm/index.js +2 -1
- package/build/esm/index.js.map +1 -1
- package/build/esm/integrations/conversationId.js +11 -0
- package/build/esm/integrations/conversationId.js.map +1 -1
- package/build/esm/integrations/express/index.js +44 -7
- package/build/esm/integrations/express/index.js.map +1 -1
- package/build/esm/integrations/express/patch-layer.js +7 -1
- package/build/esm/integrations/express/patch-layer.js.map +1 -1
- package/build/esm/integrations/express/types.js.map +1 -1
- package/build/esm/integrations/requestdata.js.map +1 -1
- package/build/esm/package.json +1 -1
- package/build/esm/tracing/ai/gen-ai-attributes.js +1 -26
- package/build/esm/tracing/ai/gen-ai-attributes.js.map +1 -1
- package/build/esm/tracing/ai/utils.js +23 -1
- package/build/esm/tracing/ai/utils.js.map +1 -1
- package/build/esm/tracing/anthropic-ai/index.js +6 -6
- package/build/esm/tracing/anthropic-ai/index.js.map +1 -1
- package/build/esm/tracing/anthropic-ai/utils.js +5 -3
- package/build/esm/tracing/anthropic-ai/utils.js.map +1 -1
- package/build/esm/tracing/google-genai/index.js +17 -6
- package/build/esm/tracing/google-genai/index.js.map +1 -1
- package/build/esm/tracing/langchain/index.js +4 -1
- package/build/esm/tracing/langchain/index.js.map +1 -1
- package/build/esm/tracing/langchain/utils.js +13 -5
- package/build/esm/tracing/langchain/utils.js.map +1 -1
- package/build/esm/tracing/langgraph/index.js +5 -4
- package/build/esm/tracing/langgraph/index.js.map +1 -1
- package/build/esm/tracing/openai/index.js +13 -6
- package/build/esm/tracing/openai/index.js.map +1 -1
- package/build/esm/tracing/utils.js +3 -37
- package/build/esm/tracing/utils.js.map +1 -1
- package/build/esm/tracing/vercel-ai/constants.js +15 -19
- package/build/esm/tracing/vercel-ai/constants.js.map +1 -1
- package/build/esm/tracing/vercel-ai/index.js +29 -42
- package/build/esm/tracing/vercel-ai/index.js.map +1 -1
- package/build/esm/tracing/vercel-ai/utils.js +14 -41
- package/build/esm/tracing/vercel-ai/utils.js.map +1 -1
- package/build/esm/tracing/vercel-ai/vercel-ai-attributes.js +4 -1
- package/build/esm/tracing/vercel-ai/vercel-ai-attributes.js.map +1 -1
- package/build/esm/utils/browser.js +2 -3
- package/build/esm/utils/browser.js.map +1 -1
- package/build/esm/utils/version.js +1 -1
- package/build/esm/utils/weakRef.js +59 -0
- package/build/esm/utils/weakRef.js.map +1 -0
- package/build/types/build-time-plugins/buildTimeOptionsBase.d.ts +13 -0
- package/build/types/build-time-plugins/buildTimeOptionsBase.d.ts.map +1 -1
- package/build/types/fetch.d.ts +12 -8
- package/build/types/fetch.d.ts.map +1 -1
- package/build/types/index.d.ts +4 -1
- package/build/types/index.d.ts.map +1 -1
- package/build/types/integrations/conversationId.d.ts.map +1 -1
- package/build/types/integrations/express/index.d.ts +10 -3
- package/build/types/integrations/express/index.d.ts.map +1 -1
- package/build/types/integrations/express/patch-layer.d.ts +1 -1
- package/build/types/integrations/express/patch-layer.d.ts.map +1 -1
- package/build/types/integrations/express/types.d.ts +5 -1
- package/build/types/integrations/express/types.d.ts.map +1 -1
- package/build/types/integrations/requestdata.d.ts.map +1 -1
- package/build/types/tracing/ai/gen-ai-attributes.d.ts +0 -8
- package/build/types/tracing/ai/gen-ai-attributes.d.ts.map +1 -1
- package/build/types/tracing/ai/utils.d.ts +11 -0
- package/build/types/tracing/ai/utils.d.ts.map +1 -1
- package/build/types/tracing/anthropic-ai/index.d.ts.map +1 -1
- package/build/types/tracing/anthropic-ai/types.d.ts +5 -0
- package/build/types/tracing/anthropic-ai/types.d.ts.map +1 -1
- package/build/types/tracing/anthropic-ai/utils.d.ts +1 -1
- package/build/types/tracing/anthropic-ai/utils.d.ts.map +1 -1
- package/build/types/tracing/google-genai/index.d.ts.map +1 -1
- package/build/types/tracing/google-genai/types.d.ts +5 -0
- package/build/types/tracing/google-genai/types.d.ts.map +1 -1
- package/build/types/tracing/langchain/index.d.ts.map +1 -1
- package/build/types/tracing/langchain/types.d.ts +5 -0
- package/build/types/tracing/langchain/types.d.ts.map +1 -1
- package/build/types/tracing/langchain/utils.d.ts +2 -2
- package/build/types/tracing/langchain/utils.d.ts.map +1 -1
- package/build/types/tracing/langgraph/index.d.ts.map +1 -1
- package/build/types/tracing/langgraph/types.d.ts +5 -0
- package/build/types/tracing/langgraph/types.d.ts.map +1 -1
- package/build/types/tracing/openai/index.d.ts.map +1 -1
- package/build/types/tracing/openai/types.d.ts +5 -0
- package/build/types/tracing/openai/types.d.ts.map +1 -1
- package/build/types/tracing/utils.d.ts.map +1 -1
- package/build/types/tracing/vercel-ai/constants.d.ts +2 -5
- package/build/types/tracing/vercel-ai/constants.d.ts.map +1 -1
- package/build/types/tracing/vercel-ai/index.d.ts.map +1 -1
- package/build/types/tracing/vercel-ai/utils.d.ts +1 -5
- package/build/types/tracing/vercel-ai/utils.d.ts.map +1 -1
- package/build/types/tracing/vercel-ai/vercel-ai-attributes.d.ts +0 -480
- package/build/types/tracing/vercel-ai/vercel-ai-attributes.d.ts.map +1 -1
- package/build/types/types-hoist/view-hierarchy.d.ts +1 -0
- package/build/types/types-hoist/view-hierarchy.d.ts.map +1 -1
- package/build/types/utils/browser.d.ts +1 -1
- package/build/types/utils/browser.d.ts.map +1 -1
- package/build/types/utils/weakRef.d.ts +34 -0
- package/build/types/utils/weakRef.d.ts.map +1 -0
- package/build/types-ts3.8/build-time-plugins/buildTimeOptionsBase.d.ts +13 -0
- package/build/types-ts3.8/fetch.d.ts +14 -10
- package/build/types-ts3.8/index.d.ts +4 -1
- package/build/types-ts3.8/integrations/express/index.d.ts +10 -3
- package/build/types-ts3.8/integrations/express/patch-layer.d.ts +1 -1
- package/build/types-ts3.8/integrations/express/types.d.ts +5 -1
- package/build/types-ts3.8/tracing/ai/gen-ai-attributes.d.ts +0 -8
- package/build/types-ts3.8/tracing/ai/utils.d.ts +11 -0
- package/build/types-ts3.8/tracing/anthropic-ai/types.d.ts +5 -0
- package/build/types-ts3.8/tracing/anthropic-ai/utils.d.ts +1 -1
- package/build/types-ts3.8/tracing/google-genai/types.d.ts +5 -0
- package/build/types-ts3.8/tracing/langchain/types.d.ts +5 -0
- package/build/types-ts3.8/tracing/langchain/utils.d.ts +2 -2
- package/build/types-ts3.8/tracing/langgraph/types.d.ts +5 -0
- package/build/types-ts3.8/tracing/openai/types.d.ts +5 -0
- package/build/types-ts3.8/tracing/vercel-ai/constants.d.ts +2 -5
- package/build/types-ts3.8/tracing/vercel-ai/utils.d.ts +1 -5
- package/build/types-ts3.8/tracing/vercel-ai/vercel-ai-attributes.d.ts +0 -480
- package/build/types-ts3.8/types-hoist/view-hierarchy.d.ts +1 -0
- package/build/types-ts3.8/utils/browser.d.ts +1 -1
- package/build/types-ts3.8/utils/weakRef.d.ts +34 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gen-ai-attributes.js","sources":["../../../../src/tracing/ai/gen-ai-attributes.ts"],"sourcesContent":["/**\n * OpenAI Integration Telemetry Attributes\n * Based on OpenTelemetry Semantic Conventions for Generative AI\n * @see https://opentelemetry.io/docs/specs/semconv/gen-ai/\n */\n\n// =============================================================================\n// OPENTELEMETRY SEMANTIC CONVENTIONS FOR GENAI\n// =============================================================================\n\n/**\n * The input messages sent to the model\n */\nexport const GEN_AI_PROMPT_ATTRIBUTE = 'gen_ai.prompt';\n\n/**\n * The Generative AI system being used\n * For OpenAI, this should always be \"openai\"\n */\nexport const GEN_AI_SYSTEM_ATTRIBUTE = 'gen_ai.system';\n\n/**\n * The name of the model as requested\n * Examples: \"gpt-4\", \"gpt-3.5-turbo\"\n */\nexport const GEN_AI_REQUEST_MODEL_ATTRIBUTE = 'gen_ai.request.model';\n\n/**\n * Whether streaming was enabled for the request\n */\nexport const GEN_AI_REQUEST_STREAM_ATTRIBUTE = 'gen_ai.request.stream';\n\n/**\n * The temperature setting for the model request\n */\nexport const GEN_AI_REQUEST_TEMPERATURE_ATTRIBUTE = 'gen_ai.request.temperature';\n\n/**\n * The maximum number of tokens requested\n */\nexport const GEN_AI_REQUEST_MAX_TOKENS_ATTRIBUTE = 'gen_ai.request.max_tokens';\n\n/**\n * The frequency penalty setting for the model request\n */\nexport const GEN_AI_REQUEST_FREQUENCY_PENALTY_ATTRIBUTE = 'gen_ai.request.frequency_penalty';\n\n/**\n * The presence penalty setting for the model request\n */\nexport const GEN_AI_REQUEST_PRESENCE_PENALTY_ATTRIBUTE = 'gen_ai.request.presence_penalty';\n\n/**\n * The top_p (nucleus sampling) setting for the model request\n */\nexport const GEN_AI_REQUEST_TOP_P_ATTRIBUTE = 'gen_ai.request.top_p';\n\n/**\n * The top_k setting for the model request\n */\nexport const GEN_AI_REQUEST_TOP_K_ATTRIBUTE = 'gen_ai.request.top_k';\n\n/**\n * Stop sequences for the model request\n */\nexport const GEN_AI_REQUEST_STOP_SEQUENCES_ATTRIBUTE = 'gen_ai.request.stop_sequences';\n\n/**\n * The encoding format for the model request\n */\nexport const GEN_AI_REQUEST_ENCODING_FORMAT_ATTRIBUTE = 'gen_ai.request.encoding_format';\n\n/**\n * The dimensions for the model request\n */\nexport const GEN_AI_REQUEST_DIMENSIONS_ATTRIBUTE = 'gen_ai.request.dimensions';\n\n/**\n * Array of reasons why the model stopped generating tokens\n */\nexport const GEN_AI_RESPONSE_FINISH_REASONS_ATTRIBUTE = 'gen_ai.response.finish_reasons';\n\n/**\n * The name of the model that generated the response\n */\nexport const GEN_AI_RESPONSE_MODEL_ATTRIBUTE = 'gen_ai.response.model';\n\n/**\n * The unique identifier for the response\n */\nexport const GEN_AI_RESPONSE_ID_ATTRIBUTE = 'gen_ai.response.id';\n\n/**\n * The reason why the model stopped generating tokens\n */\nexport const GEN_AI_RESPONSE_STOP_REASON_ATTRIBUTE = 'gen_ai.response.stop_reason';\n\n/**\n * The number of tokens used in the prompt\n */\nexport const GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE = 'gen_ai.usage.input_tokens';\n\n/**\n * The number of tokens used in the response\n */\nexport const GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE = 'gen_ai.usage.output_tokens';\n\n/**\n * The total number of tokens used (input + output)\n */\nexport const GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE = 'gen_ai.usage.total_tokens';\n\n/**\n * The operation name\n */\nexport const GEN_AI_OPERATION_NAME_ATTRIBUTE = 'gen_ai.operation.name';\n\n/**\n * Original length of messages array, used to indicate truncations had occured\n */\nexport const GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE = 'sentry.sdk_meta.gen_ai.input.messages.original_length';\n\n/**\n * The prompt messages\n * Only recorded when recordInputs is enabled\n */\nexport const GEN_AI_INPUT_MESSAGES_ATTRIBUTE = 'gen_ai.input.messages';\n\n/**\n * The model's response messages including text and tool calls\n * Only recorded when recordOutputs is enabled\n * Format: stringified array of message objects with role, parts, and finish_reason\n * @see https://opentelemetry.io/docs/specs/semconv/registry/attributes/gen-ai/#gen-ai-output-messages\n */\nexport const GEN_AI_OUTPUT_MESSAGES_ATTRIBUTE = 'gen_ai.output.messages';\n\n/**\n * The system instructions extracted from system messages\n * Only recorded when recordInputs is enabled\n * According to OpenTelemetry spec: https://opentelemetry.io/docs/specs/semconv/registry/attributes/gen-ai/#gen-ai-system-instructions\n */\nexport const GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE = 'gen_ai.system_instructions';\n\n/**\n * The response text\n * Only recorded when recordOutputs is enabled\n */\nexport const GEN_AI_RESPONSE_TEXT_ATTRIBUTE = 'gen_ai.response.text';\n\n/**\n * The available tools from incoming request\n * Only recorded when recordInputs is enabled\n */\nexport const GEN_AI_REQUEST_AVAILABLE_TOOLS_ATTRIBUTE = 'gen_ai.request.available_tools';\n\n/**\n * Whether the response is a streaming response\n */\nexport const GEN_AI_RESPONSE_STREAMING_ATTRIBUTE = 'gen_ai.response.streaming';\n\n/**\n * The tool calls from the response\n * Only recorded when recordOutputs is enabled\n */\nexport const GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE = 'gen_ai.response.tool_calls';\n\n/**\n * The agent name\n */\nexport const GEN_AI_AGENT_NAME_ATTRIBUTE = 'gen_ai.agent.name';\n\n/**\n * The pipeline name\n */\nexport const GEN_AI_PIPELINE_NAME_ATTRIBUTE = 'gen_ai.pipeline.name';\n\n/**\n * The conversation ID for linking messages across API calls\n * For OpenAI Assistants API: thread_id\n * For LangGraph: configurable.thread_id\n */\nexport const GEN_AI_CONVERSATION_ID_ATTRIBUTE = 'gen_ai.conversation.id';\n\n/**\n * The number of cache creation input tokens used\n */\nexport const GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS_ATTRIBUTE = 'gen_ai.usage.cache_creation_input_tokens';\n\n/**\n * The number of cache read input tokens used\n */\nexport const GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS_ATTRIBUTE = 'gen_ai.usage.cache_read_input_tokens';\n\n/**\n * The number of cache write input tokens used\n */\nexport const GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE_ATTRIBUTE = 'gen_ai.usage.input_tokens.cache_write';\n\n/**\n * The number of cached input tokens that were used\n */\nexport const GEN_AI_USAGE_INPUT_TOKENS_CACHED_ATTRIBUTE = 'gen_ai.usage.input_tokens.cached';\n\n/**\n * The span operation name for invoking an agent\n */\nexport const GEN_AI_INVOKE_AGENT_OPERATION_ATTRIBUTE = 'gen_ai.invoke_agent';\n\n/**\n * The span operation name for generating content\n */\nexport const GEN_AI_GENERATE_CONTENT_OPERATION_ATTRIBUTE = 'gen_ai.generate_content';\n\n/**\n * The embeddings input\n * Only recorded when recordInputs is enabled\n */\nexport const GEN_AI_EMBEDDINGS_INPUT_ATTRIBUTE = 'gen_ai.embeddings.input';\n\n/**\n * The span operation for embeddings\n */\nexport const GEN_AI_EMBEDDINGS_OPERATION_ATTRIBUTE = 'gen_ai.embeddings';\n\n/**\n * The span operation name for embedding\n */\nexport const GEN_AI_EMBED_DO_EMBED_OPERATION_ATTRIBUTE = 'gen_ai.embeddings';\n\n/**\n * The span operation name for embedding many\n */\nexport const GEN_AI_EMBED_MANY_DO_EMBED_OPERATION_ATTRIBUTE = 'gen_ai.embeddings';\n\n/**\n * The span operation name for reranking\n */\nexport const GEN_AI_RERANK_DO_RERANK_OPERATION_ATTRIBUTE = 'gen_ai.rerank';\n\n/**\n * The span operation name for executing a tool\n */\nexport const GEN_AI_EXECUTE_TOOL_OPERATION_ATTRIBUTE = 'gen_ai.execute_tool';\n\n/**\n * The tool name for tool call spans\n */\nexport const GEN_AI_TOOL_NAME_ATTRIBUTE = 'gen_ai.tool.name';\n\n/**\n * The tool call ID\n */\nexport const GEN_AI_TOOL_CALL_ID_ATTRIBUTE = 'gen_ai.tool.call.id';\n\n/**\n * The tool type (e.g., 'function')\n */\nexport const GEN_AI_TOOL_TYPE_ATTRIBUTE = 'gen_ai.tool.type';\n\n/**\n * The tool input/arguments\n */\nexport const GEN_AI_TOOL_INPUT_ATTRIBUTE = 'gen_ai.tool.input';\n\n/**\n * The tool output/result\n */\nexport const GEN_AI_TOOL_OUTPUT_ATTRIBUTE = 'gen_ai.tool.output';\n\n/**\n * The description of the tool being used\n * @see https://opentelemetry.io/docs/specs/semconv/registry/attributes/gen-ai/#gen-ai-tool-description\n */\nexport const GEN_AI_TOOL_DESCRIPTION_ATTRIBUTE = 'gen_ai.tool.description';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"gen-ai-attributes.js","sources":["../../../../src/tracing/ai/gen-ai-attributes.ts"],"sourcesContent":["/**\n * OpenAI Integration Telemetry Attributes\n * Based on OpenTelemetry Semantic Conventions for Generative AI\n * @see https://opentelemetry.io/docs/specs/semconv/gen-ai/\n */\n\n// =============================================================================\n// OPENTELEMETRY SEMANTIC CONVENTIONS FOR GENAI\n// =============================================================================\n\n/**\n * The input messages sent to the model\n */\nexport const GEN_AI_PROMPT_ATTRIBUTE = 'gen_ai.prompt';\n\n/**\n * The Generative AI system being used\n * For OpenAI, this should always be \"openai\"\n */\nexport const GEN_AI_SYSTEM_ATTRIBUTE = 'gen_ai.system';\n\n/**\n * The name of the model as requested\n * Examples: \"gpt-4\", \"gpt-3.5-turbo\"\n */\nexport const GEN_AI_REQUEST_MODEL_ATTRIBUTE = 'gen_ai.request.model';\n\n/**\n * Whether streaming was enabled for the request\n */\nexport const GEN_AI_REQUEST_STREAM_ATTRIBUTE = 'gen_ai.request.stream';\n\n/**\n * The temperature setting for the model request\n */\nexport const GEN_AI_REQUEST_TEMPERATURE_ATTRIBUTE = 'gen_ai.request.temperature';\n\n/**\n * The maximum number of tokens requested\n */\nexport const GEN_AI_REQUEST_MAX_TOKENS_ATTRIBUTE = 'gen_ai.request.max_tokens';\n\n/**\n * The frequency penalty setting for the model request\n */\nexport const GEN_AI_REQUEST_FREQUENCY_PENALTY_ATTRIBUTE = 'gen_ai.request.frequency_penalty';\n\n/**\n * The presence penalty setting for the model request\n */\nexport const GEN_AI_REQUEST_PRESENCE_PENALTY_ATTRIBUTE = 'gen_ai.request.presence_penalty';\n\n/**\n * The top_p (nucleus sampling) setting for the model request\n */\nexport const GEN_AI_REQUEST_TOP_P_ATTRIBUTE = 'gen_ai.request.top_p';\n\n/**\n * The top_k setting for the model request\n */\nexport const GEN_AI_REQUEST_TOP_K_ATTRIBUTE = 'gen_ai.request.top_k';\n\n/**\n * Stop sequences for the model request\n */\nexport const GEN_AI_REQUEST_STOP_SEQUENCES_ATTRIBUTE = 'gen_ai.request.stop_sequences';\n\n/**\n * The encoding format for the model request\n */\nexport const GEN_AI_REQUEST_ENCODING_FORMAT_ATTRIBUTE = 'gen_ai.request.encoding_format';\n\n/**\n * The dimensions for the model request\n */\nexport const GEN_AI_REQUEST_DIMENSIONS_ATTRIBUTE = 'gen_ai.request.dimensions';\n\n/**\n * Array of reasons why the model stopped generating tokens\n */\nexport const GEN_AI_RESPONSE_FINISH_REASONS_ATTRIBUTE = 'gen_ai.response.finish_reasons';\n\n/**\n * The name of the model that generated the response\n */\nexport const GEN_AI_RESPONSE_MODEL_ATTRIBUTE = 'gen_ai.response.model';\n\n/**\n * The unique identifier for the response\n */\nexport const GEN_AI_RESPONSE_ID_ATTRIBUTE = 'gen_ai.response.id';\n\n/**\n * The reason why the model stopped generating tokens\n */\nexport const GEN_AI_RESPONSE_STOP_REASON_ATTRIBUTE = 'gen_ai.response.stop_reason';\n\n/**\n * The number of tokens used in the prompt\n */\nexport const GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE = 'gen_ai.usage.input_tokens';\n\n/**\n * The number of tokens used in the response\n */\nexport const GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE = 'gen_ai.usage.output_tokens';\n\n/**\n * The total number of tokens used (input + output)\n */\nexport const GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE = 'gen_ai.usage.total_tokens';\n\n/**\n * The operation name\n */\nexport const GEN_AI_OPERATION_NAME_ATTRIBUTE = 'gen_ai.operation.name';\n\n/**\n * Original length of messages array, used to indicate truncations had occured\n */\nexport const GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE = 'sentry.sdk_meta.gen_ai.input.messages.original_length';\n\n/**\n * The prompt messages\n * Only recorded when recordInputs is enabled\n */\nexport const GEN_AI_INPUT_MESSAGES_ATTRIBUTE = 'gen_ai.input.messages';\n\n/**\n * The model's response messages including text and tool calls\n * Only recorded when recordOutputs is enabled\n * Format: stringified array of message objects with role, parts, and finish_reason\n * @see https://opentelemetry.io/docs/specs/semconv/registry/attributes/gen-ai/#gen-ai-output-messages\n */\nexport const GEN_AI_OUTPUT_MESSAGES_ATTRIBUTE = 'gen_ai.output.messages';\n\n/**\n * The system instructions extracted from system messages\n * Only recorded when recordInputs is enabled\n * According to OpenTelemetry spec: https://opentelemetry.io/docs/specs/semconv/registry/attributes/gen-ai/#gen-ai-system-instructions\n */\nexport const GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE = 'gen_ai.system_instructions';\n\n/**\n * The response text\n * Only recorded when recordOutputs is enabled\n */\nexport const GEN_AI_RESPONSE_TEXT_ATTRIBUTE = 'gen_ai.response.text';\n\n/**\n * The available tools from incoming request\n * Only recorded when recordInputs is enabled\n */\nexport const GEN_AI_REQUEST_AVAILABLE_TOOLS_ATTRIBUTE = 'gen_ai.request.available_tools';\n\n/**\n * Whether the response is a streaming response\n */\nexport const GEN_AI_RESPONSE_STREAMING_ATTRIBUTE = 'gen_ai.response.streaming';\n\n/**\n * The tool calls from the response\n * Only recorded when recordOutputs is enabled\n */\nexport const GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE = 'gen_ai.response.tool_calls';\n\n/**\n * The agent name\n */\nexport const GEN_AI_AGENT_NAME_ATTRIBUTE = 'gen_ai.agent.name';\n\n/**\n * The pipeline name\n */\nexport const GEN_AI_PIPELINE_NAME_ATTRIBUTE = 'gen_ai.pipeline.name';\n\n/**\n * The conversation ID for linking messages across API calls\n * For OpenAI Assistants API: thread_id\n * For LangGraph: configurable.thread_id\n */\nexport const GEN_AI_CONVERSATION_ID_ATTRIBUTE = 'gen_ai.conversation.id';\n\n/**\n * The number of cache creation input tokens used\n */\nexport const GEN_AI_USAGE_CACHE_CREATION_INPUT_TOKENS_ATTRIBUTE = 'gen_ai.usage.cache_creation_input_tokens';\n\n/**\n * The number of cache read input tokens used\n */\nexport const GEN_AI_USAGE_CACHE_READ_INPUT_TOKENS_ATTRIBUTE = 'gen_ai.usage.cache_read_input_tokens';\n\n/**\n * The number of cache write input tokens used\n */\nexport const GEN_AI_USAGE_INPUT_TOKENS_CACHE_WRITE_ATTRIBUTE = 'gen_ai.usage.input_tokens.cache_write';\n\n/**\n * The number of cached input tokens that were used\n */\nexport const GEN_AI_USAGE_INPUT_TOKENS_CACHED_ATTRIBUTE = 'gen_ai.usage.input_tokens.cached';\n\n/**\n * The span operation name for invoking an agent\n */\nexport const GEN_AI_INVOKE_AGENT_OPERATION_ATTRIBUTE = 'gen_ai.invoke_agent';\n\n/**\n * The span operation name for generating content\n */\nexport const GEN_AI_GENERATE_CONTENT_OPERATION_ATTRIBUTE = 'gen_ai.generate_content';\n\n/**\n * The embeddings input\n * Only recorded when recordInputs is enabled\n */\nexport const GEN_AI_EMBEDDINGS_INPUT_ATTRIBUTE = 'gen_ai.embeddings.input';\n\n/**\n * The span operation for embeddings\n */\nexport const GEN_AI_EMBEDDINGS_OPERATION_ATTRIBUTE = 'gen_ai.embeddings';\n\n/**\n * The span operation name for reranking\n */\nexport const GEN_AI_RERANK_DO_RERANK_OPERATION_ATTRIBUTE = 'gen_ai.rerank';\n\n/**\n * The span operation name for executing a tool\n */\nexport const GEN_AI_EXECUTE_TOOL_OPERATION_ATTRIBUTE = 'gen_ai.execute_tool';\n\n/**\n * The tool name for tool call spans\n */\nexport const GEN_AI_TOOL_NAME_ATTRIBUTE = 'gen_ai.tool.name';\n\n/**\n * The tool call ID\n */\nexport const GEN_AI_TOOL_CALL_ID_ATTRIBUTE = 'gen_ai.tool.call.id';\n\n/**\n * The tool type (e.g., 'function')\n */\nexport const GEN_AI_TOOL_TYPE_ATTRIBUTE = 'gen_ai.tool.type';\n\n/**\n * The tool input/arguments\n */\nexport const GEN_AI_TOOL_INPUT_ATTRIBUTE = 'gen_ai.tool.input';\n\n/**\n * The tool output/result\n */\nexport const GEN_AI_TOOL_OUTPUT_ATTRIBUTE = 'gen_ai.tool.output';\n\n/**\n * The description of the tool being used\n * @see https://opentelemetry.io/docs/specs/semconv/registry/attributes/gen-ai/#gen-ai-tool-description\n */\nexport const GEN_AI_TOOL_DESCRIPTION_ATTRIBUTE = 'gen_ai.tool.description';\n"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACO,MAAM,uBAAA,GAA0B;;AAEvC;AACA;AACA;AACA;AACO,MAAM,uBAAA,GAA0B;;AAEvC;AACA;AACA;AACA;AACO,MAAM,8BAAA,GAAiC;;AAE9C;AACA;AACA;AACO,MAAM,+BAAA,GAAkC;;AAE/C;AACA;AACA;AACO,MAAM,oCAAA,GAAuC;;AAEpD;AACA;AACA;AACO,MAAM,mCAAA,GAAsC;;AAEnD;AACA;AACA;AACO,MAAM,0CAAA,GAA6C;;AAE1D;AACA;AACA;AACO,MAAM,yCAAA,GAA4C;;AAEzD;AACA;AACA;AACO,MAAM,8BAAA,GAAiC;;AAE9C;AACA;AACA;AACO,MAAM,8BAAA,GAAiC;;AAO9C;AACA;AACA;AACO,MAAM,wCAAA,GAA2C;;AAExD;AACA;AACA;AACO,MAAM,mCAAA,GAAsC;;AAEnD;AACA;AACA;AACO,MAAM,wCAAA,GAA2C;;AAExD;AACA;AACA;AACO,MAAM,+BAAA,GAAkC;;AAE/C;AACA;AACA;AACO,MAAM,4BAAA,GAA+B;;AAE5C;AACA;AACA;AACO,MAAM,qCAAA,GAAwC;;AAErD;AACA;AACA;AACO,MAAM,mCAAA,GAAsC;;AAEnD;AACA;AACA;AACO,MAAM,oCAAA,GAAuC;;AAEpD;AACA;AACA;AACO,MAAM,mCAAA,GAAsC;;AAEnD;AACA;AACA;AACO,MAAM,+BAAA,GAAkC;;AAE/C;AACA;AACA;AACO,MAAM,+CAAA,GAAkD;;AAE/D;AACA;AACA;AACA;AACO,MAAM,+BAAA,GAAkC;;AAE/C;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,gCAAA,GAAmC;;AAEhD;AACA;AACA;AACA;AACA;AACO,MAAM,oCAAA,GAAuC;;AAEpD;AACA;AACA;AACA;AACO,MAAM,8BAAA,GAAiC;;AAE9C;AACA;AACA;AACA;AACO,MAAM,wCAAA,GAA2C;;AAExD;AACA;AACA;AACO,MAAM,mCAAA,GAAsC;;AAEnD;AACA;AACA;AACA;AACO,MAAM,oCAAA,GAAuC;;AAEpD;AACA;AACA;AACO,MAAM,2BAAA,GAA8B;;AAE3C;AACA;AACA;AACO,MAAM,8BAAA,GAAiC;;AAE9C;AACA;AACA;AACA;AACA;AACO,MAAM,gCAAA,GAAmC;;AAEhD;AACA;AACA;AACO,MAAM,kDAAA,GAAqD;;AAElE;AACA;AACA;AACO,MAAM,8CAAA,GAAiD;;AAE9D;AACA;AACA;AACO,MAAM,+CAAA,GAAkD;;AAE/D;AACA;AACA;AACO,MAAM,0CAAA,GAA6C;;AAE1D;AACA;AACA;AACO,MAAM,uCAAA,GAA0C;;AAOvD;AACA;AACA;AACA;AACO,MAAM,iCAAA,GAAoC;;AAEjD;AACA;AACA;AACO,MAAM,qCAAA,GAAwC;;AAYrD;AACA;AACA;AACO,MAAM,0BAAA,GAA6B;;AAE1C;AACA;AACA;AACO,MAAM,6BAAA,GAAgC;;AAE7C;AACA;AACA;AACO,MAAM,0BAAA,GAA6B;;AAE1C;AACA;AACA;AACO,MAAM,2BAAA,GAA8B;;AAE3C;AACA;AACA;AACO,MAAM,4BAAA,GAA+B;;AAE5C;AACA;AACA;AACA;AACO,MAAM,iCAAA,GAAoC;;;;"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { captureException } from '../../exports.js';
|
|
2
2
|
import { getClient } from '../../currentScopes.js';
|
|
3
|
+
import { hasSpanStreamingEnabled } from '../spans/hasSpanStreamingEnabled.js';
|
|
3
4
|
import { isThenable } from '../../utils/is.js';
|
|
4
5
|
import { GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE, GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE, GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE, GEN_AI_RESPONSE_STREAMING_ATTRIBUTE, GEN_AI_RESPONSE_ID_ATTRIBUTE, GEN_AI_RESPONSE_MODEL_ATTRIBUTE, GEN_AI_RESPONSE_FINISH_REASONS_ATTRIBUTE, GEN_AI_RESPONSE_TEXT_ATTRIBUTE, GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE } from './gen-ai-attributes.js';
|
|
5
6
|
import { truncateGenAiStringInput, truncateGenAiMessages } from './messageTruncation.js';
|
|
@@ -21,6 +22,16 @@ function resolveAIRecordingOptions(options) {
|
|
|
21
22
|
} ;
|
|
22
23
|
}
|
|
23
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Resolves whether truncation should be enabled.
|
|
27
|
+
* If the user explicitly set `enableTruncation`, that value is used.
|
|
28
|
+
* Otherwise, truncation is disabled when span streaming is active.
|
|
29
|
+
*/
|
|
30
|
+
function shouldEnableTruncation(enableTruncation) {
|
|
31
|
+
const client = getClient();
|
|
32
|
+
return enableTruncation ?? !(client && hasSpanStreamingEnabled(client));
|
|
33
|
+
}
|
|
34
|
+
|
|
24
35
|
/**
|
|
25
36
|
* Build method path from current traversal
|
|
26
37
|
*/
|
|
@@ -121,6 +132,17 @@ function endStreamSpan(span, state, recordOutputs) {
|
|
|
121
132
|
span.end();
|
|
122
133
|
}
|
|
123
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Serialize a value to a JSON string without truncation.
|
|
137
|
+
* Strings are returned as-is, arrays and objects are JSON-stringified.
|
|
138
|
+
*/
|
|
139
|
+
function getJsonString(value) {
|
|
140
|
+
if (typeof value === 'string') {
|
|
141
|
+
return value;
|
|
142
|
+
}
|
|
143
|
+
return JSON.stringify(value);
|
|
144
|
+
}
|
|
145
|
+
|
|
124
146
|
/**
|
|
125
147
|
* Get the truncated JSON string for a string or array of strings.
|
|
126
148
|
*
|
|
@@ -259,5 +281,5 @@ function wrapPromiseWithMethods(
|
|
|
259
281
|
}) ;
|
|
260
282
|
}
|
|
261
283
|
|
|
262
|
-
export { buildMethodPath, endStreamSpan, extractSystemInstructions, getTruncatedJsonString, resolveAIRecordingOptions, setTokenUsageAttributes, wrapPromiseWithMethods };
|
|
284
|
+
export { buildMethodPath, endStreamSpan, extractSystemInstructions, getJsonString, getTruncatedJsonString, resolveAIRecordingOptions, setTokenUsageAttributes, shouldEnableTruncation, wrapPromiseWithMethods };
|
|
263
285
|
//# sourceMappingURL=utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sources":["../../../../src/tracing/ai/utils.ts"],"sourcesContent":["/**\n * Shared utils for AI integrations (OpenAI, Anthropic, Verce.AI, etc.)\n */\nimport { captureException } from '../../exports';\nimport { getClient } from '../../currentScopes';\nimport type { Span } from '../../types-hoist/span';\nimport { isThenable } from '../../utils/is';\nimport {\n GEN_AI_RESPONSE_FINISH_REASONS_ATTRIBUTE,\n GEN_AI_RESPONSE_ID_ATTRIBUTE,\n GEN_AI_RESPONSE_MODEL_ATTRIBUTE,\n GEN_AI_RESPONSE_STREAMING_ATTRIBUTE,\n GEN_AI_RESPONSE_TEXT_ATTRIBUTE,\n GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE,\n GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE,\n GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE,\n GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE,\n} from './gen-ai-attributes';\nimport { truncateGenAiMessages, truncateGenAiStringInput } from './messageTruncation';\n\nexport interface AIRecordingOptions {\n recordInputs?: boolean;\n recordOutputs?: boolean;\n}\n\n/**\n * A method registry entry describes a single instrumented method:\n * which gen_ai operation it maps to and whether it is intrinsically streaming.\n */\nexport interface InstrumentedMethodEntry {\n /** Operation name (e.g. 'chat', 'embeddings', 'generate_content'). Omit for factory methods that only need result proxying. */\n operation?: string;\n /** True if the method itself is always streaming (not param-based) */\n streaming?: boolean;\n /** When set, the method's return value is re-proxied with this as the base path */\n proxyResultPath?: string;\n}\n\n/**\n * Maps method paths to their registry entries.\n * Used by proxy-based AI client instrumentations to determine which methods\n * to instrument, what operation name to use, and whether they stream.\n */\nexport type InstrumentedMethodRegistry = Record<string, InstrumentedMethodEntry>;\n\n/**\n * Resolves AI recording options by falling back to the client's `sendDefaultPii` setting.\n * Precedence: explicit option > sendDefaultPii > false\n */\nexport function resolveAIRecordingOptions<T extends AIRecordingOptions>(options?: T): T & Required<AIRecordingOptions> {\n const sendDefaultPii = Boolean(getClient()?.getOptions().sendDefaultPii);\n return {\n ...options,\n recordInputs: options?.recordInputs ?? sendDefaultPii,\n recordOutputs: options?.recordOutputs ?? sendDefaultPii,\n } as T & Required<AIRecordingOptions>;\n}\n\n/**\n * Build method path from current traversal\n */\nexport function buildMethodPath(currentPath: string, prop: string): string {\n return currentPath ? `${currentPath}.${prop}` : prop;\n}\n\n/**\n * Set token usage attributes\n * @param span - The span to add attributes to\n * @param promptTokens - The number of prompt tokens\n * @param completionTokens - The number of completion tokens\n * @param cachedInputTokens - The number of cached input tokens\n * @param cachedOutputTokens - The number of cached output tokens\n */\nexport function setTokenUsageAttributes(\n span: Span,\n promptTokens?: number,\n completionTokens?: number,\n cachedInputTokens?: number,\n cachedOutputTokens?: number,\n): void {\n if (promptTokens !== undefined) {\n span.setAttributes({\n [GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE]: promptTokens,\n });\n }\n if (completionTokens !== undefined) {\n span.setAttributes({\n [GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE]: completionTokens,\n });\n }\n if (\n promptTokens !== undefined ||\n completionTokens !== undefined ||\n cachedInputTokens !== undefined ||\n cachedOutputTokens !== undefined\n ) {\n /**\n * Total input tokens in a request is the summation of `input_tokens`,\n * `cache_creation_input_tokens`, and `cache_read_input_tokens`.\n */\n const totalTokens =\n (promptTokens ?? 0) + (completionTokens ?? 0) + (cachedInputTokens ?? 0) + (cachedOutputTokens ?? 0);\n\n span.setAttributes({\n [GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE]: totalTokens,\n });\n }\n}\n\nexport interface StreamResponseState {\n responseId?: string;\n responseModel?: string;\n finishReasons: string[];\n responseTexts: string[];\n toolCalls: unknown[];\n promptTokens?: number;\n completionTokens?: number;\n totalTokens?: number;\n cacheCreationInputTokens?: number;\n cacheReadInputTokens?: number;\n}\n\n/**\n * Ends a streaming span by setting all accumulated response attributes and ending the span.\n * Shared across OpenAI, Anthropic, and Google GenAI streaming implementations.\n */\nexport function endStreamSpan(span: Span, state: StreamResponseState, recordOutputs: boolean): void {\n if (!span.isRecording()) {\n return;\n }\n\n const attrs: Record<string, string | number | boolean> = {\n [GEN_AI_RESPONSE_STREAMING_ATTRIBUTE]: true,\n };\n\n if (state.responseId) attrs[GEN_AI_RESPONSE_ID_ATTRIBUTE] = state.responseId;\n if (state.responseModel) attrs[GEN_AI_RESPONSE_MODEL_ATTRIBUTE] = state.responseModel;\n\n if (state.promptTokens !== undefined) attrs[GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE] = state.promptTokens;\n if (state.completionTokens !== undefined) attrs[GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE] = state.completionTokens;\n\n // Use explicit total if provided (OpenAI, Google), otherwise compute from cache tokens (Anthropic)\n if (state.totalTokens !== undefined) {\n attrs[GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE] = state.totalTokens;\n } else if (\n state.promptTokens !== undefined ||\n state.completionTokens !== undefined ||\n state.cacheCreationInputTokens !== undefined ||\n state.cacheReadInputTokens !== undefined\n ) {\n attrs[GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE] =\n (state.promptTokens ?? 0) +\n (state.completionTokens ?? 0) +\n (state.cacheCreationInputTokens ?? 0) +\n (state.cacheReadInputTokens ?? 0);\n }\n\n if (state.finishReasons.length) {\n attrs[GEN_AI_RESPONSE_FINISH_REASONS_ATTRIBUTE] = JSON.stringify(state.finishReasons);\n }\n if (recordOutputs && state.responseTexts.length) {\n attrs[GEN_AI_RESPONSE_TEXT_ATTRIBUTE] = state.responseTexts.join('');\n }\n if (recordOutputs && state.toolCalls.length) {\n attrs[GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE] = JSON.stringify(state.toolCalls);\n }\n\n span.setAttributes(attrs);\n span.end();\n}\n\n/**\n * Get the truncated JSON string for a string or array of strings.\n *\n * @param value - The string or array of strings to truncate\n * @returns The truncated JSON string\n */\nexport function getTruncatedJsonString<T>(value: T | T[]): string {\n if (typeof value === 'string') {\n // Some values are already JSON strings, so we don't need to duplicate the JSON parsing\n return truncateGenAiStringInput(value);\n }\n if (Array.isArray(value)) {\n // truncateGenAiMessages returns an array of strings, so we need to stringify it\n const truncatedMessages = truncateGenAiMessages(value);\n return JSON.stringify(truncatedMessages);\n }\n // value is an object, so we need to stringify it\n return JSON.stringify(value);\n}\n\n/**\n * Extract system instructions from messages array.\n * Finds the first system message and formats it according to OpenTelemetry semantic conventions.\n *\n * @param messages - Array of messages to extract system instructions from\n * @returns systemInstructions (JSON string) and filteredMessages (without system message)\n */\nexport function extractSystemInstructions(messages: unknown[] | unknown): {\n systemInstructions: string | undefined;\n filteredMessages: unknown[] | unknown;\n} {\n if (!Array.isArray(messages)) {\n return { systemInstructions: undefined, filteredMessages: messages };\n }\n\n const systemMessageIndex = messages.findIndex(\n msg => msg && typeof msg === 'object' && 'role' in msg && (msg as { role: string }).role === 'system',\n );\n\n if (systemMessageIndex === -1) {\n return { systemInstructions: undefined, filteredMessages: messages };\n }\n\n const systemMessage = messages[systemMessageIndex] as { role: string; content?: string | unknown };\n const systemContent =\n typeof systemMessage.content === 'string'\n ? systemMessage.content\n : systemMessage.content !== undefined\n ? JSON.stringify(systemMessage.content)\n : undefined;\n\n if (!systemContent) {\n return { systemInstructions: undefined, filteredMessages: messages };\n }\n\n const systemInstructions = JSON.stringify([{ type: 'text', content: systemContent }]);\n const filteredMessages = [...messages.slice(0, systemMessageIndex), ...messages.slice(systemMessageIndex + 1)];\n\n return { systemInstructions, filteredMessages };\n}\n\n/**\n * Creates a wrapped version of .withResponse() that replaces the data field\n * with the instrumented result while preserving metadata (response, request_id).\n */\nasync function createWithResponseWrapper<T>(\n originalWithResponse: Promise<unknown>,\n instrumentedPromise: Promise<T>,\n mechanismType: string,\n): Promise<unknown> {\n // Attach catch handler to originalWithResponse immediately to prevent unhandled rejection\n // If instrumentedPromise rejects first, we still need this handled\n const safeOriginalWithResponse = originalWithResponse.catch(error => {\n captureException(error, {\n mechanism: {\n handled: false,\n type: mechanismType,\n },\n });\n throw error;\n });\n\n const instrumentedResult = await instrumentedPromise;\n const originalWrapper = await safeOriginalWithResponse;\n\n // Combine instrumented result with original metadata\n if (originalWrapper && typeof originalWrapper === 'object' && 'data' in originalWrapper) {\n return {\n ...originalWrapper,\n data: instrumentedResult,\n };\n }\n return instrumentedResult;\n}\n\n/**\n * Wraps a promise-like object to preserve additional methods (like .withResponse())\n * that AI SDK clients (OpenAI, Anthropic) attach to their APIPromise return values.\n *\n * Standard Promise methods (.then, .catch, .finally) are routed to the instrumented\n * promise to preserve Sentry's span instrumentation, while custom SDK methods are\n * forwarded to the original promise to maintain the SDK's API surface.\n */\nexport function wrapPromiseWithMethods<R>(\n originalPromiseLike: Promise<R>,\n instrumentedPromise: Promise<R>,\n mechanismType: string,\n): Promise<R> {\n // If the original result is not thenable, return the instrumented promise\n if (!isThenable(originalPromiseLike)) {\n return instrumentedPromise;\n }\n\n // Create a proxy that forwards Promise methods to instrumentedPromise\n // and preserves additional methods from the original result\n return new Proxy(originalPromiseLike, {\n get(target: object, prop: string | symbol): unknown {\n // For standard Promise methods (.then, .catch, .finally, Symbol.toStringTag),\n // use instrumentedPromise to preserve Sentry instrumentation.\n // For custom methods (like .withResponse()), use the original target.\n const useInstrumentedPromise = prop in Promise.prototype || prop === Symbol.toStringTag;\n const source = useInstrumentedPromise ? instrumentedPromise : target;\n\n const value = Reflect.get(source, prop) as unknown;\n\n // Special handling for .withResponse() to preserve instrumentation\n // .withResponse() returns { data: T, response: Response, request_id: string }\n if (prop === 'withResponse' && typeof value === 'function') {\n return function wrappedWithResponse(this: unknown): unknown {\n const originalWithResponse = (value as (...args: unknown[]) => unknown).call(target);\n return createWithResponseWrapper(originalWithResponse, instrumentedPromise, mechanismType);\n };\n }\n\n return typeof value === 'function' ? value.bind(source) : value;\n },\n }) as Promise<R>;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../../../src/tracing/ai/utils.ts"],"sourcesContent":["/**\n * Shared utils for AI integrations (OpenAI, Anthropic, Verce.AI, etc.)\n */\nimport { captureException } from '../../exports';\nimport { getClient } from '../../currentScopes';\nimport { hasSpanStreamingEnabled } from '../spans/hasSpanStreamingEnabled';\nimport type { Span } from '../../types-hoist/span';\nimport { isThenable } from '../../utils/is';\nimport {\n GEN_AI_RESPONSE_FINISH_REASONS_ATTRIBUTE,\n GEN_AI_RESPONSE_ID_ATTRIBUTE,\n GEN_AI_RESPONSE_MODEL_ATTRIBUTE,\n GEN_AI_RESPONSE_STREAMING_ATTRIBUTE,\n GEN_AI_RESPONSE_TEXT_ATTRIBUTE,\n GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE,\n GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE,\n GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE,\n GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE,\n} from './gen-ai-attributes';\nimport { truncateGenAiMessages, truncateGenAiStringInput } from './messageTruncation';\n\nexport interface AIRecordingOptions {\n recordInputs?: boolean;\n recordOutputs?: boolean;\n}\n\n/**\n * A method registry entry describes a single instrumented method:\n * which gen_ai operation it maps to and whether it is intrinsically streaming.\n */\nexport interface InstrumentedMethodEntry {\n /** Operation name (e.g. 'chat', 'embeddings', 'generate_content'). Omit for factory methods that only need result proxying. */\n operation?: string;\n /** True if the method itself is always streaming (not param-based) */\n streaming?: boolean;\n /** When set, the method's return value is re-proxied with this as the base path */\n proxyResultPath?: string;\n}\n\n/**\n * Maps method paths to their registry entries.\n * Used by proxy-based AI client instrumentations to determine which methods\n * to instrument, what operation name to use, and whether they stream.\n */\nexport type InstrumentedMethodRegistry = Record<string, InstrumentedMethodEntry>;\n\n/**\n * Resolves AI recording options by falling back to the client's `sendDefaultPii` setting.\n * Precedence: explicit option > sendDefaultPii > false\n */\nexport function resolveAIRecordingOptions<T extends AIRecordingOptions>(options?: T): T & Required<AIRecordingOptions> {\n const sendDefaultPii = Boolean(getClient()?.getOptions().sendDefaultPii);\n return {\n ...options,\n recordInputs: options?.recordInputs ?? sendDefaultPii,\n recordOutputs: options?.recordOutputs ?? sendDefaultPii,\n } as T & Required<AIRecordingOptions>;\n}\n\n/**\n * Resolves whether truncation should be enabled.\n * If the user explicitly set `enableTruncation`, that value is used.\n * Otherwise, truncation is disabled when span streaming is active.\n */\nexport function shouldEnableTruncation(enableTruncation: boolean | undefined): boolean {\n const client = getClient();\n return enableTruncation ?? !(client && hasSpanStreamingEnabled(client));\n}\n\n/**\n * Build method path from current traversal\n */\nexport function buildMethodPath(currentPath: string, prop: string): string {\n return currentPath ? `${currentPath}.${prop}` : prop;\n}\n\n/**\n * Set token usage attributes\n * @param span - The span to add attributes to\n * @param promptTokens - The number of prompt tokens\n * @param completionTokens - The number of completion tokens\n * @param cachedInputTokens - The number of cached input tokens\n * @param cachedOutputTokens - The number of cached output tokens\n */\nexport function setTokenUsageAttributes(\n span: Span,\n promptTokens?: number,\n completionTokens?: number,\n cachedInputTokens?: number,\n cachedOutputTokens?: number,\n): void {\n if (promptTokens !== undefined) {\n span.setAttributes({\n [GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE]: promptTokens,\n });\n }\n if (completionTokens !== undefined) {\n span.setAttributes({\n [GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE]: completionTokens,\n });\n }\n if (\n promptTokens !== undefined ||\n completionTokens !== undefined ||\n cachedInputTokens !== undefined ||\n cachedOutputTokens !== undefined\n ) {\n /**\n * Total input tokens in a request is the summation of `input_tokens`,\n * `cache_creation_input_tokens`, and `cache_read_input_tokens`.\n */\n const totalTokens =\n (promptTokens ?? 0) + (completionTokens ?? 0) + (cachedInputTokens ?? 0) + (cachedOutputTokens ?? 0);\n\n span.setAttributes({\n [GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE]: totalTokens,\n });\n }\n}\n\nexport interface StreamResponseState {\n responseId?: string;\n responseModel?: string;\n finishReasons: string[];\n responseTexts: string[];\n toolCalls: unknown[];\n promptTokens?: number;\n completionTokens?: number;\n totalTokens?: number;\n cacheCreationInputTokens?: number;\n cacheReadInputTokens?: number;\n}\n\n/**\n * Ends a streaming span by setting all accumulated response attributes and ending the span.\n * Shared across OpenAI, Anthropic, and Google GenAI streaming implementations.\n */\nexport function endStreamSpan(span: Span, state: StreamResponseState, recordOutputs: boolean): void {\n if (!span.isRecording()) {\n return;\n }\n\n const attrs: Record<string, string | number | boolean> = {\n [GEN_AI_RESPONSE_STREAMING_ATTRIBUTE]: true,\n };\n\n if (state.responseId) attrs[GEN_AI_RESPONSE_ID_ATTRIBUTE] = state.responseId;\n if (state.responseModel) attrs[GEN_AI_RESPONSE_MODEL_ATTRIBUTE] = state.responseModel;\n\n if (state.promptTokens !== undefined) attrs[GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE] = state.promptTokens;\n if (state.completionTokens !== undefined) attrs[GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE] = state.completionTokens;\n\n // Use explicit total if provided (OpenAI, Google), otherwise compute from cache tokens (Anthropic)\n if (state.totalTokens !== undefined) {\n attrs[GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE] = state.totalTokens;\n } else if (\n state.promptTokens !== undefined ||\n state.completionTokens !== undefined ||\n state.cacheCreationInputTokens !== undefined ||\n state.cacheReadInputTokens !== undefined\n ) {\n attrs[GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE] =\n (state.promptTokens ?? 0) +\n (state.completionTokens ?? 0) +\n (state.cacheCreationInputTokens ?? 0) +\n (state.cacheReadInputTokens ?? 0);\n }\n\n if (state.finishReasons.length) {\n attrs[GEN_AI_RESPONSE_FINISH_REASONS_ATTRIBUTE] = JSON.stringify(state.finishReasons);\n }\n if (recordOutputs && state.responseTexts.length) {\n attrs[GEN_AI_RESPONSE_TEXT_ATTRIBUTE] = state.responseTexts.join('');\n }\n if (recordOutputs && state.toolCalls.length) {\n attrs[GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE] = JSON.stringify(state.toolCalls);\n }\n\n span.setAttributes(attrs);\n span.end();\n}\n\n/**\n * Serialize a value to a JSON string without truncation.\n * Strings are returned as-is, arrays and objects are JSON-stringified.\n */\nexport function getJsonString<T>(value: T | T[]): string {\n if (typeof value === 'string') {\n return value;\n }\n return JSON.stringify(value);\n}\n\n/**\n * Get the truncated JSON string for a string or array of strings.\n *\n * @param value - The string or array of strings to truncate\n * @returns The truncated JSON string\n */\nexport function getTruncatedJsonString<T>(value: T | T[]): string {\n if (typeof value === 'string') {\n // Some values are already JSON strings, so we don't need to duplicate the JSON parsing\n return truncateGenAiStringInput(value);\n }\n if (Array.isArray(value)) {\n // truncateGenAiMessages returns an array of strings, so we need to stringify it\n const truncatedMessages = truncateGenAiMessages(value);\n return JSON.stringify(truncatedMessages);\n }\n // value is an object, so we need to stringify it\n return JSON.stringify(value);\n}\n\n/**\n * Extract system instructions from messages array.\n * Finds the first system message and formats it according to OpenTelemetry semantic conventions.\n *\n * @param messages - Array of messages to extract system instructions from\n * @returns systemInstructions (JSON string) and filteredMessages (without system message)\n */\nexport function extractSystemInstructions(messages: unknown[] | unknown): {\n systemInstructions: string | undefined;\n filteredMessages: unknown[] | unknown;\n} {\n if (!Array.isArray(messages)) {\n return { systemInstructions: undefined, filteredMessages: messages };\n }\n\n const systemMessageIndex = messages.findIndex(\n msg => msg && typeof msg === 'object' && 'role' in msg && (msg as { role: string }).role === 'system',\n );\n\n if (systemMessageIndex === -1) {\n return { systemInstructions: undefined, filteredMessages: messages };\n }\n\n const systemMessage = messages[systemMessageIndex] as { role: string; content?: string | unknown };\n const systemContent =\n typeof systemMessage.content === 'string'\n ? systemMessage.content\n : systemMessage.content !== undefined\n ? JSON.stringify(systemMessage.content)\n : undefined;\n\n if (!systemContent) {\n return { systemInstructions: undefined, filteredMessages: messages };\n }\n\n const systemInstructions = JSON.stringify([{ type: 'text', content: systemContent }]);\n const filteredMessages = [...messages.slice(0, systemMessageIndex), ...messages.slice(systemMessageIndex + 1)];\n\n return { systemInstructions, filteredMessages };\n}\n\n/**\n * Creates a wrapped version of .withResponse() that replaces the data field\n * with the instrumented result while preserving metadata (response, request_id).\n */\nasync function createWithResponseWrapper<T>(\n originalWithResponse: Promise<unknown>,\n instrumentedPromise: Promise<T>,\n mechanismType: string,\n): Promise<unknown> {\n // Attach catch handler to originalWithResponse immediately to prevent unhandled rejection\n // If instrumentedPromise rejects first, we still need this handled\n const safeOriginalWithResponse = originalWithResponse.catch(error => {\n captureException(error, {\n mechanism: {\n handled: false,\n type: mechanismType,\n },\n });\n throw error;\n });\n\n const instrumentedResult = await instrumentedPromise;\n const originalWrapper = await safeOriginalWithResponse;\n\n // Combine instrumented result with original metadata\n if (originalWrapper && typeof originalWrapper === 'object' && 'data' in originalWrapper) {\n return {\n ...originalWrapper,\n data: instrumentedResult,\n };\n }\n return instrumentedResult;\n}\n\n/**\n * Wraps a promise-like object to preserve additional methods (like .withResponse())\n * that AI SDK clients (OpenAI, Anthropic) attach to their APIPromise return values.\n *\n * Standard Promise methods (.then, .catch, .finally) are routed to the instrumented\n * promise to preserve Sentry's span instrumentation, while custom SDK methods are\n * forwarded to the original promise to maintain the SDK's API surface.\n */\nexport function wrapPromiseWithMethods<R>(\n originalPromiseLike: Promise<R>,\n instrumentedPromise: Promise<R>,\n mechanismType: string,\n): Promise<R> {\n // If the original result is not thenable, return the instrumented promise\n if (!isThenable(originalPromiseLike)) {\n return instrumentedPromise;\n }\n\n // Create a proxy that forwards Promise methods to instrumentedPromise\n // and preserves additional methods from the original result\n return new Proxy(originalPromiseLike, {\n get(target: object, prop: string | symbol): unknown {\n // For standard Promise methods (.then, .catch, .finally, Symbol.toStringTag),\n // use instrumentedPromise to preserve Sentry instrumentation.\n // For custom methods (like .withResponse()), use the original target.\n const useInstrumentedPromise = prop in Promise.prototype || prop === Symbol.toStringTag;\n const source = useInstrumentedPromise ? instrumentedPromise : target;\n\n const value = Reflect.get(source, prop) as unknown;\n\n // Special handling for .withResponse() to preserve instrumentation\n // .withResponse() returns { data: T, response: Response, request_id: string }\n if (prop === 'withResponse' && typeof value === 'function') {\n return function wrappedWithResponse(this: unknown): unknown {\n const originalWithResponse = (value as (...args: unknown[]) => unknown).call(target);\n return createWithResponseWrapper(originalWithResponse, instrumentedPromise, mechanismType);\n };\n }\n\n return typeof value === 'function' ? value.bind(source) : value;\n },\n }) as Promise<R>;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '../../semanticAttributes.js';
|
|
|
3
3
|
import { SPAN_STATUS_ERROR } from '../spanstatus.js';
|
|
4
4
|
import { startSpan, startSpanManual } from '../trace.js';
|
|
5
5
|
import { GEN_AI_REQUEST_AVAILABLE_TOOLS_ATTRIBUTE, GEN_AI_REQUEST_MODEL_ATTRIBUTE, GEN_AI_REQUEST_TEMPERATURE_ATTRIBUTE, GEN_AI_REQUEST_TOP_P_ATTRIBUTE, GEN_AI_REQUEST_STREAM_ATTRIBUTE, GEN_AI_REQUEST_TOP_K_ATTRIBUTE, GEN_AI_REQUEST_FREQUENCY_PENALTY_ATTRIBUTE, GEN_AI_REQUEST_MAX_TOKENS_ATTRIBUTE, GEN_AI_PROMPT_ATTRIBUTE, GEN_AI_OPERATION_NAME_ATTRIBUTE, GEN_AI_SYSTEM_ATTRIBUTE, GEN_AI_RESPONSE_TEXT_ATTRIBUTE, GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE, GEN_AI_RESPONSE_MODEL_ATTRIBUTE, GEN_AI_RESPONSE_ID_ATTRIBUTE } from '../ai/gen-ai-attributes.js';
|
|
6
|
-
import { resolveAIRecordingOptions, wrapPromiseWithMethods, buildMethodPath, setTokenUsageAttributes } from '../ai/utils.js';
|
|
6
|
+
import { resolveAIRecordingOptions, shouldEnableTruncation, wrapPromiseWithMethods, buildMethodPath, setTokenUsageAttributes } from '../ai/utils.js';
|
|
7
7
|
import { ANTHROPIC_METHOD_REGISTRY } from './constants.js';
|
|
8
8
|
import { instrumentAsyncIterableStream, instrumentMessageStream } from './streaming.js';
|
|
9
9
|
import { messagesFromParams, setMessagesAttribute, handleResponseError } from './utils.js';
|
|
@@ -48,9 +48,9 @@ function extractRequestAttributes(args, methodPath, operationName) {
|
|
|
48
48
|
* Add private request attributes to spans.
|
|
49
49
|
* This is only recorded if recordInputs is true.
|
|
50
50
|
*/
|
|
51
|
-
function addPrivateRequestAttributes(span, params) {
|
|
51
|
+
function addPrivateRequestAttributes(span, params, enableTruncation) {
|
|
52
52
|
const messages = messagesFromParams(params);
|
|
53
|
-
setMessagesAttribute(span, messages);
|
|
53
|
+
setMessagesAttribute(span, messages, enableTruncation);
|
|
54
54
|
|
|
55
55
|
if ('prompt' in params) {
|
|
56
56
|
span.setAttributes({ [GEN_AI_PROMPT_ATTRIBUTE]: JSON.stringify(params.prompt) });
|
|
@@ -182,7 +182,7 @@ function handleStreamingRequest(
|
|
|
182
182
|
originalResult = originalMethod.apply(context, args) ;
|
|
183
183
|
|
|
184
184
|
if (options.recordInputs && params) {
|
|
185
|
-
addPrivateRequestAttributes(span, params);
|
|
185
|
+
addPrivateRequestAttributes(span, params, shouldEnableTruncation(options.enableTruncation));
|
|
186
186
|
}
|
|
187
187
|
|
|
188
188
|
return (async () => {
|
|
@@ -204,7 +204,7 @@ function handleStreamingRequest(
|
|
|
204
204
|
return startSpanManual(spanConfig, span => {
|
|
205
205
|
try {
|
|
206
206
|
if (options.recordInputs && params) {
|
|
207
|
-
addPrivateRequestAttributes(span, params);
|
|
207
|
+
addPrivateRequestAttributes(span, params, shouldEnableTruncation(options.enableTruncation));
|
|
208
208
|
}
|
|
209
209
|
const messageStream = target.apply(context, args);
|
|
210
210
|
return instrumentMessageStream(messageStream, span, options.recordOutputs ?? false);
|
|
@@ -265,7 +265,7 @@ function instrumentMethod(
|
|
|
265
265
|
originalResult = target.apply(context, args) ;
|
|
266
266
|
|
|
267
267
|
if (options.recordInputs && params) {
|
|
268
|
-
addPrivateRequestAttributes(span, params);
|
|
268
|
+
addPrivateRequestAttributes(span, params, shouldEnableTruncation(options.enableTruncation));
|
|
269
269
|
}
|
|
270
270
|
|
|
271
271
|
return originalResult.then(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../src/tracing/anthropic-ai/index.ts"],"sourcesContent":["import { captureException } from '../../exports';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '../../semanticAttributes';\nimport { SPAN_STATUS_ERROR } from '../../tracing';\nimport { startSpan, startSpanManual } from '../../tracing/trace';\nimport type { Span, SpanAttributeValue } from '../../types-hoist/span';\nimport {\n GEN_AI_OPERATION_NAME_ATTRIBUTE,\n GEN_AI_PROMPT_ATTRIBUTE,\n GEN_AI_REQUEST_AVAILABLE_TOOLS_ATTRIBUTE,\n GEN_AI_REQUEST_FREQUENCY_PENALTY_ATTRIBUTE,\n GEN_AI_REQUEST_MAX_TOKENS_ATTRIBUTE,\n GEN_AI_REQUEST_MODEL_ATTRIBUTE,\n GEN_AI_REQUEST_STREAM_ATTRIBUTE,\n GEN_AI_REQUEST_TEMPERATURE_ATTRIBUTE,\n GEN_AI_REQUEST_TOP_K_ATTRIBUTE,\n GEN_AI_REQUEST_TOP_P_ATTRIBUTE,\n GEN_AI_RESPONSE_ID_ATTRIBUTE,\n GEN_AI_RESPONSE_MODEL_ATTRIBUTE,\n GEN_AI_RESPONSE_TEXT_ATTRIBUTE,\n GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE,\n GEN_AI_SYSTEM_ATTRIBUTE,\n} from '../ai/gen-ai-attributes';\nimport type { InstrumentedMethodEntry } from '../ai/utils';\nimport {\n buildMethodPath,\n resolveAIRecordingOptions,\n setTokenUsageAttributes,\n wrapPromiseWithMethods,\n} from '../ai/utils';\nimport { ANTHROPIC_METHOD_REGISTRY } from './constants';\nimport { instrumentAsyncIterableStream, instrumentMessageStream } from './streaming';\nimport type { AnthropicAiOptions, AnthropicAiResponse, AnthropicAiStreamingEvent, ContentBlock } from './types';\nimport { handleResponseError, messagesFromParams, setMessagesAttribute } from './utils';\n\n/**\n * Extract request attributes from method arguments\n */\nfunction extractRequestAttributes(args: unknown[], methodPath: string, operationName: string): Record<string, unknown> {\n const attributes: Record<string, unknown> = {\n [GEN_AI_SYSTEM_ATTRIBUTE]: 'anthropic',\n [GEN_AI_OPERATION_NAME_ATTRIBUTE]: operationName,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ai.anthropic',\n };\n\n if (args.length > 0 && typeof args[0] === 'object' && args[0] !== null) {\n const params = args[0] as Record<string, unknown>;\n if (params.tools && Array.isArray(params.tools)) {\n attributes[GEN_AI_REQUEST_AVAILABLE_TOOLS_ATTRIBUTE] = JSON.stringify(params.tools);\n }\n\n attributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE] = params.model ?? 'unknown';\n if ('temperature' in params) attributes[GEN_AI_REQUEST_TEMPERATURE_ATTRIBUTE] = params.temperature;\n if ('top_p' in params) attributes[GEN_AI_REQUEST_TOP_P_ATTRIBUTE] = params.top_p;\n if ('stream' in params) attributes[GEN_AI_REQUEST_STREAM_ATTRIBUTE] = params.stream;\n if ('top_k' in params) attributes[GEN_AI_REQUEST_TOP_K_ATTRIBUTE] = params.top_k;\n if ('frequency_penalty' in params)\n attributes[GEN_AI_REQUEST_FREQUENCY_PENALTY_ATTRIBUTE] = params.frequency_penalty;\n if ('max_tokens' in params) attributes[GEN_AI_REQUEST_MAX_TOKENS_ATTRIBUTE] = params.max_tokens;\n } else {\n if (methodPath === 'models.retrieve' || methodPath === 'models.get') {\n // models.retrieve(model-id) and models.get(model-id)\n attributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE] = args[0];\n } else {\n attributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE] = 'unknown';\n }\n }\n\n return attributes;\n}\n\n/**\n * Add private request attributes to spans.\n * This is only recorded if recordInputs is true.\n */\nfunction addPrivateRequestAttributes(span: Span, params: Record<string, unknown>): void {\n const messages = messagesFromParams(params);\n setMessagesAttribute(span, messages);\n\n if ('prompt' in params) {\n span.setAttributes({ [GEN_AI_PROMPT_ATTRIBUTE]: JSON.stringify(params.prompt) });\n }\n}\n\n/**\n * Add content attributes when recordOutputs is enabled\n */\nfunction addContentAttributes(span: Span, response: AnthropicAiResponse): void {\n // Messages.create\n if ('content' in response) {\n if (Array.isArray(response.content)) {\n span.setAttributes({\n [GEN_AI_RESPONSE_TEXT_ATTRIBUTE]: response.content\n .map((item: ContentBlock) => item.text)\n .filter(text => !!text)\n .join(''),\n });\n\n const toolCalls: Array<ContentBlock> = [];\n\n for (const item of response.content) {\n if (item.type === 'tool_use' || item.type === 'server_tool_use') {\n toolCalls.push(item);\n }\n }\n if (toolCalls.length > 0) {\n span.setAttributes({ [GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE]: JSON.stringify(toolCalls) });\n }\n }\n }\n // Completions.create\n if ('completion' in response) {\n span.setAttributes({ [GEN_AI_RESPONSE_TEXT_ATTRIBUTE]: response.completion });\n }\n // Models.countTokens\n if ('input_tokens' in response) {\n span.setAttributes({ [GEN_AI_RESPONSE_TEXT_ATTRIBUTE]: JSON.stringify(response.input_tokens) });\n }\n}\n\n/**\n * Add basic metadata attributes from the response\n */\nfunction addMetadataAttributes(span: Span, response: AnthropicAiResponse): void {\n if ('id' in response && 'model' in response) {\n span.setAttributes({\n [GEN_AI_RESPONSE_ID_ATTRIBUTE]: response.id,\n [GEN_AI_RESPONSE_MODEL_ATTRIBUTE]: response.model,\n });\n\n if ('usage' in response && response.usage) {\n setTokenUsageAttributes(\n span,\n response.usage.input_tokens,\n response.usage.output_tokens,\n response.usage.cache_creation_input_tokens,\n response.usage.cache_read_input_tokens,\n );\n }\n }\n}\n\n/**\n * Add response attributes to spans\n */\nfunction addResponseAttributes(span: Span, response: AnthropicAiResponse, recordOutputs?: boolean): void {\n if (!response || typeof response !== 'object') return;\n\n // capture error, do not add attributes if error (they shouldn't exist)\n if ('type' in response && response.type === 'error') {\n handleResponseError(span, response);\n return;\n }\n\n // Private response attributes that are only recorded if recordOutputs is true.\n if (recordOutputs) {\n addContentAttributes(span, response);\n }\n\n // Add basic metadata attributes\n addMetadataAttributes(span, response);\n}\n\n/**\n * Handle common error catching and reporting for streaming requests\n */\nfunction handleStreamingError(error: unknown, span: Span, methodPath: string): never {\n captureException(error, {\n mechanism: { handled: false, type: 'auto.ai.anthropic', data: { function: methodPath } },\n });\n\n if (span.isRecording()) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n span.end();\n }\n throw error;\n}\n\n/**\n * Handle streaming cases with common logic\n */\nfunction handleStreamingRequest<T extends unknown[], R>(\n originalMethod: (...args: T) => R | Promise<R>,\n target: (...args: T) => R | Promise<R>,\n context: unknown,\n args: T,\n requestAttributes: Record<string, unknown>,\n operationName: string,\n methodPath: string,\n params: Record<string, unknown> | undefined,\n options: AnthropicAiOptions,\n isStreamRequested: boolean,\n isStreamingMethod: boolean,\n): R | Promise<R> {\n const model = requestAttributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE] ?? 'unknown';\n const spanConfig = {\n name: `${operationName} ${model}`,\n op: `gen_ai.${operationName}`,\n attributes: requestAttributes as Record<string, SpanAttributeValue>,\n };\n\n // messages.stream() always returns a sync MessageStream, even with stream: true param\n if (isStreamRequested && !isStreamingMethod) {\n let originalResult!: Promise<R>;\n\n const instrumentedPromise = startSpanManual(spanConfig, (span: Span) => {\n originalResult = originalMethod.apply(context, args) as Promise<R>;\n\n if (options.recordInputs && params) {\n addPrivateRequestAttributes(span, params);\n }\n\n return (async () => {\n try {\n const result = await originalResult;\n return instrumentAsyncIterableStream(\n result as AsyncIterable<AnthropicAiStreamingEvent>,\n span,\n options.recordOutputs ?? false,\n ) as unknown as R;\n } catch (error) {\n return handleStreamingError(error, span, methodPath);\n }\n })();\n });\n\n return wrapPromiseWithMethods(originalResult, instrumentedPromise, 'auto.ai.anthropic');\n } else {\n return startSpanManual(spanConfig, span => {\n try {\n if (options.recordInputs && params) {\n addPrivateRequestAttributes(span, params);\n }\n const messageStream = target.apply(context, args);\n return instrumentMessageStream(messageStream, span, options.recordOutputs ?? false);\n } catch (error) {\n return handleStreamingError(error, span, methodPath);\n }\n });\n }\n}\n\n/**\n * Instrument a method with Sentry spans\n * Following Sentry AI Agents Manual Instrumentation conventions\n * @see https://docs.sentry.io/platforms/javascript/guides/node/tracing/instrumentation/ai-agents-module/#manual-instrumentation\n */\nfunction instrumentMethod<T extends unknown[], R>(\n originalMethod: (...args: T) => R | Promise<R>,\n methodPath: string,\n instrumentedMethod: InstrumentedMethodEntry,\n context: unknown,\n options: AnthropicAiOptions,\n): (...args: T) => R | Promise<R> {\n return new Proxy(originalMethod, {\n apply(target, thisArg, args: T): R | Promise<R> {\n const operationName = instrumentedMethod.operation || 'unknown';\n const requestAttributes = extractRequestAttributes(args, methodPath, operationName);\n const model = requestAttributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE] ?? 'unknown';\n\n const params = typeof args[0] === 'object' ? (args[0] as Record<string, unknown>) : undefined;\n const isStreamRequested = Boolean(params?.stream);\n const isStreamingMethod = instrumentedMethod.streaming === true;\n\n if (isStreamRequested || isStreamingMethod) {\n return handleStreamingRequest(\n originalMethod,\n target,\n context,\n args,\n requestAttributes,\n operationName,\n methodPath,\n params,\n options,\n isStreamRequested,\n isStreamingMethod,\n );\n }\n\n let originalResult!: Promise<R>;\n\n const instrumentedPromise = startSpan(\n {\n name: `${operationName} ${model}`,\n op: `gen_ai.${operationName}`,\n attributes: requestAttributes as Record<string, SpanAttributeValue>,\n },\n span => {\n originalResult = target.apply(context, args) as Promise<R>;\n\n if (options.recordInputs && params) {\n addPrivateRequestAttributes(span, params);\n }\n\n return originalResult.then(\n result => {\n addResponseAttributes(span, result as AnthropicAiResponse, options.recordOutputs);\n return result;\n },\n error => {\n captureException(error, {\n mechanism: {\n handled: false,\n type: 'auto.ai.anthropic',\n data: {\n function: methodPath,\n },\n },\n });\n throw error;\n },\n );\n },\n );\n\n return wrapPromiseWithMethods(originalResult, instrumentedPromise, 'auto.ai.anthropic');\n },\n }) as (...args: T) => R | Promise<R>;\n}\n\n/**\n * Create a deep proxy for Anthropic AI client instrumentation\n */\nfunction createDeepProxy<T extends object>(target: T, currentPath = '', options: AnthropicAiOptions): T {\n return new Proxy(target, {\n get(obj: object, prop: string): unknown {\n const value = (obj as Record<string, unknown>)[prop];\n const methodPath = buildMethodPath(currentPath, String(prop));\n\n const instrumentedMethod = ANTHROPIC_METHOD_REGISTRY[methodPath as keyof typeof ANTHROPIC_METHOD_REGISTRY];\n if (typeof value === 'function' && instrumentedMethod) {\n return instrumentMethod(\n value as (...args: unknown[]) => unknown | Promise<unknown>,\n methodPath,\n instrumentedMethod,\n obj,\n options,\n );\n }\n\n if (typeof value === 'function') {\n // Bind non-instrumented functions to preserve the original `this` context,\n return value.bind(obj);\n }\n\n if (value && typeof value === 'object') {\n return createDeepProxy(value, methodPath, options);\n }\n\n return value;\n },\n }) as T;\n}\n\n/**\n * Instrument an Anthropic AI client with Sentry tracing\n * Can be used across Node.js, Cloudflare Workers, and Vercel Edge\n *\n * @template T - The type of the client that extends object\n * @param client - The Anthropic AI client to instrument\n * @param options - Optional configuration for recording inputs and outputs\n * @returns The instrumented client with the same type as the input\n */\nexport function instrumentAnthropicAiClient<T extends object>(anthropicAiClient: T, options?: AnthropicAiOptions): T {\n return createDeepProxy(anthropicAiClient, '', resolveAIRecordingOptions(options));\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/tracing/anthropic-ai/index.ts"],"sourcesContent":["import { captureException } from '../../exports';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '../../semanticAttributes';\nimport { SPAN_STATUS_ERROR } from '../../tracing';\nimport { startSpan, startSpanManual } from '../../tracing/trace';\nimport type { Span, SpanAttributeValue } from '../../types-hoist/span';\nimport {\n GEN_AI_OPERATION_NAME_ATTRIBUTE,\n GEN_AI_PROMPT_ATTRIBUTE,\n GEN_AI_REQUEST_AVAILABLE_TOOLS_ATTRIBUTE,\n GEN_AI_REQUEST_FREQUENCY_PENALTY_ATTRIBUTE,\n GEN_AI_REQUEST_MAX_TOKENS_ATTRIBUTE,\n GEN_AI_REQUEST_MODEL_ATTRIBUTE,\n GEN_AI_REQUEST_STREAM_ATTRIBUTE,\n GEN_AI_REQUEST_TEMPERATURE_ATTRIBUTE,\n GEN_AI_REQUEST_TOP_K_ATTRIBUTE,\n GEN_AI_REQUEST_TOP_P_ATTRIBUTE,\n GEN_AI_RESPONSE_ID_ATTRIBUTE,\n GEN_AI_RESPONSE_MODEL_ATTRIBUTE,\n GEN_AI_RESPONSE_TEXT_ATTRIBUTE,\n GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE,\n GEN_AI_SYSTEM_ATTRIBUTE,\n} from '../ai/gen-ai-attributes';\nimport type { InstrumentedMethodEntry } from '../ai/utils';\nimport {\n buildMethodPath,\n resolveAIRecordingOptions,\n setTokenUsageAttributes,\n shouldEnableTruncation,\n wrapPromiseWithMethods,\n} from '../ai/utils';\nimport { ANTHROPIC_METHOD_REGISTRY } from './constants';\nimport { instrumentAsyncIterableStream, instrumentMessageStream } from './streaming';\nimport type { AnthropicAiOptions, AnthropicAiResponse, AnthropicAiStreamingEvent, ContentBlock } from './types';\nimport { handleResponseError, messagesFromParams, setMessagesAttribute } from './utils';\n\n/**\n * Extract request attributes from method arguments\n */\nfunction extractRequestAttributes(args: unknown[], methodPath: string, operationName: string): Record<string, unknown> {\n const attributes: Record<string, unknown> = {\n [GEN_AI_SYSTEM_ATTRIBUTE]: 'anthropic',\n [GEN_AI_OPERATION_NAME_ATTRIBUTE]: operationName,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ai.anthropic',\n };\n\n if (args.length > 0 && typeof args[0] === 'object' && args[0] !== null) {\n const params = args[0] as Record<string, unknown>;\n if (params.tools && Array.isArray(params.tools)) {\n attributes[GEN_AI_REQUEST_AVAILABLE_TOOLS_ATTRIBUTE] = JSON.stringify(params.tools);\n }\n\n attributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE] = params.model ?? 'unknown';\n if ('temperature' in params) attributes[GEN_AI_REQUEST_TEMPERATURE_ATTRIBUTE] = params.temperature;\n if ('top_p' in params) attributes[GEN_AI_REQUEST_TOP_P_ATTRIBUTE] = params.top_p;\n if ('stream' in params) attributes[GEN_AI_REQUEST_STREAM_ATTRIBUTE] = params.stream;\n if ('top_k' in params) attributes[GEN_AI_REQUEST_TOP_K_ATTRIBUTE] = params.top_k;\n if ('frequency_penalty' in params)\n attributes[GEN_AI_REQUEST_FREQUENCY_PENALTY_ATTRIBUTE] = params.frequency_penalty;\n if ('max_tokens' in params) attributes[GEN_AI_REQUEST_MAX_TOKENS_ATTRIBUTE] = params.max_tokens;\n } else {\n if (methodPath === 'models.retrieve' || methodPath === 'models.get') {\n // models.retrieve(model-id) and models.get(model-id)\n attributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE] = args[0];\n } else {\n attributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE] = 'unknown';\n }\n }\n\n return attributes;\n}\n\n/**\n * Add private request attributes to spans.\n * This is only recorded if recordInputs is true.\n */\nfunction addPrivateRequestAttributes(span: Span, params: Record<string, unknown>, enableTruncation: boolean): void {\n const messages = messagesFromParams(params);\n setMessagesAttribute(span, messages, enableTruncation);\n\n if ('prompt' in params) {\n span.setAttributes({ [GEN_AI_PROMPT_ATTRIBUTE]: JSON.stringify(params.prompt) });\n }\n}\n\n/**\n * Add content attributes when recordOutputs is enabled\n */\nfunction addContentAttributes(span: Span, response: AnthropicAiResponse): void {\n // Messages.create\n if ('content' in response) {\n if (Array.isArray(response.content)) {\n span.setAttributes({\n [GEN_AI_RESPONSE_TEXT_ATTRIBUTE]: response.content\n .map((item: ContentBlock) => item.text)\n .filter(text => !!text)\n .join(''),\n });\n\n const toolCalls: Array<ContentBlock> = [];\n\n for (const item of response.content) {\n if (item.type === 'tool_use' || item.type === 'server_tool_use') {\n toolCalls.push(item);\n }\n }\n if (toolCalls.length > 0) {\n span.setAttributes({ [GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE]: JSON.stringify(toolCalls) });\n }\n }\n }\n // Completions.create\n if ('completion' in response) {\n span.setAttributes({ [GEN_AI_RESPONSE_TEXT_ATTRIBUTE]: response.completion });\n }\n // Models.countTokens\n if ('input_tokens' in response) {\n span.setAttributes({ [GEN_AI_RESPONSE_TEXT_ATTRIBUTE]: JSON.stringify(response.input_tokens) });\n }\n}\n\n/**\n * Add basic metadata attributes from the response\n */\nfunction addMetadataAttributes(span: Span, response: AnthropicAiResponse): void {\n if ('id' in response && 'model' in response) {\n span.setAttributes({\n [GEN_AI_RESPONSE_ID_ATTRIBUTE]: response.id,\n [GEN_AI_RESPONSE_MODEL_ATTRIBUTE]: response.model,\n });\n\n if ('usage' in response && response.usage) {\n setTokenUsageAttributes(\n span,\n response.usage.input_tokens,\n response.usage.output_tokens,\n response.usage.cache_creation_input_tokens,\n response.usage.cache_read_input_tokens,\n );\n }\n }\n}\n\n/**\n * Add response attributes to spans\n */\nfunction addResponseAttributes(span: Span, response: AnthropicAiResponse, recordOutputs?: boolean): void {\n if (!response || typeof response !== 'object') return;\n\n // capture error, do not add attributes if error (they shouldn't exist)\n if ('type' in response && response.type === 'error') {\n handleResponseError(span, response);\n return;\n }\n\n // Private response attributes that are only recorded if recordOutputs is true.\n if (recordOutputs) {\n addContentAttributes(span, response);\n }\n\n // Add basic metadata attributes\n addMetadataAttributes(span, response);\n}\n\n/**\n * Handle common error catching and reporting for streaming requests\n */\nfunction handleStreamingError(error: unknown, span: Span, methodPath: string): never {\n captureException(error, {\n mechanism: { handled: false, type: 'auto.ai.anthropic', data: { function: methodPath } },\n });\n\n if (span.isRecording()) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n span.end();\n }\n throw error;\n}\n\n/**\n * Handle streaming cases with common logic\n */\nfunction handleStreamingRequest<T extends unknown[], R>(\n originalMethod: (...args: T) => R | Promise<R>,\n target: (...args: T) => R | Promise<R>,\n context: unknown,\n args: T,\n requestAttributes: Record<string, unknown>,\n operationName: string,\n methodPath: string,\n params: Record<string, unknown> | undefined,\n options: AnthropicAiOptions,\n isStreamRequested: boolean,\n isStreamingMethod: boolean,\n): R | Promise<R> {\n const model = requestAttributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE] ?? 'unknown';\n const spanConfig = {\n name: `${operationName} ${model}`,\n op: `gen_ai.${operationName}`,\n attributes: requestAttributes as Record<string, SpanAttributeValue>,\n };\n\n // messages.stream() always returns a sync MessageStream, even with stream: true param\n if (isStreamRequested && !isStreamingMethod) {\n let originalResult!: Promise<R>;\n\n const instrumentedPromise = startSpanManual(spanConfig, (span: Span) => {\n originalResult = originalMethod.apply(context, args) as Promise<R>;\n\n if (options.recordInputs && params) {\n addPrivateRequestAttributes(span, params, shouldEnableTruncation(options.enableTruncation));\n }\n\n return (async () => {\n try {\n const result = await originalResult;\n return instrumentAsyncIterableStream(\n result as AsyncIterable<AnthropicAiStreamingEvent>,\n span,\n options.recordOutputs ?? false,\n ) as unknown as R;\n } catch (error) {\n return handleStreamingError(error, span, methodPath);\n }\n })();\n });\n\n return wrapPromiseWithMethods(originalResult, instrumentedPromise, 'auto.ai.anthropic');\n } else {\n return startSpanManual(spanConfig, span => {\n try {\n if (options.recordInputs && params) {\n addPrivateRequestAttributes(span, params, shouldEnableTruncation(options.enableTruncation));\n }\n const messageStream = target.apply(context, args);\n return instrumentMessageStream(messageStream, span, options.recordOutputs ?? false);\n } catch (error) {\n return handleStreamingError(error, span, methodPath);\n }\n });\n }\n}\n\n/**\n * Instrument a method with Sentry spans\n * Following Sentry AI Agents Manual Instrumentation conventions\n * @see https://docs.sentry.io/platforms/javascript/guides/node/tracing/instrumentation/ai-agents-module/#manual-instrumentation\n */\nfunction instrumentMethod<T extends unknown[], R>(\n originalMethod: (...args: T) => R | Promise<R>,\n methodPath: string,\n instrumentedMethod: InstrumentedMethodEntry,\n context: unknown,\n options: AnthropicAiOptions,\n): (...args: T) => R | Promise<R> {\n return new Proxy(originalMethod, {\n apply(target, thisArg, args: T): R | Promise<R> {\n const operationName = instrumentedMethod.operation || 'unknown';\n const requestAttributes = extractRequestAttributes(args, methodPath, operationName);\n const model = requestAttributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE] ?? 'unknown';\n\n const params = typeof args[0] === 'object' ? (args[0] as Record<string, unknown>) : undefined;\n const isStreamRequested = Boolean(params?.stream);\n const isStreamingMethod = instrumentedMethod.streaming === true;\n\n if (isStreamRequested || isStreamingMethod) {\n return handleStreamingRequest(\n originalMethod,\n target,\n context,\n args,\n requestAttributes,\n operationName,\n methodPath,\n params,\n options,\n isStreamRequested,\n isStreamingMethod,\n );\n }\n\n let originalResult!: Promise<R>;\n\n const instrumentedPromise = startSpan(\n {\n name: `${operationName} ${model}`,\n op: `gen_ai.${operationName}`,\n attributes: requestAttributes as Record<string, SpanAttributeValue>,\n },\n span => {\n originalResult = target.apply(context, args) as Promise<R>;\n\n if (options.recordInputs && params) {\n addPrivateRequestAttributes(span, params, shouldEnableTruncation(options.enableTruncation));\n }\n\n return originalResult.then(\n result => {\n addResponseAttributes(span, result as AnthropicAiResponse, options.recordOutputs);\n return result;\n },\n error => {\n captureException(error, {\n mechanism: {\n handled: false,\n type: 'auto.ai.anthropic',\n data: {\n function: methodPath,\n },\n },\n });\n throw error;\n },\n );\n },\n );\n\n return wrapPromiseWithMethods(originalResult, instrumentedPromise, 'auto.ai.anthropic');\n },\n }) as (...args: T) => R | Promise<R>;\n}\n\n/**\n * Create a deep proxy for Anthropic AI client instrumentation\n */\nfunction createDeepProxy<T extends object>(target: T, currentPath = '', options: AnthropicAiOptions): T {\n return new Proxy(target, {\n get(obj: object, prop: string): unknown {\n const value = (obj as Record<string, unknown>)[prop];\n const methodPath = buildMethodPath(currentPath, String(prop));\n\n const instrumentedMethod = ANTHROPIC_METHOD_REGISTRY[methodPath as keyof typeof ANTHROPIC_METHOD_REGISTRY];\n if (typeof value === 'function' && instrumentedMethod) {\n return instrumentMethod(\n value as (...args: unknown[]) => unknown | Promise<unknown>,\n methodPath,\n instrumentedMethod,\n obj,\n options,\n );\n }\n\n if (typeof value === 'function') {\n // Bind non-instrumented functions to preserve the original `this` context,\n return value.bind(obj);\n }\n\n if (value && typeof value === 'object') {\n return createDeepProxy(value, methodPath, options);\n }\n\n return value;\n },\n }) as T;\n}\n\n/**\n * Instrument an Anthropic AI client with Sentry tracing\n * Can be used across Node.js, Cloudflare Workers, and Vercel Edge\n *\n * @template T - The type of the client that extends object\n * @param client - The Anthropic AI client to instrument\n * @param options - Optional configuration for recording inputs and outputs\n * @returns The instrumented client with the same type as the input\n */\nexport function instrumentAnthropicAiClient<T extends object>(anthropicAiClient: T, options?: AnthropicAiOptions): T {\n return createDeepProxy(anthropicAiClient, '', resolveAIRecordingOptions(options));\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { captureException } from '../../exports.js';
|
|
2
2
|
import { SPAN_STATUS_ERROR } from '../spanstatus.js';
|
|
3
3
|
import { GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE, GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE, GEN_AI_INPUT_MESSAGES_ATTRIBUTE } from '../ai/gen-ai-attributes.js';
|
|
4
|
-
import { extractSystemInstructions, getTruncatedJsonString } from '../ai/utils.js';
|
|
4
|
+
import { extractSystemInstructions, getTruncatedJsonString, getJsonString } from '../ai/utils.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Set the messages and messages original length attributes.
|
|
8
8
|
* Extracts system instructions before truncation.
|
|
9
9
|
*/
|
|
10
|
-
function setMessagesAttribute(span, messages) {
|
|
10
|
+
function setMessagesAttribute(span, messages, enableTruncation) {
|
|
11
11
|
if (Array.isArray(messages) && messages.length === 0) {
|
|
12
12
|
return;
|
|
13
13
|
}
|
|
@@ -22,7 +22,9 @@ function setMessagesAttribute(span, messages) {
|
|
|
22
22
|
|
|
23
23
|
const filteredLength = Array.isArray(filteredMessages) ? filteredMessages.length : 1;
|
|
24
24
|
span.setAttributes({
|
|
25
|
-
[GEN_AI_INPUT_MESSAGES_ATTRIBUTE]:
|
|
25
|
+
[GEN_AI_INPUT_MESSAGES_ATTRIBUTE]: enableTruncation
|
|
26
|
+
? getTruncatedJsonString(filteredMessages)
|
|
27
|
+
: getJsonString(filteredMessages),
|
|
26
28
|
[GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE]: filteredLength,
|
|
27
29
|
});
|
|
28
30
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sources":["../../../../src/tracing/anthropic-ai/utils.ts"],"sourcesContent":["import { captureException } from '../../exports';\nimport { SPAN_STATUS_ERROR } from '../../tracing';\nimport type { Span } from '../../types-hoist/span';\nimport type { SpanStatusType } from '../../types-hoist/spanStatus';\nimport {\n GEN_AI_INPUT_MESSAGES_ATTRIBUTE,\n GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE,\n GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE,\n} from '../ai/gen-ai-attributes';\nimport { extractSystemInstructions, getTruncatedJsonString } from '../ai/utils';\nimport type { AnthropicAiResponse } from './types';\n\n/**\n * Set the messages and messages original length attributes.\n * Extracts system instructions before truncation.\n */\nexport function setMessagesAttribute(span: Span, messages: unknown): void {\n if (Array.isArray(messages) && messages.length === 0) {\n return;\n }\n\n const { systemInstructions, filteredMessages } = extractSystemInstructions(messages);\n\n if (systemInstructions) {\n span.setAttributes({\n [GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE]: systemInstructions,\n });\n }\n\n const filteredLength = Array.isArray(filteredMessages) ? filteredMessages.length : 1;\n span.setAttributes({\n [GEN_AI_INPUT_MESSAGES_ATTRIBUTE]: getTruncatedJsonString(filteredMessages),\n [GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE]: filteredLength,\n });\n}\n\nconst ANTHROPIC_ERROR_TYPE_TO_SPAN_STATUS: Record<string, SpanStatusType> = {\n invalid_request_error: 'invalid_argument',\n authentication_error: 'unauthenticated',\n permission_error: 'permission_denied',\n not_found_error: 'not_found',\n request_too_large: 'failed_precondition',\n rate_limit_error: 'resource_exhausted',\n api_error: 'internal_error',\n overloaded_error: 'unavailable',\n};\n\n/**\n * Map an Anthropic API error type to a SpanStatusType value.\n * @see https://docs.anthropic.com/en/api/errors#error-shapes\n */\nexport function mapAnthropicErrorToStatusMessage(errorType: string | undefined): SpanStatusType {\n if (!errorType) {\n return 'internal_error';\n }\n return ANTHROPIC_ERROR_TYPE_TO_SPAN_STATUS[errorType] || 'internal_error';\n}\n\n/**\n * Capture error information from the response\n * @see https://docs.anthropic.com/en/api/errors#error-shapes\n */\nexport function handleResponseError(span: Span, response: AnthropicAiResponse): void {\n if (response.error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: mapAnthropicErrorToStatusMessage(response.error.type) });\n\n captureException(response.error, {\n mechanism: {\n handled: false,\n type: 'auto.ai.anthropic.anthropic_error',\n },\n });\n }\n}\n\n/**\n * Include the system prompt in the messages list, if available\n */\nexport function messagesFromParams(params: Record<string, unknown>): unknown[] {\n const { system, messages, input } = params;\n\n const systemMessages = typeof system === 'string' ? [{ role: 'system', content: params.system }] : [];\n\n const inputParamMessages = Array.isArray(input) ? input : input != null ? [input] : undefined;\n\n const messagesParamMessages = Array.isArray(messages) ? messages : messages != null ? [messages] : [];\n\n const userMessages = inputParamMessages ?? messagesParamMessages;\n\n return [...systemMessages, ...userMessages];\n}\n"],"names":[],"mappings":";;;;;AAYA;AACA;AACA;AACA;AACO,SAAS,oBAAoB,CAAC,IAAI,EAAQ,QAAQ,EAAiB;
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../../../src/tracing/anthropic-ai/utils.ts"],"sourcesContent":["import { captureException } from '../../exports';\nimport { SPAN_STATUS_ERROR } from '../../tracing';\nimport type { Span } from '../../types-hoist/span';\nimport type { SpanStatusType } from '../../types-hoist/spanStatus';\nimport {\n GEN_AI_INPUT_MESSAGES_ATTRIBUTE,\n GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE,\n GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE,\n} from '../ai/gen-ai-attributes';\nimport { extractSystemInstructions, getJsonString, getTruncatedJsonString } from '../ai/utils';\nimport type { AnthropicAiResponse } from './types';\n\n/**\n * Set the messages and messages original length attributes.\n * Extracts system instructions before truncation.\n */\nexport function setMessagesAttribute(span: Span, messages: unknown, enableTruncation: boolean): void {\n if (Array.isArray(messages) && messages.length === 0) {\n return;\n }\n\n const { systemInstructions, filteredMessages } = extractSystemInstructions(messages);\n\n if (systemInstructions) {\n span.setAttributes({\n [GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE]: systemInstructions,\n });\n }\n\n const filteredLength = Array.isArray(filteredMessages) ? filteredMessages.length : 1;\n span.setAttributes({\n [GEN_AI_INPUT_MESSAGES_ATTRIBUTE]: enableTruncation\n ? getTruncatedJsonString(filteredMessages)\n : getJsonString(filteredMessages),\n [GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE]: filteredLength,\n });\n}\n\nconst ANTHROPIC_ERROR_TYPE_TO_SPAN_STATUS: Record<string, SpanStatusType> = {\n invalid_request_error: 'invalid_argument',\n authentication_error: 'unauthenticated',\n permission_error: 'permission_denied',\n not_found_error: 'not_found',\n request_too_large: 'failed_precondition',\n rate_limit_error: 'resource_exhausted',\n api_error: 'internal_error',\n overloaded_error: 'unavailable',\n};\n\n/**\n * Map an Anthropic API error type to a SpanStatusType value.\n * @see https://docs.anthropic.com/en/api/errors#error-shapes\n */\nexport function mapAnthropicErrorToStatusMessage(errorType: string | undefined): SpanStatusType {\n if (!errorType) {\n return 'internal_error';\n }\n return ANTHROPIC_ERROR_TYPE_TO_SPAN_STATUS[errorType] || 'internal_error';\n}\n\n/**\n * Capture error information from the response\n * @see https://docs.anthropic.com/en/api/errors#error-shapes\n */\nexport function handleResponseError(span: Span, response: AnthropicAiResponse): void {\n if (response.error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: mapAnthropicErrorToStatusMessage(response.error.type) });\n\n captureException(response.error, {\n mechanism: {\n handled: false,\n type: 'auto.ai.anthropic.anthropic_error',\n },\n });\n }\n}\n\n/**\n * Include the system prompt in the messages list, if available\n */\nexport function messagesFromParams(params: Record<string, unknown>): unknown[] {\n const { system, messages, input } = params;\n\n const systemMessages = typeof system === 'string' ? [{ role: 'system', content: params.system }] : [];\n\n const inputParamMessages = Array.isArray(input) ? input : input != null ? [input] : undefined;\n\n const messagesParamMessages = Array.isArray(messages) ? messages : messages != null ? [messages] : [];\n\n const userMessages = inputParamMessages ?? messagesParamMessages;\n\n return [...systemMessages, ...userMessages];\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -4,8 +4,7 @@ import { SPAN_STATUS_ERROR } from '../spanstatus.js';
|
|
|
4
4
|
import { startSpanManual, startSpan } from '../trace.js';
|
|
5
5
|
import { handleCallbackErrors } from '../../utils/handleCallbackErrors.js';
|
|
6
6
|
import { GEN_AI_REQUEST_MODEL_ATTRIBUTE, GEN_AI_REQUEST_AVAILABLE_TOOLS_ATTRIBUTE, GEN_AI_EMBEDDINGS_INPUT_ATTRIBUTE, GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE, GEN_AI_INPUT_MESSAGES_ATTRIBUTE, GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE, GEN_AI_RESPONSE_MODEL_ATTRIBUTE, GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE, GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE, GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE, GEN_AI_RESPONSE_TEXT_ATTRIBUTE, GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE, GEN_AI_OPERATION_NAME_ATTRIBUTE, GEN_AI_SYSTEM_ATTRIBUTE, GEN_AI_REQUEST_TEMPERATURE_ATTRIBUTE, GEN_AI_REQUEST_TOP_P_ATTRIBUTE, GEN_AI_REQUEST_TOP_K_ATTRIBUTE, GEN_AI_REQUEST_MAX_TOKENS_ATTRIBUTE, GEN_AI_REQUEST_FREQUENCY_PENALTY_ATTRIBUTE, GEN_AI_REQUEST_PRESENCE_PENALTY_ATTRIBUTE } from '../ai/gen-ai-attributes.js';
|
|
7
|
-
import {
|
|
8
|
-
import { resolveAIRecordingOptions, buildMethodPath, extractSystemInstructions } from '../ai/utils.js';
|
|
7
|
+
import { resolveAIRecordingOptions, shouldEnableTruncation, buildMethodPath, extractSystemInstructions, getTruncatedJsonString, getJsonString } from '../ai/utils.js';
|
|
9
8
|
import { GOOGLE_GENAI_METHOD_REGISTRY, GOOGLE_GENAI_SYSTEM_NAME } from './constants.js';
|
|
10
9
|
import { instrumentStream } from './streaming.js';
|
|
11
10
|
import { contentUnionToMessages } from './utils.js';
|
|
@@ -110,7 +109,12 @@ function extractRequestAttributes(
|
|
|
110
109
|
* This is only recorded if recordInputs is true.
|
|
111
110
|
* Handles different parameter formats for different Google GenAI methods.
|
|
112
111
|
*/
|
|
113
|
-
function addPrivateRequestAttributes(
|
|
112
|
+
function addPrivateRequestAttributes(
|
|
113
|
+
span,
|
|
114
|
+
params,
|
|
115
|
+
isEmbeddings,
|
|
116
|
+
enableTruncation,
|
|
117
|
+
) {
|
|
114
118
|
if (isEmbeddings) {
|
|
115
119
|
const contents = params.contents;
|
|
116
120
|
if (contents != null) {
|
|
@@ -160,7 +164,9 @@ function addPrivateRequestAttributes(span, params, isEmbeddings) {
|
|
|
160
164
|
const filteredLength = Array.isArray(filteredMessages) ? filteredMessages.length : 0;
|
|
161
165
|
span.setAttributes({
|
|
162
166
|
[GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE]: filteredLength,
|
|
163
|
-
[GEN_AI_INPUT_MESSAGES_ATTRIBUTE]:
|
|
167
|
+
[GEN_AI_INPUT_MESSAGES_ATTRIBUTE]: enableTruncation
|
|
168
|
+
? getTruncatedJsonString(filteredMessages)
|
|
169
|
+
: getJsonString(filteredMessages),
|
|
164
170
|
});
|
|
165
171
|
}
|
|
166
172
|
}
|
|
@@ -261,7 +267,12 @@ function instrumentMethod(
|
|
|
261
267
|
async (span) => {
|
|
262
268
|
try {
|
|
263
269
|
if (options.recordInputs && params) {
|
|
264
|
-
addPrivateRequestAttributes(
|
|
270
|
+
addPrivateRequestAttributes(
|
|
271
|
+
span,
|
|
272
|
+
params,
|
|
273
|
+
isEmbeddings,
|
|
274
|
+
shouldEnableTruncation(options.enableTruncation),
|
|
275
|
+
);
|
|
265
276
|
}
|
|
266
277
|
const stream = await target.apply(context, args);
|
|
267
278
|
return instrumentStream(stream, span, Boolean(options.recordOutputs)) ;
|
|
@@ -289,7 +300,7 @@ function instrumentMethod(
|
|
|
289
300
|
},
|
|
290
301
|
(span) => {
|
|
291
302
|
if (options.recordInputs && params) {
|
|
292
|
-
addPrivateRequestAttributes(span, params, isEmbeddings);
|
|
303
|
+
addPrivateRequestAttributes(span, params, isEmbeddings, shouldEnableTruncation(options.enableTruncation));
|
|
293
304
|
}
|
|
294
305
|
|
|
295
306
|
return handleCallbackErrors(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../../src/tracing/google-genai/index.ts"],"sourcesContent":["/* eslint-disable max-lines */\nimport { captureException } from '../../exports';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '../../semanticAttributes';\nimport { SPAN_STATUS_ERROR } from '../../tracing';\nimport { startSpan, startSpanManual } from '../../tracing/trace';\nimport type { Span, SpanAttributeValue } from '../../types-hoist/span';\nimport { handleCallbackErrors } from '../../utils/handleCallbackErrors';\nimport {\n GEN_AI_EMBEDDINGS_INPUT_ATTRIBUTE,\n GEN_AI_INPUT_MESSAGES_ATTRIBUTE,\n GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE,\n GEN_AI_OPERATION_NAME_ATTRIBUTE,\n GEN_AI_REQUEST_AVAILABLE_TOOLS_ATTRIBUTE,\n GEN_AI_REQUEST_FREQUENCY_PENALTY_ATTRIBUTE,\n GEN_AI_REQUEST_MAX_TOKENS_ATTRIBUTE,\n GEN_AI_REQUEST_MODEL_ATTRIBUTE,\n GEN_AI_REQUEST_PRESENCE_PENALTY_ATTRIBUTE,\n GEN_AI_REQUEST_TEMPERATURE_ATTRIBUTE,\n GEN_AI_REQUEST_TOP_K_ATTRIBUTE,\n GEN_AI_REQUEST_TOP_P_ATTRIBUTE,\n GEN_AI_RESPONSE_MODEL_ATTRIBUTE,\n GEN_AI_RESPONSE_TEXT_ATTRIBUTE,\n GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE,\n GEN_AI_SYSTEM_ATTRIBUTE,\n GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE,\n GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE,\n GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE,\n GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE,\n} from '../ai/gen-ai-attributes';\nimport { truncateGenAiMessages } from '../ai/messageTruncation';\nimport type { InstrumentedMethodEntry } from '../ai/utils';\nimport { buildMethodPath, extractSystemInstructions, resolveAIRecordingOptions } from '../ai/utils';\nimport { GOOGLE_GENAI_METHOD_REGISTRY, GOOGLE_GENAI_SYSTEM_NAME } from './constants';\nimport { instrumentStream } from './streaming';\nimport type { Candidate, ContentPart, GoogleGenAIOptions, GoogleGenAIResponse } from './types';\nimport type { ContentListUnion, ContentUnion, Message, PartListUnion } from './utils';\nimport { contentUnionToMessages } from './utils';\n\n/**\n * Extract model from parameters or chat context object\n * For chat instances, the model is available on the chat object as 'model' (older versions) or 'modelVersion' (newer versions)\n */\nexport function extractModel(params: Record<string, unknown>, context?: unknown): string {\n if ('model' in params && typeof params.model === 'string') {\n return params.model;\n }\n\n // Try to get model from chat context object (chat instance has model property)\n if (context && typeof context === 'object') {\n const contextObj = context as Record<string, unknown>;\n\n // Check for 'model' property (older versions, and streaming)\n if ('model' in contextObj && typeof contextObj.model === 'string') {\n return contextObj.model;\n }\n\n // Check for 'modelVersion' property (newer versions)\n if ('modelVersion' in contextObj && typeof contextObj.modelVersion === 'string') {\n return contextObj.modelVersion;\n }\n }\n\n return 'unknown';\n}\n\n/**\n * Extract generation config parameters\n */\nfunction extractConfigAttributes(config: Record<string, unknown>): Record<string, SpanAttributeValue> {\n const attributes: Record<string, SpanAttributeValue> = {};\n\n if ('temperature' in config && typeof config.temperature === 'number') {\n attributes[GEN_AI_REQUEST_TEMPERATURE_ATTRIBUTE] = config.temperature;\n }\n if ('topP' in config && typeof config.topP === 'number') {\n attributes[GEN_AI_REQUEST_TOP_P_ATTRIBUTE] = config.topP;\n }\n if ('topK' in config && typeof config.topK === 'number') {\n attributes[GEN_AI_REQUEST_TOP_K_ATTRIBUTE] = config.topK;\n }\n if ('maxOutputTokens' in config && typeof config.maxOutputTokens === 'number') {\n attributes[GEN_AI_REQUEST_MAX_TOKENS_ATTRIBUTE] = config.maxOutputTokens;\n }\n if ('frequencyPenalty' in config && typeof config.frequencyPenalty === 'number') {\n attributes[GEN_AI_REQUEST_FREQUENCY_PENALTY_ATTRIBUTE] = config.frequencyPenalty;\n }\n if ('presencePenalty' in config && typeof config.presencePenalty === 'number') {\n attributes[GEN_AI_REQUEST_PRESENCE_PENALTY_ATTRIBUTE] = config.presencePenalty;\n }\n\n return attributes;\n}\n\n/**\n * Extract request attributes from method arguments\n * Builds the base attributes for span creation including system info, model, and config\n */\nfunction extractRequestAttributes(\n operationName: string,\n params?: Record<string, unknown>,\n context?: unknown,\n): Record<string, SpanAttributeValue> {\n const attributes: Record<string, SpanAttributeValue> = {\n [GEN_AI_SYSTEM_ATTRIBUTE]: GOOGLE_GENAI_SYSTEM_NAME,\n [GEN_AI_OPERATION_NAME_ATTRIBUTE]: operationName,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ai.google_genai',\n };\n\n if (params) {\n attributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE] = extractModel(params, context);\n\n // Extract generation config parameters\n if ('config' in params && typeof params.config === 'object' && params.config) {\n const config = params.config as Record<string, unknown>;\n Object.assign(attributes, extractConfigAttributes(config));\n\n // Extract available tools from config\n if ('tools' in config && Array.isArray(config.tools)) {\n const functionDeclarations = config.tools.flatMap(\n (tool: { functionDeclarations: unknown[] }) => tool.functionDeclarations,\n );\n attributes[GEN_AI_REQUEST_AVAILABLE_TOOLS_ATTRIBUTE] = JSON.stringify(functionDeclarations);\n }\n }\n } else {\n attributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE] = extractModel({}, context);\n }\n\n return attributes;\n}\n\n/**\n * Add private request attributes to spans.\n * This is only recorded if recordInputs is true.\n * Handles different parameter formats for different Google GenAI methods.\n */\nfunction addPrivateRequestAttributes(span: Span, params: Record<string, unknown>, isEmbeddings: boolean): void {\n if (isEmbeddings) {\n const contents = params.contents;\n if (contents != null) {\n span.setAttribute(\n GEN_AI_EMBEDDINGS_INPUT_ATTRIBUTE,\n typeof contents === 'string' ? contents : JSON.stringify(contents),\n );\n }\n return;\n }\n\n const messages: Message[] = [];\n\n // config.systemInstruction: ContentUnion\n if (\n 'config' in params &&\n params.config &&\n typeof params.config === 'object' &&\n 'systemInstruction' in params.config &&\n params.config.systemInstruction\n ) {\n messages.push(...contentUnionToMessages(params.config.systemInstruction as ContentUnion, 'system'));\n }\n\n // For chats.create: history contains the conversation history\n if ('history' in params) {\n messages.push(...contentUnionToMessages(params.history as PartListUnion, 'user'));\n }\n\n // For models.generateContent: ContentListUnion\n if ('contents' in params) {\n messages.push(...contentUnionToMessages(params.contents as ContentListUnion, 'user'));\n }\n\n // For chat.sendMessage: message can be PartListUnion\n if ('message' in params) {\n messages.push(...contentUnionToMessages(params.message as PartListUnion, 'user'));\n }\n\n if (Array.isArray(messages) && messages.length) {\n const { systemInstructions, filteredMessages } = extractSystemInstructions(messages);\n\n if (systemInstructions) {\n span.setAttribute(GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE, systemInstructions);\n }\n\n const filteredLength = Array.isArray(filteredMessages) ? filteredMessages.length : 0;\n span.setAttributes({\n [GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE]: filteredLength,\n [GEN_AI_INPUT_MESSAGES_ATTRIBUTE]: JSON.stringify(truncateGenAiMessages(filteredMessages as unknown[])),\n });\n }\n}\n\n/**\n * Add response attributes from the Google GenAI response\n * @see https://github.com/googleapis/js-genai/blob/v1.19.0/src/types.ts#L2313\n */\nfunction addResponseAttributes(span: Span, response: GoogleGenAIResponse, recordOutputs?: boolean): void {\n if (!response || typeof response !== 'object') return;\n\n if (response.modelVersion) {\n span.setAttribute(GEN_AI_RESPONSE_MODEL_ATTRIBUTE, response.modelVersion);\n }\n\n // Add usage metadata if present\n if (response.usageMetadata && typeof response.usageMetadata === 'object') {\n const usage = response.usageMetadata;\n if (typeof usage.promptTokenCount === 'number') {\n span.setAttributes({\n [GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE]: usage.promptTokenCount,\n });\n }\n if (typeof usage.candidatesTokenCount === 'number') {\n span.setAttributes({\n [GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE]: usage.candidatesTokenCount,\n });\n }\n if (typeof usage.totalTokenCount === 'number') {\n span.setAttributes({\n [GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE]: usage.totalTokenCount,\n });\n }\n }\n\n // Add response text if recordOutputs is enabled\n if (recordOutputs && Array.isArray(response.candidates) && response.candidates.length > 0) {\n const responseTexts = response.candidates\n .map((candidate: Candidate) => {\n if (candidate.content?.parts && Array.isArray(candidate.content.parts)) {\n return candidate.content.parts\n .map((part: ContentPart) => (typeof part.text === 'string' ? part.text : ''))\n .filter((text: string) => text.length > 0)\n .join('');\n }\n return '';\n })\n .filter((text: string) => text.length > 0);\n\n if (responseTexts.length > 0) {\n span.setAttributes({\n [GEN_AI_RESPONSE_TEXT_ATTRIBUTE]: responseTexts.join(''),\n });\n }\n }\n\n // Add tool calls if recordOutputs is enabled\n if (recordOutputs && response.functionCalls) {\n const functionCalls = response.functionCalls;\n if (Array.isArray(functionCalls) && functionCalls.length > 0) {\n span.setAttributes({\n [GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE]: JSON.stringify(functionCalls),\n });\n }\n }\n}\n\n/**\n * Instrument any async or synchronous genai method with Sentry spans\n * Handles operations like models.generateContent and chat.sendMessage and chats.create\n * @see https://docs.sentry.io/platforms/javascript/guides/node/tracing/instrumentation/ai-agents-module/#manual-instrumentation\n */\nfunction instrumentMethod<T extends unknown[], R>(\n originalMethod: (...args: T) => R | Promise<R>,\n methodPath: string,\n instrumentedMethod: InstrumentedMethodEntry,\n context: unknown,\n options: GoogleGenAIOptions,\n): (...args: T) => R | Promise<R> {\n const isEmbeddings = instrumentedMethod.operation === 'embeddings';\n\n return new Proxy(originalMethod, {\n apply(target, _, args: T): R | Promise<R> {\n const operationName = instrumentedMethod.operation || 'unknown';\n const params = args[0] as Record<string, unknown> | undefined;\n const requestAttributes = extractRequestAttributes(operationName, params, context);\n const model = requestAttributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE] ?? 'unknown';\n\n // Check if this is a streaming method\n if (instrumentedMethod.streaming) {\n // Use startSpanManual for streaming methods to control span lifecycle\n return startSpanManual(\n {\n name: `${operationName} ${model}`,\n op: `gen_ai.${operationName}`,\n attributes: requestAttributes,\n },\n async (span: Span) => {\n try {\n if (options.recordInputs && params) {\n addPrivateRequestAttributes(span, params, isEmbeddings);\n }\n const stream = await target.apply(context, args);\n return instrumentStream(stream, span, Boolean(options.recordOutputs)) as R;\n } catch (error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureException(error, {\n mechanism: {\n handled: false,\n type: 'auto.ai.google_genai',\n data: { function: methodPath },\n },\n });\n span.end();\n throw error;\n }\n },\n );\n }\n // Single span for both sync and async operations\n return startSpan(\n {\n name: `${operationName} ${model}`,\n op: `gen_ai.${operationName}`,\n attributes: requestAttributes,\n },\n (span: Span) => {\n if (options.recordInputs && params) {\n addPrivateRequestAttributes(span, params, isEmbeddings);\n }\n\n return handleCallbackErrors(\n () => target.apply(context, args),\n error => {\n captureException(error, {\n mechanism: { handled: false, type: 'auto.ai.google_genai', data: { function: methodPath } },\n });\n },\n () => {},\n result => {\n // Only add response attributes for content-producing methods, not for embeddings\n if (!isEmbeddings) {\n addResponseAttributes(span, result, options.recordOutputs);\n }\n },\n );\n },\n );\n },\n }) as (...args: T) => R | Promise<R>;\n}\n\n/**\n * Create a deep proxy for Google GenAI client instrumentation\n * Recursively instruments methods and handles special cases like chats.create\n */\nfunction createDeepProxy<T extends object>(target: T, currentPath = '', options: GoogleGenAIOptions): T {\n return new Proxy(target, {\n get: (t, prop, receiver) => {\n const value = Reflect.get(t, prop, receiver);\n const methodPath = buildMethodPath(currentPath, String(prop));\n\n const instrumentedMethod: InstrumentedMethodEntry | undefined =\n GOOGLE_GENAI_METHOD_REGISTRY[methodPath as keyof typeof GOOGLE_GENAI_METHOD_REGISTRY];\n if (typeof value === 'function' && instrumentedMethod) {\n // If an operation is specified, we need to instrument the method itself\n const wrappedMethod = instrumentedMethod.operation\n ? instrumentMethod(value as (...args: unknown[]) => unknown, methodPath, instrumentedMethod, t, options)\n : value.bind(t);\n\n if (!instrumentedMethod.proxyResultPath) {\n return wrappedMethod;\n }\n\n // If a proxyResultPath is specified, we need to proxy the result of the method.\n // Note: This currently only properly handles synchronous methods. For async methods,\n // the Promise itself would be proxied instead of the resolved value. Currently we\n // don't have a case where this is needed, so I'll keep it simple for now.\n return function (...args: unknown[]): unknown {\n const result = wrappedMethod(...args);\n if (result && typeof result === 'object') {\n return createDeepProxy(result as object, instrumentedMethod.proxyResultPath, options);\n }\n return result;\n };\n }\n\n if (typeof value === 'function') {\n // Bind non-instrumented functions to preserve the original `this` context\n return value.bind(t);\n }\n\n if (value && typeof value === 'object') {\n return createDeepProxy(value, methodPath, options);\n }\n\n return value;\n },\n });\n}\n\n/**\n * Instrument a Google GenAI client with Sentry tracing\n * Can be used across Node.js, Cloudflare Workers, and Vercel Edge\n *\n * @template T - The type of the client that extends client object\n * @param client - The Google GenAI client to instrument\n * @param options - Optional configuration for recording inputs and outputs\n * @returns The instrumented client with the same type as the input\n *\n * @example\n * ```typescript\n * import { GoogleGenAI } from '@google/genai';\n * import { instrumentGoogleGenAIClient } from '@sentry/core';\n *\n * const genAI = new GoogleGenAI({ apiKey: process.env.GOOGLE_GENAI_API_KEY });\n * const instrumentedClient = instrumentGoogleGenAIClient(genAI);\n *\n * // Now both chats.create and sendMessage will be instrumented\n * const chat = instrumentedClient.chats.create({ model: 'gemini-1.5-pro' });\n * const response = await chat.sendMessage({ message: 'Hello' });\n * ```\n */\nexport function instrumentGoogleGenAIClient<T extends object>(client: T, options?: GoogleGenAIOptions): T {\n return createDeepProxy(client, '', resolveAIRecordingOptions(options));\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/tracing/google-genai/index.ts"],"sourcesContent":["/* eslint-disable max-lines */\nimport { captureException } from '../../exports';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '../../semanticAttributes';\nimport { SPAN_STATUS_ERROR } from '../../tracing';\nimport { startSpan, startSpanManual } from '../../tracing/trace';\nimport type { Span, SpanAttributeValue } from '../../types-hoist/span';\nimport { handleCallbackErrors } from '../../utils/handleCallbackErrors';\nimport {\n GEN_AI_EMBEDDINGS_INPUT_ATTRIBUTE,\n GEN_AI_INPUT_MESSAGES_ATTRIBUTE,\n GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE,\n GEN_AI_OPERATION_NAME_ATTRIBUTE,\n GEN_AI_REQUEST_AVAILABLE_TOOLS_ATTRIBUTE,\n GEN_AI_REQUEST_FREQUENCY_PENALTY_ATTRIBUTE,\n GEN_AI_REQUEST_MAX_TOKENS_ATTRIBUTE,\n GEN_AI_REQUEST_MODEL_ATTRIBUTE,\n GEN_AI_REQUEST_PRESENCE_PENALTY_ATTRIBUTE,\n GEN_AI_REQUEST_TEMPERATURE_ATTRIBUTE,\n GEN_AI_REQUEST_TOP_K_ATTRIBUTE,\n GEN_AI_REQUEST_TOP_P_ATTRIBUTE,\n GEN_AI_RESPONSE_MODEL_ATTRIBUTE,\n GEN_AI_RESPONSE_TEXT_ATTRIBUTE,\n GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE,\n GEN_AI_SYSTEM_ATTRIBUTE,\n GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE,\n GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE,\n GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE,\n GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE,\n} from '../ai/gen-ai-attributes';\nimport type { InstrumentedMethodEntry } from '../ai/utils';\nimport {\n buildMethodPath,\n extractSystemInstructions,\n getJsonString,\n getTruncatedJsonString,\n resolveAIRecordingOptions,\n shouldEnableTruncation,\n} from '../ai/utils';\nimport { GOOGLE_GENAI_METHOD_REGISTRY, GOOGLE_GENAI_SYSTEM_NAME } from './constants';\nimport { instrumentStream } from './streaming';\nimport type { Candidate, ContentPart, GoogleGenAIOptions, GoogleGenAIResponse } from './types';\nimport type { ContentListUnion, ContentUnion, Message, PartListUnion } from './utils';\nimport { contentUnionToMessages } from './utils';\n\n/**\n * Extract model from parameters or chat context object\n * For chat instances, the model is available on the chat object as 'model' (older versions) or 'modelVersion' (newer versions)\n */\nexport function extractModel(params: Record<string, unknown>, context?: unknown): string {\n if ('model' in params && typeof params.model === 'string') {\n return params.model;\n }\n\n // Try to get model from chat context object (chat instance has model property)\n if (context && typeof context === 'object') {\n const contextObj = context as Record<string, unknown>;\n\n // Check for 'model' property (older versions, and streaming)\n if ('model' in contextObj && typeof contextObj.model === 'string') {\n return contextObj.model;\n }\n\n // Check for 'modelVersion' property (newer versions)\n if ('modelVersion' in contextObj && typeof contextObj.modelVersion === 'string') {\n return contextObj.modelVersion;\n }\n }\n\n return 'unknown';\n}\n\n/**\n * Extract generation config parameters\n */\nfunction extractConfigAttributes(config: Record<string, unknown>): Record<string, SpanAttributeValue> {\n const attributes: Record<string, SpanAttributeValue> = {};\n\n if ('temperature' in config && typeof config.temperature === 'number') {\n attributes[GEN_AI_REQUEST_TEMPERATURE_ATTRIBUTE] = config.temperature;\n }\n if ('topP' in config && typeof config.topP === 'number') {\n attributes[GEN_AI_REQUEST_TOP_P_ATTRIBUTE] = config.topP;\n }\n if ('topK' in config && typeof config.topK === 'number') {\n attributes[GEN_AI_REQUEST_TOP_K_ATTRIBUTE] = config.topK;\n }\n if ('maxOutputTokens' in config && typeof config.maxOutputTokens === 'number') {\n attributes[GEN_AI_REQUEST_MAX_TOKENS_ATTRIBUTE] = config.maxOutputTokens;\n }\n if ('frequencyPenalty' in config && typeof config.frequencyPenalty === 'number') {\n attributes[GEN_AI_REQUEST_FREQUENCY_PENALTY_ATTRIBUTE] = config.frequencyPenalty;\n }\n if ('presencePenalty' in config && typeof config.presencePenalty === 'number') {\n attributes[GEN_AI_REQUEST_PRESENCE_PENALTY_ATTRIBUTE] = config.presencePenalty;\n }\n\n return attributes;\n}\n\n/**\n * Extract request attributes from method arguments\n * Builds the base attributes for span creation including system info, model, and config\n */\nfunction extractRequestAttributes(\n operationName: string,\n params?: Record<string, unknown>,\n context?: unknown,\n): Record<string, SpanAttributeValue> {\n const attributes: Record<string, SpanAttributeValue> = {\n [GEN_AI_SYSTEM_ATTRIBUTE]: GOOGLE_GENAI_SYSTEM_NAME,\n [GEN_AI_OPERATION_NAME_ATTRIBUTE]: operationName,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ai.google_genai',\n };\n\n if (params) {\n attributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE] = extractModel(params, context);\n\n // Extract generation config parameters\n if ('config' in params && typeof params.config === 'object' && params.config) {\n const config = params.config as Record<string, unknown>;\n Object.assign(attributes, extractConfigAttributes(config));\n\n // Extract available tools from config\n if ('tools' in config && Array.isArray(config.tools)) {\n const functionDeclarations = config.tools.flatMap(\n (tool: { functionDeclarations: unknown[] }) => tool.functionDeclarations,\n );\n attributes[GEN_AI_REQUEST_AVAILABLE_TOOLS_ATTRIBUTE] = JSON.stringify(functionDeclarations);\n }\n }\n } else {\n attributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE] = extractModel({}, context);\n }\n\n return attributes;\n}\n\n/**\n * Add private request attributes to spans.\n * This is only recorded if recordInputs is true.\n * Handles different parameter formats for different Google GenAI methods.\n */\nfunction addPrivateRequestAttributes(\n span: Span,\n params: Record<string, unknown>,\n isEmbeddings: boolean,\n enableTruncation: boolean,\n): void {\n if (isEmbeddings) {\n const contents = params.contents;\n if (contents != null) {\n span.setAttribute(\n GEN_AI_EMBEDDINGS_INPUT_ATTRIBUTE,\n typeof contents === 'string' ? contents : JSON.stringify(contents),\n );\n }\n return;\n }\n\n const messages: Message[] = [];\n\n // config.systemInstruction: ContentUnion\n if (\n 'config' in params &&\n params.config &&\n typeof params.config === 'object' &&\n 'systemInstruction' in params.config &&\n params.config.systemInstruction\n ) {\n messages.push(...contentUnionToMessages(params.config.systemInstruction as ContentUnion, 'system'));\n }\n\n // For chats.create: history contains the conversation history\n if ('history' in params) {\n messages.push(...contentUnionToMessages(params.history as PartListUnion, 'user'));\n }\n\n // For models.generateContent: ContentListUnion\n if ('contents' in params) {\n messages.push(...contentUnionToMessages(params.contents as ContentListUnion, 'user'));\n }\n\n // For chat.sendMessage: message can be PartListUnion\n if ('message' in params) {\n messages.push(...contentUnionToMessages(params.message as PartListUnion, 'user'));\n }\n\n if (Array.isArray(messages) && messages.length) {\n const { systemInstructions, filteredMessages } = extractSystemInstructions(messages);\n\n if (systemInstructions) {\n span.setAttribute(GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE, systemInstructions);\n }\n\n const filteredLength = Array.isArray(filteredMessages) ? filteredMessages.length : 0;\n span.setAttributes({\n [GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE]: filteredLength,\n [GEN_AI_INPUT_MESSAGES_ATTRIBUTE]: enableTruncation\n ? getTruncatedJsonString(filteredMessages)\n : getJsonString(filteredMessages),\n });\n }\n}\n\n/**\n * Add response attributes from the Google GenAI response\n * @see https://github.com/googleapis/js-genai/blob/v1.19.0/src/types.ts#L2313\n */\nfunction addResponseAttributes(span: Span, response: GoogleGenAIResponse, recordOutputs?: boolean): void {\n if (!response || typeof response !== 'object') return;\n\n if (response.modelVersion) {\n span.setAttribute(GEN_AI_RESPONSE_MODEL_ATTRIBUTE, response.modelVersion);\n }\n\n // Add usage metadata if present\n if (response.usageMetadata && typeof response.usageMetadata === 'object') {\n const usage = response.usageMetadata;\n if (typeof usage.promptTokenCount === 'number') {\n span.setAttributes({\n [GEN_AI_USAGE_INPUT_TOKENS_ATTRIBUTE]: usage.promptTokenCount,\n });\n }\n if (typeof usage.candidatesTokenCount === 'number') {\n span.setAttributes({\n [GEN_AI_USAGE_OUTPUT_TOKENS_ATTRIBUTE]: usage.candidatesTokenCount,\n });\n }\n if (typeof usage.totalTokenCount === 'number') {\n span.setAttributes({\n [GEN_AI_USAGE_TOTAL_TOKENS_ATTRIBUTE]: usage.totalTokenCount,\n });\n }\n }\n\n // Add response text if recordOutputs is enabled\n if (recordOutputs && Array.isArray(response.candidates) && response.candidates.length > 0) {\n const responseTexts = response.candidates\n .map((candidate: Candidate) => {\n if (candidate.content?.parts && Array.isArray(candidate.content.parts)) {\n return candidate.content.parts\n .map((part: ContentPart) => (typeof part.text === 'string' ? part.text : ''))\n .filter((text: string) => text.length > 0)\n .join('');\n }\n return '';\n })\n .filter((text: string) => text.length > 0);\n\n if (responseTexts.length > 0) {\n span.setAttributes({\n [GEN_AI_RESPONSE_TEXT_ATTRIBUTE]: responseTexts.join(''),\n });\n }\n }\n\n // Add tool calls if recordOutputs is enabled\n if (recordOutputs && response.functionCalls) {\n const functionCalls = response.functionCalls;\n if (Array.isArray(functionCalls) && functionCalls.length > 0) {\n span.setAttributes({\n [GEN_AI_RESPONSE_TOOL_CALLS_ATTRIBUTE]: JSON.stringify(functionCalls),\n });\n }\n }\n}\n\n/**\n * Instrument any async or synchronous genai method with Sentry spans\n * Handles operations like models.generateContent and chat.sendMessage and chats.create\n * @see https://docs.sentry.io/platforms/javascript/guides/node/tracing/instrumentation/ai-agents-module/#manual-instrumentation\n */\nfunction instrumentMethod<T extends unknown[], R>(\n originalMethod: (...args: T) => R | Promise<R>,\n methodPath: string,\n instrumentedMethod: InstrumentedMethodEntry,\n context: unknown,\n options: GoogleGenAIOptions,\n): (...args: T) => R | Promise<R> {\n const isEmbeddings = instrumentedMethod.operation === 'embeddings';\n\n return new Proxy(originalMethod, {\n apply(target, _, args: T): R | Promise<R> {\n const operationName = instrumentedMethod.operation || 'unknown';\n const params = args[0] as Record<string, unknown> | undefined;\n const requestAttributes = extractRequestAttributes(operationName, params, context);\n const model = requestAttributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE] ?? 'unknown';\n\n // Check if this is a streaming method\n if (instrumentedMethod.streaming) {\n // Use startSpanManual for streaming methods to control span lifecycle\n return startSpanManual(\n {\n name: `${operationName} ${model}`,\n op: `gen_ai.${operationName}`,\n attributes: requestAttributes,\n },\n async (span: Span) => {\n try {\n if (options.recordInputs && params) {\n addPrivateRequestAttributes(\n span,\n params,\n isEmbeddings,\n shouldEnableTruncation(options.enableTruncation),\n );\n }\n const stream = await target.apply(context, args);\n return instrumentStream(stream, span, Boolean(options.recordOutputs)) as R;\n } catch (error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureException(error, {\n mechanism: {\n handled: false,\n type: 'auto.ai.google_genai',\n data: { function: methodPath },\n },\n });\n span.end();\n throw error;\n }\n },\n );\n }\n // Single span for both sync and async operations\n return startSpan(\n {\n name: `${operationName} ${model}`,\n op: `gen_ai.${operationName}`,\n attributes: requestAttributes,\n },\n (span: Span) => {\n if (options.recordInputs && params) {\n addPrivateRequestAttributes(span, params, isEmbeddings, shouldEnableTruncation(options.enableTruncation));\n }\n\n return handleCallbackErrors(\n () => target.apply(context, args),\n error => {\n captureException(error, {\n mechanism: { handled: false, type: 'auto.ai.google_genai', data: { function: methodPath } },\n });\n },\n () => {},\n result => {\n // Only add response attributes for content-producing methods, not for embeddings\n if (!isEmbeddings) {\n addResponseAttributes(span, result, options.recordOutputs);\n }\n },\n );\n },\n );\n },\n }) as (...args: T) => R | Promise<R>;\n}\n\n/**\n * Create a deep proxy for Google GenAI client instrumentation\n * Recursively instruments methods and handles special cases like chats.create\n */\nfunction createDeepProxy<T extends object>(target: T, currentPath = '', options: GoogleGenAIOptions): T {\n return new Proxy(target, {\n get: (t, prop, receiver) => {\n const value = Reflect.get(t, prop, receiver);\n const methodPath = buildMethodPath(currentPath, String(prop));\n\n const instrumentedMethod: InstrumentedMethodEntry | undefined =\n GOOGLE_GENAI_METHOD_REGISTRY[methodPath as keyof typeof GOOGLE_GENAI_METHOD_REGISTRY];\n if (typeof value === 'function' && instrumentedMethod) {\n // If an operation is specified, we need to instrument the method itself\n const wrappedMethod = instrumentedMethod.operation\n ? instrumentMethod(value as (...args: unknown[]) => unknown, methodPath, instrumentedMethod, t, options)\n : value.bind(t);\n\n if (!instrumentedMethod.proxyResultPath) {\n return wrappedMethod;\n }\n\n // If a proxyResultPath is specified, we need to proxy the result of the method.\n // Note: This currently only properly handles synchronous methods. For async methods,\n // the Promise itself would be proxied instead of the resolved value. Currently we\n // don't have a case where this is needed, so I'll keep it simple for now.\n return function (...args: unknown[]): unknown {\n const result = wrappedMethod(...args);\n if (result && typeof result === 'object') {\n return createDeepProxy(result as object, instrumentedMethod.proxyResultPath, options);\n }\n return result;\n };\n }\n\n if (typeof value === 'function') {\n // Bind non-instrumented functions to preserve the original `this` context\n return value.bind(t);\n }\n\n if (value && typeof value === 'object') {\n return createDeepProxy(value, methodPath, options);\n }\n\n return value;\n },\n });\n}\n\n/**\n * Instrument a Google GenAI client with Sentry tracing\n * Can be used across Node.js, Cloudflare Workers, and Vercel Edge\n *\n * @template T - The type of the client that extends client object\n * @param client - The Google GenAI client to instrument\n * @param options - Optional configuration for recording inputs and outputs\n * @returns The instrumented client with the same type as the input\n *\n * @example\n * ```typescript\n * import { GoogleGenAI } from '@google/genai';\n * import { instrumentGoogleGenAIClient } from '@sentry/core';\n *\n * const genAI = new GoogleGenAI({ apiKey: process.env.GOOGLE_GENAI_API_KEY });\n * const instrumentedClient = instrumentGoogleGenAIClient(genAI);\n *\n * // Now both chats.create and sendMessage will be instrumented\n * const chat = instrumentedClient.chats.create({ model: 'gemini-1.5-pro' });\n * const response = await chat.sendMessage({ message: 'Hello' });\n * ```\n */\nexport function instrumentGoogleGenAIClient<T extends object>(client: T, options?: GoogleGenAIOptions): T {\n return createDeepProxy(client, '', resolveAIRecordingOptions(options));\n}\n"],"names":[],"mappings":"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"}
|