@posthog/ai 6.1.1 → 6.1.2

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../../src/utils.ts","../../src/typeGuards.ts","../../src/sanitization.ts","../../src/anthropic/index.ts"],"sourcesContent":["import { PostHog } from 'posthog-node'\nimport { Buffer } from 'buffer'\nimport OpenAIOrignal from 'openai'\nimport AnthropicOriginal from '@anthropic-ai/sdk'\nimport type { ChatCompletionTool } from 'openai/resources/chat/completions'\nimport type { Tool as GeminiTool } from '@google/genai'\nimport type { FormattedMessage, FormattedContent, TokenUsage } from './types'\n\ntype ChatCompletionCreateParamsBase = OpenAIOrignal.Chat.Completions.ChatCompletionCreateParams\ntype MessageCreateParams = AnthropicOriginal.Messages.MessageCreateParams\ntype ResponseCreateParams = OpenAIOrignal.Responses.ResponseCreateParams\ntype AnthropicTool = AnthropicOriginal.Tool\n\n// limit large outputs by truncating to 200kb (approx 200k bytes)\nexport const MAX_OUTPUT_SIZE = 200000\nconst STRING_FORMAT = 'utf8'\n\nexport interface MonitoringParams {\n posthogDistinctId?: string\n posthogTraceId?: string\n posthogProperties?: Record<string, any>\n posthogPrivacyMode?: boolean\n posthogGroups?: Record<string, any>\n posthogModelOverride?: string\n posthogProviderOverride?: string\n posthogCostOverride?: CostOverride\n posthogCaptureImmediate?: boolean\n}\n\nexport interface CostOverride {\n inputCost: number\n outputCost: number\n}\n\nexport const getModelParams = (\n params: ((ChatCompletionCreateParamsBase | MessageCreateParams | ResponseCreateParams) & MonitoringParams) | null\n): Record<string, any> => {\n if (!params) {\n return {}\n }\n const modelParams: Record<string, any> = {}\n const paramKeys = [\n 'temperature',\n 'max_tokens',\n 'max_completion_tokens',\n 'top_p',\n 'frequency_penalty',\n 'presence_penalty',\n 'n',\n 'stop',\n 'stream',\n 'streaming',\n ] as const\n\n for (const key of paramKeys) {\n if (key in params && (params as any)[key] !== undefined) {\n modelParams[key] = (params as any)[key]\n }\n }\n return modelParams\n}\n\n/**\n * Helper to format responses (non-streaming) for consumption, mirroring Python's openai vs. anthropic approach.\n */\nexport const formatResponse = (response: any, provider: string): FormattedMessage[] => {\n if (!response) {\n return []\n }\n if (provider === 'anthropic') {\n return formatResponseAnthropic(response)\n } else if (provider === 'openai') {\n return formatResponseOpenAI(response)\n } else if (provider === 'gemini') {\n return formatResponseGemini(response)\n }\n return []\n}\n\nexport const formatResponseAnthropic = (response: any): FormattedMessage[] => {\n const output: FormattedMessage[] = []\n const content: FormattedContent = []\n\n for (const choice of response.content ?? []) {\n if (choice?.type === 'text' && choice?.text) {\n content.push({ type: 'text', text: choice.text })\n } else if (choice?.type === 'tool_use' && choice?.name && choice?.id) {\n content.push({\n type: 'function',\n id: choice.id,\n function: {\n name: choice.name,\n arguments: choice.input || {},\n },\n })\n }\n }\n\n if (content.length > 0) {\n output.push({\n role: 'assistant',\n content,\n })\n }\n\n return output\n}\n\nexport const formatResponseOpenAI = (response: any): FormattedMessage[] => {\n const output: FormattedMessage[] = []\n\n if (response.choices) {\n for (const choice of response.choices) {\n const content: FormattedContent = []\n let role = 'assistant'\n\n if (choice.message) {\n if (choice.message.role) {\n role = choice.message.role\n }\n\n if (choice.message.content) {\n content.push({ type: 'text', text: choice.message.content })\n }\n\n if (choice.message.tool_calls) {\n for (const toolCall of choice.message.tool_calls) {\n content.push({\n type: 'function',\n id: toolCall.id,\n function: {\n name: toolCall.function.name,\n arguments: toolCall.function.arguments,\n },\n })\n }\n }\n }\n\n if (content.length > 0) {\n output.push({\n role,\n content,\n })\n }\n }\n }\n\n // Handle Responses API format\n if (response.output) {\n const content: FormattedContent = []\n let role = 'assistant'\n\n for (const item of response.output) {\n if (item.type === 'message') {\n role = item.role\n\n if (item.content && Array.isArray(item.content)) {\n for (const contentItem of item.content) {\n if (contentItem.type === 'output_text' && contentItem.text) {\n content.push({ type: 'text', text: contentItem.text })\n } else if (contentItem.text) {\n content.push({ type: 'text', text: contentItem.text })\n } else if (contentItem.type === 'input_image' && contentItem.image_url) {\n content.push({\n type: 'image',\n image: contentItem.image_url,\n })\n }\n }\n } else if (item.content) {\n content.push({ type: 'text', text: String(item.content) })\n }\n } else if (item.type === 'function_call') {\n content.push({\n type: 'function',\n id: item.call_id || item.id || '',\n function: {\n name: item.name,\n arguments: item.arguments || {},\n },\n })\n }\n }\n\n if (content.length > 0) {\n output.push({\n role,\n content,\n })\n }\n }\n\n return output\n}\n\nexport const formatResponseGemini = (response: any): FormattedMessage[] => {\n const output: FormattedMessage[] = []\n\n if (response.candidates && Array.isArray(response.candidates)) {\n for (const candidate of response.candidates) {\n if (candidate.content && candidate.content.parts) {\n const content: FormattedContent = []\n\n for (const part of candidate.content.parts) {\n if (part.text) {\n content.push({ type: 'text', text: part.text })\n } else if (part.functionCall) {\n content.push({\n type: 'function',\n function: {\n name: part.functionCall.name,\n arguments: part.functionCall.args,\n },\n })\n }\n }\n\n if (content.length > 0) {\n output.push({\n role: 'assistant',\n content,\n })\n }\n } else if (candidate.text) {\n output.push({\n role: 'assistant',\n content: [{ type: 'text', text: candidate.text }],\n })\n }\n }\n } else if (response.text) {\n output.push({\n role: 'assistant',\n content: [{ type: 'text', text: response.text }],\n })\n }\n\n return output\n}\n\nexport const mergeSystemPrompt = (params: MessageCreateParams & MonitoringParams, provider: string): any => {\n if (provider == 'anthropic') {\n const messages = params.messages || []\n if (!(params as any).system) {\n return messages\n }\n const systemMessage = (params as any).system\n return [{ role: 'system', content: systemMessage }, ...messages]\n }\n return params.messages\n}\n\nexport const withPrivacyMode = (client: PostHog, privacyMode: boolean, input: any): any => {\n return (client as any).privacy_mode || privacyMode ? null : input\n}\n\nexport const truncate = (str: string): string => {\n try {\n const buffer = Buffer.from(str, STRING_FORMAT)\n if (buffer.length <= MAX_OUTPUT_SIZE) {\n return str\n }\n const truncatedBuffer = buffer.slice(0, MAX_OUTPUT_SIZE)\n return `${truncatedBuffer.toString(STRING_FORMAT)}... [truncated]`\n } catch (error) {\n console.error('Error truncating, likely not a string')\n return str\n }\n}\n\n/**\n * Extract available tool calls from the request parameters.\n * These are the tools provided to the LLM, not the tool calls in the response.\n */\nexport const extractAvailableToolCalls = (\n provider: string,\n params: any\n): ChatCompletionTool[] | AnthropicTool[] | GeminiTool[] | null => {\n if (provider === 'anthropic') {\n if (params.tools) {\n return params.tools\n }\n\n return null\n } else if (provider === 'gemini') {\n if (params.config && params.config.tools) {\n return params.config.tools\n }\n\n return null\n } else if (provider === 'openai') {\n if (params.tools) {\n return params.tools\n }\n\n return null\n } else if (provider === 'vercel') {\n // Vercel AI SDK stores tools in params.mode.tools when mode type is 'regular'\n if (params.mode?.type === 'regular' && params.mode.tools) {\n return params.mode.tools\n }\n\n return null\n }\n\n return null\n}\n\nexport type SendEventToPosthogParams = {\n client: PostHog\n distinctId?: string\n traceId: string\n model: string\n provider: string\n input: any\n output: any\n latency: number\n baseURL: string\n httpStatus: number\n usage?: TokenUsage\n params: (ChatCompletionCreateParamsBase | MessageCreateParams | ResponseCreateParams) & MonitoringParams\n isError?: boolean\n error?: string\n tools?: ChatCompletionTool[] | AnthropicTool[] | GeminiTool[] | null\n captureImmediate?: boolean\n}\n\nfunction sanitizeValues(obj: any): any {\n if (obj === undefined || obj === null) {\n return obj\n }\n const jsonSafe = JSON.parse(JSON.stringify(obj))\n if (typeof jsonSafe === 'string') {\n return Buffer.from(jsonSafe, STRING_FORMAT).toString(STRING_FORMAT)\n } else if (Array.isArray(jsonSafe)) {\n return jsonSafe.map(sanitizeValues)\n } else if (jsonSafe && typeof jsonSafe === 'object') {\n return Object.fromEntries(Object.entries(jsonSafe).map(([k, v]) => [k, sanitizeValues(v)]))\n }\n return jsonSafe\n}\n\nexport const sendEventToPosthog = async ({\n client,\n distinctId,\n traceId,\n model,\n provider,\n input,\n output,\n latency,\n baseURL,\n params,\n httpStatus = 200,\n usage = {},\n isError = false,\n error,\n tools,\n captureImmediate = false,\n}: SendEventToPosthogParams): Promise<void> => {\n if (!client.capture) {\n return Promise.resolve()\n }\n // sanitize input and output for UTF-8 validity\n const safeInput = sanitizeValues(input)\n const safeOutput = sanitizeValues(output)\n const safeError = sanitizeValues(error)\n\n let errorData = {}\n if (isError) {\n errorData = {\n $ai_is_error: true,\n $ai_error: safeError,\n }\n }\n let costOverrideData = {}\n if (params.posthogCostOverride) {\n const inputCostUSD = (params.posthogCostOverride.inputCost ?? 0) * (usage.inputTokens ?? 0)\n const outputCostUSD = (params.posthogCostOverride.outputCost ?? 0) * (usage.outputTokens ?? 0)\n costOverrideData = {\n $ai_input_cost_usd: inputCostUSD,\n $ai_output_cost_usd: outputCostUSD,\n $ai_total_cost_usd: inputCostUSD + outputCostUSD,\n }\n }\n\n const additionalTokenValues = {\n ...(usage.reasoningTokens ? { $ai_reasoning_tokens: usage.reasoningTokens } : {}),\n ...(usage.cacheReadInputTokens ? { $ai_cache_read_input_tokens: usage.cacheReadInputTokens } : {}),\n ...(usage.cacheCreationInputTokens ? { $ai_cache_creation_input_tokens: usage.cacheCreationInputTokens } : {}),\n }\n\n const properties = {\n $ai_provider: params.posthogProviderOverride ?? provider,\n $ai_model: params.posthogModelOverride ?? model,\n $ai_model_parameters: getModelParams(params),\n $ai_input: withPrivacyMode(client, params.posthogPrivacyMode ?? false, safeInput),\n $ai_output_choices: withPrivacyMode(client, params.posthogPrivacyMode ?? false, safeOutput),\n $ai_http_status: httpStatus,\n $ai_input_tokens: usage.inputTokens ?? 0,\n $ai_output_tokens: usage.outputTokens ?? 0,\n ...additionalTokenValues,\n $ai_latency: latency,\n $ai_trace_id: traceId,\n $ai_base_url: baseURL,\n ...params.posthogProperties,\n ...(distinctId ? {} : { $process_person_profile: false }),\n ...(tools ? { $ai_tools: tools } : {}),\n ...errorData,\n ...costOverrideData,\n }\n\n const event = {\n distinctId: distinctId ?? traceId,\n event: '$ai_generation',\n properties,\n groups: params.posthogGroups,\n }\n\n if (captureImmediate) {\n // await capture promise to send single event in serverless environments\n await client.captureImmediate(event)\n } else {\n client.capture(event)\n }\n}\n","// Type guards for safer type checking\n\nexport const isString = (value: unknown): value is string => {\n return typeof value === 'string'\n}\n\nexport const isObject = (value: unknown): value is Record<string, unknown> => {\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n}\n","import { isString, isObject } from './typeGuards'\n\nconst REDACTED_IMAGE_PLACEHOLDER = '[base64 image redacted]'\n\n// ============================================\n// Base64 Detection Helpers\n// ============================================\n\nconst isBase64DataUrl = (str: string): boolean => {\n return /^data:([^;]+);base64,/.test(str)\n}\n\nconst isValidUrl = (str: string): boolean => {\n try {\n new URL(str)\n return true\n } catch {\n // Not an absolute URL, check if it's a relative URL or path\n return str.startsWith('/') || str.startsWith('./') || str.startsWith('../')\n }\n}\n\nconst isRawBase64 = (str: string): boolean => {\n // Skip if it's a valid URL or path\n if (isValidUrl(str)) {\n return false\n }\n\n // Check if it's a valid base64 string\n // Base64 images are typically at least a few hundred chars, but we'll be conservative\n return str.length > 20 && /^[A-Za-z0-9+/]+=*$/.test(str)\n}\n\nexport function redactBase64DataUrl(str: string): string\nexport function redactBase64DataUrl(str: unknown): unknown\nexport function redactBase64DataUrl(str: unknown): unknown {\n if (!isString(str)) return str\n\n // Check for data URL format\n if (isBase64DataUrl(str)) {\n return REDACTED_IMAGE_PLACEHOLDER\n }\n\n // Check for raw base64 (Vercel sends raw base64 for inline images)\n if (isRawBase64(str)) {\n return REDACTED_IMAGE_PLACEHOLDER\n }\n\n return str\n}\n\n// ============================================\n// Common Message Processing\n// ============================================\n\ntype ContentTransformer = (item: unknown) => unknown\n\nconst processMessages = (messages: unknown, transformContent: ContentTransformer): unknown => {\n if (!messages) return messages\n\n const processContent = (content: unknown): unknown => {\n if (typeof content === 'string') return content\n\n if (!content) return content\n\n if (Array.isArray(content)) {\n return content.map(transformContent)\n }\n\n // Handle single object content\n return transformContent(content)\n }\n\n const processMessage = (msg: unknown): unknown => {\n if (!isObject(msg) || !('content' in msg)) return msg\n return { ...msg, content: processContent(msg.content) }\n }\n\n // Handle both arrays and single messages\n if (Array.isArray(messages)) {\n return messages.map(processMessage)\n }\n\n return processMessage(messages)\n}\n\n// ============================================\n// Provider-Specific Image Sanitizers\n// ============================================\n\nconst sanitizeOpenAIImage = (item: unknown): unknown => {\n if (!isObject(item)) return item\n\n // Handle image_url format\n if (item.type === 'image_url' && 'image_url' in item && isObject(item.image_url) && 'url' in item.image_url) {\n return {\n ...item,\n image_url: {\n ...item.image_url,\n url: redactBase64DataUrl(item.image_url.url),\n },\n }\n }\n\n return item\n}\n\nconst sanitizeOpenAIResponseImage = (item: unknown): unknown => {\n if (!isObject(item)) return item\n\n // Handle input_image format\n if (item.type === 'input_image' && 'image_url' in item) {\n return {\n ...item,\n image_url: redactBase64DataUrl(item.image_url),\n }\n }\n\n return item\n}\n\nconst sanitizeAnthropicImage = (item: unknown): unknown => {\n if (!isObject(item)) return item\n\n // Handle Anthropic's image format\n if (\n item.type === 'image' &&\n 'source' in item &&\n isObject(item.source) &&\n item.source.type === 'base64' &&\n 'data' in item.source\n ) {\n return {\n ...item,\n source: {\n ...item.source,\n data: REDACTED_IMAGE_PLACEHOLDER,\n },\n }\n }\n\n return item\n}\n\nconst sanitizeGeminiPart = (part: unknown): unknown => {\n if (!isObject(part)) return part\n\n // Handle Gemini's inline data format\n if ('inlineData' in part && isObject(part.inlineData) && 'data' in part.inlineData) {\n return {\n ...part,\n inlineData: {\n ...part.inlineData,\n data: REDACTED_IMAGE_PLACEHOLDER,\n },\n }\n }\n\n return part\n}\n\nconst processGeminiItem = (item: unknown): unknown => {\n if (!isObject(item)) return item\n\n // If it has parts, process them\n if ('parts' in item && item.parts) {\n const parts = Array.isArray(item.parts) ? item.parts.map(sanitizeGeminiPart) : sanitizeGeminiPart(item.parts)\n\n return { ...item, parts }\n }\n\n return item\n}\n\nconst sanitizeLangChainImage = (item: unknown): unknown => {\n if (!isObject(item)) return item\n\n // OpenAI style\n if (item.type === 'image_url' && 'image_url' in item && isObject(item.image_url) && 'url' in item.image_url) {\n return {\n ...item,\n image_url: {\n ...item.image_url,\n url: redactBase64DataUrl(item.image_url.url),\n },\n }\n }\n\n // Direct image with data field\n if (item.type === 'image' && 'data' in item) {\n return { ...item, data: redactBase64DataUrl(item.data) }\n }\n\n // Anthropic style\n if (item.type === 'image' && 'source' in item && isObject(item.source) && 'data' in item.source) {\n return {\n ...item,\n source: {\n ...item.source,\n data: redactBase64DataUrl(item.source.data),\n },\n }\n }\n\n // Google style\n if (item.type === 'media' && 'data' in item) {\n return { ...item, data: redactBase64DataUrl(item.data) }\n }\n\n return item\n}\n\n// Export individual sanitizers for tree-shaking\nexport const sanitizeOpenAI = (data: unknown): unknown => {\n return processMessages(data, sanitizeOpenAIImage)\n}\n\nexport const sanitizeOpenAIResponse = (data: unknown): unknown => {\n return processMessages(data, sanitizeOpenAIResponseImage)\n}\n\nexport const sanitizeAnthropic = (data: unknown): unknown => {\n return processMessages(data, sanitizeAnthropicImage)\n}\n\nexport const sanitizeGemini = (data: unknown): unknown => {\n // Gemini has a different structure with 'parts' directly on items instead of 'content'\n // So we need custom processing instead of using processMessages\n if (!data) return data\n\n if (Array.isArray(data)) {\n return data.map(processGeminiItem)\n }\n\n return processGeminiItem(data)\n}\n\nexport const sanitizeLangChain = (data: unknown): unknown => {\n return processMessages(data, sanitizeLangChainImage)\n}\n","import AnthropicOriginal from '@anthropic-ai/sdk'\nimport { PostHog } from 'posthog-node'\nimport { v4 as uuidv4 } from 'uuid'\nimport {\n formatResponseAnthropic,\n mergeSystemPrompt,\n MonitoringParams,\n sendEventToPosthog,\n extractAvailableToolCalls,\n} from '../utils'\n\ntype MessageCreateParamsNonStreaming = AnthropicOriginal.Messages.MessageCreateParamsNonStreaming\ntype MessageCreateParamsStreaming = AnthropicOriginal.Messages.MessageCreateParamsStreaming\ntype MessageCreateParams = AnthropicOriginal.Messages.MessageCreateParams\ntype Message = AnthropicOriginal.Messages.Message\ntype RawMessageStreamEvent = AnthropicOriginal.Messages.RawMessageStreamEvent\ntype MessageCreateParamsBase = AnthropicOriginal.Messages.MessageCreateParams\n\nimport type { APIPromise, RequestOptions } from '@anthropic-ai/sdk/core'\nimport type { Stream } from '@anthropic-ai/sdk/streaming'\nimport { sanitizeAnthropic } from '../sanitization'\n\ninterface MonitoringAnthropicConfig {\n apiKey: string\n posthog: PostHog\n baseURL?: string\n}\n\nexport class PostHogAnthropic extends AnthropicOriginal {\n private readonly phClient: PostHog\n public messages: WrappedMessages\n\n constructor(config: MonitoringAnthropicConfig) {\n const { posthog, ...anthropicConfig } = config\n super(anthropicConfig)\n this.phClient = posthog\n this.messages = new WrappedMessages(this, this.phClient)\n }\n}\n\nexport class WrappedMessages extends AnthropicOriginal.Messages {\n private readonly phClient: PostHog\n\n constructor(parentClient: PostHogAnthropic, phClient: PostHog) {\n super(parentClient)\n this.phClient = phClient\n }\n\n public create(body: MessageCreateParamsNonStreaming, options?: RequestOptions): APIPromise<Message>\n public create(\n body: MessageCreateParamsStreaming & MonitoringParams,\n options?: RequestOptions\n ): APIPromise<Stream<RawMessageStreamEvent>>\n public create(\n body: MessageCreateParamsBase & MonitoringParams,\n options?: RequestOptions\n ): APIPromise<Stream<RawMessageStreamEvent> | Message>\n public create(\n body: MessageCreateParams & MonitoringParams,\n options?: RequestOptions\n ): APIPromise<Message> | APIPromise<Stream<RawMessageStreamEvent>> {\n const {\n posthogDistinctId,\n posthogTraceId,\n posthogProperties,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n posthogPrivacyMode = false,\n posthogGroups,\n posthogCaptureImmediate,\n ...anthropicParams\n } = body\n\n const traceId = posthogTraceId ?? uuidv4()\n const startTime = Date.now()\n\n const parentPromise = super.create(anthropicParams, options)\n\n if (anthropicParams.stream) {\n return parentPromise.then((value) => {\n let accumulatedContent = ''\n const usage: {\n inputTokens: number\n outputTokens: number\n cacheCreationInputTokens?: number\n cacheReadInputTokens?: number\n } = {\n inputTokens: 0,\n outputTokens: 0,\n cacheCreationInputTokens: 0,\n cacheReadInputTokens: 0,\n }\n if ('tee' in value) {\n const [stream1, stream2] = value.tee()\n ;(async () => {\n try {\n for await (const chunk of stream1) {\n if ('delta' in chunk) {\n if ('text' in chunk.delta) {\n const delta = chunk?.delta?.text ?? ''\n accumulatedContent += delta\n }\n }\n if (chunk.type == 'message_start') {\n usage.inputTokens = chunk.message.usage.input_tokens ?? 0\n usage.cacheCreationInputTokens = chunk.message.usage.cache_creation_input_tokens ?? 0\n usage.cacheReadInputTokens = chunk.message.usage.cache_read_input_tokens ?? 0\n }\n if ('usage' in chunk) {\n usage.outputTokens = chunk.usage.output_tokens ?? 0\n }\n }\n\n const latency = (Date.now() - startTime) / 1000\n\n const availableTools = extractAvailableToolCalls('anthropic', anthropicParams)\n\n await sendEventToPosthog({\n client: this.phClient,\n distinctId: posthogDistinctId,\n traceId,\n model: anthropicParams.model,\n provider: 'anthropic',\n input: sanitizeAnthropic(mergeSystemPrompt(anthropicParams, 'anthropic')),\n output: [{ content: accumulatedContent, role: 'assistant' }],\n latency,\n baseURL: (this as any).baseURL ?? '',\n params: body,\n httpStatus: 200,\n usage,\n tools: availableTools,\n captureImmediate: posthogCaptureImmediate,\n })\n } catch (error: any) {\n // error handling\n await sendEventToPosthog({\n client: this.phClient,\n distinctId: posthogDistinctId,\n traceId,\n model: anthropicParams.model,\n provider: 'anthropic',\n input: sanitizeAnthropic(mergeSystemPrompt(anthropicParams, 'anthropic')),\n output: [],\n latency: 0,\n baseURL: (this as any).baseURL ?? '',\n params: body,\n httpStatus: error?.status ? error.status : 500,\n usage: {\n inputTokens: 0,\n outputTokens: 0,\n },\n isError: true,\n error: JSON.stringify(error),\n captureImmediate: posthogCaptureImmediate,\n })\n }\n })()\n\n // Return the other stream to the user\n return stream2\n }\n return value\n }) as APIPromise<Stream<RawMessageStreamEvent>>\n } else {\n const wrappedPromise = parentPromise.then(\n async (result) => {\n if ('content' in result) {\n const latency = (Date.now() - startTime) / 1000\n\n const availableTools = extractAvailableToolCalls('anthropic', anthropicParams)\n\n await sendEventToPosthog({\n client: this.phClient,\n distinctId: posthogDistinctId,\n traceId,\n model: anthropicParams.model,\n provider: 'anthropic',\n input: sanitizeAnthropic(mergeSystemPrompt(anthropicParams, 'anthropic')),\n output: formatResponseAnthropic(result),\n latency,\n baseURL: (this as any).baseURL ?? '',\n params: body,\n httpStatus: 200,\n usage: {\n inputTokens: result.usage.input_tokens ?? 0,\n outputTokens: result.usage.output_tokens ?? 0,\n cacheCreationInputTokens: result.usage.cache_creation_input_tokens ?? 0,\n cacheReadInputTokens: result.usage.cache_read_input_tokens ?? 0,\n },\n tools: availableTools,\n captureImmediate: posthogCaptureImmediate,\n })\n }\n return result\n },\n async (error: any) => {\n await sendEventToPosthog({\n client: this.phClient,\n distinctId: posthogDistinctId,\n traceId,\n model: anthropicParams.model,\n provider: 'anthropic',\n input: sanitizeAnthropic(mergeSystemPrompt(anthropicParams, 'anthropic')),\n output: [],\n latency: 0,\n baseURL: (this as any).baseURL ?? '',\n params: body,\n httpStatus: error?.status ? error.status : 500,\n usage: {\n inputTokens: 0,\n outputTokens: 0,\n },\n isError: true,\n error: JSON.stringify(error),\n captureImmediate: posthogCaptureImmediate,\n })\n throw error\n }\n ) as APIPromise<Message>\n\n return wrappedPromise\n }\n }\n}\n\nexport default PostHogAnthropic\n\nexport { PostHogAnthropic as Anthropic }\n"],"names":["STRING_FORMAT","getModelParams","params","modelParams","paramKeys","key","undefined","formatResponseAnthropic","response","output","content","choice","type","text","push","name","id","function","arguments","input","length","role","mergeSystemPrompt","provider","messages","system","systemMessage","withPrivacyMode","client","privacyMode","privacy_mode","extractAvailableToolCalls","tools","sanitizeValues","obj","jsonSafe","JSON","parse","stringify","Buffer","from","toString","Array","isArray","map","Object","fromEntries","entries","k","v","sendEventToPosthog","distinctId","traceId","model","latency","baseURL","httpStatus","usage","isError","error","captureImmediate","capture","Promise","resolve","safeInput","safeOutput","safeError","errorData","$ai_is_error","$ai_error","costOverrideData","posthogCostOverride","inputCostUSD","inputCost","inputTokens","outputCostUSD","outputCost","outputTokens","$ai_input_cost_usd","$ai_output_cost_usd","$ai_total_cost_usd","additionalTokenValues","reasoningTokens","$ai_reasoning_tokens","cacheReadInputTokens","$ai_cache_read_input_tokens","cacheCreationInputTokens","$ai_cache_creation_input_tokens","properties","$ai_provider","posthogProviderOverride","$ai_model","posthogModelOverride","$ai_model_parameters","$ai_input","posthogPrivacyMode","$ai_output_choices","$ai_http_status","$ai_input_tokens","$ai_output_tokens","$ai_latency","$ai_trace_id","$ai_base_url","posthogProperties","$process_person_profile","$ai_tools","event","groups","posthogGroups","isObject","value","REDACTED_IMAGE_PLACEHOLDER","processMessages","transformContent","processContent","processMessage","msg","sanitizeAnthropicImage","item","source","data","sanitizeAnthropic","PostHogAnthropic","AnthropicOriginal","constructor","config","posthog","anthropicConfig","phClient","WrappedMessages","Messages","parentClient","create","body","options","posthogDistinctId","posthogTraceId","posthogCaptureImmediate","anthropicParams","uuidv4","startTime","Date","now","parentPromise","stream","then","accumulatedContent","stream1","stream2","tee","chunk","delta","message","input_tokens","cache_creation_input_tokens","cache_read_input_tokens","output_tokens","availableTools","status","wrappedPromise","result"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../../src/utils.ts","../../src/typeGuards.ts","../../src/sanitization.ts","../../src/anthropic/index.ts"],"sourcesContent":["import { PostHog } from 'posthog-node'\nimport { Buffer } from 'buffer'\nimport OpenAIOrignal from 'openai'\nimport AnthropicOriginal from '@anthropic-ai/sdk'\nimport type { ChatCompletionTool } from 'openai/resources/chat/completions'\nimport type { Tool as GeminiTool } from '@google/genai'\nimport type { FormattedMessage, FormattedContent, TokenUsage } from './types'\n\ntype ChatCompletionCreateParamsBase = OpenAIOrignal.Chat.Completions.ChatCompletionCreateParams\ntype MessageCreateParams = AnthropicOriginal.Messages.MessageCreateParams\ntype ResponseCreateParams = OpenAIOrignal.Responses.ResponseCreateParams\ntype AnthropicTool = AnthropicOriginal.Tool\n\n// limit large outputs by truncating to 200kb (approx 200k bytes)\nexport const MAX_OUTPUT_SIZE = 200000\nconst STRING_FORMAT = 'utf8'\n\nexport interface MonitoringParams {\n posthogDistinctId?: string\n posthogTraceId?: string\n posthogProperties?: Record<string, any>\n posthogPrivacyMode?: boolean\n posthogGroups?: Record<string, any>\n posthogModelOverride?: string\n posthogProviderOverride?: string\n posthogCostOverride?: CostOverride\n posthogCaptureImmediate?: boolean\n}\n\nexport interface CostOverride {\n inputCost: number\n outputCost: number\n}\n\nexport const getModelParams = (\n params: ((ChatCompletionCreateParamsBase | MessageCreateParams | ResponseCreateParams) & MonitoringParams) | null\n): Record<string, any> => {\n if (!params) {\n return {}\n }\n const modelParams: Record<string, any> = {}\n const paramKeys = [\n 'temperature',\n 'max_tokens',\n 'max_completion_tokens',\n 'top_p',\n 'frequency_penalty',\n 'presence_penalty',\n 'n',\n 'stop',\n 'stream',\n 'streaming',\n ] as const\n\n for (const key of paramKeys) {\n if (key in params && (params as any)[key] !== undefined) {\n modelParams[key] = (params as any)[key]\n }\n }\n return modelParams\n}\n\n/**\n * Helper to format responses (non-streaming) for consumption, mirroring Python's openai vs. anthropic approach.\n */\nexport const formatResponse = (response: any, provider: string): FormattedMessage[] => {\n if (!response) {\n return []\n }\n if (provider === 'anthropic') {\n return formatResponseAnthropic(response)\n } else if (provider === 'openai') {\n return formatResponseOpenAI(response)\n } else if (provider === 'gemini') {\n return formatResponseGemini(response)\n }\n return []\n}\n\nexport const formatResponseAnthropic = (response: any): FormattedMessage[] => {\n const output: FormattedMessage[] = []\n const content: FormattedContent = []\n\n for (const choice of response.content ?? []) {\n if (choice?.type === 'text' && choice?.text) {\n content.push({ type: 'text', text: choice.text })\n } else if (choice?.type === 'tool_use' && choice?.name && choice?.id) {\n content.push({\n type: 'function',\n id: choice.id,\n function: {\n name: choice.name,\n arguments: choice.input || {},\n },\n })\n }\n }\n\n if (content.length > 0) {\n output.push({\n role: 'assistant',\n content,\n })\n }\n\n return output\n}\n\nexport const formatResponseOpenAI = (response: any): FormattedMessage[] => {\n const output: FormattedMessage[] = []\n\n if (response.choices) {\n for (const choice of response.choices) {\n const content: FormattedContent = []\n let role = 'assistant'\n\n if (choice.message) {\n if (choice.message.role) {\n role = choice.message.role\n }\n\n if (choice.message.content) {\n content.push({ type: 'text', text: choice.message.content })\n }\n\n if (choice.message.tool_calls) {\n for (const toolCall of choice.message.tool_calls) {\n content.push({\n type: 'function',\n id: toolCall.id,\n function: {\n name: toolCall.function.name,\n arguments: toolCall.function.arguments,\n },\n })\n }\n }\n }\n\n if (content.length > 0) {\n output.push({\n role,\n content,\n })\n }\n }\n }\n\n // Handle Responses API format\n if (response.output) {\n const content: FormattedContent = []\n let role = 'assistant'\n\n for (const item of response.output) {\n if (item.type === 'message') {\n role = item.role\n\n if (item.content && Array.isArray(item.content)) {\n for (const contentItem of item.content) {\n if (contentItem.type === 'output_text' && contentItem.text) {\n content.push({ type: 'text', text: contentItem.text })\n } else if (contentItem.text) {\n content.push({ type: 'text', text: contentItem.text })\n } else if (contentItem.type === 'input_image' && contentItem.image_url) {\n content.push({\n type: 'image',\n image: contentItem.image_url,\n })\n }\n }\n } else if (item.content) {\n content.push({ type: 'text', text: String(item.content) })\n }\n } else if (item.type === 'function_call') {\n content.push({\n type: 'function',\n id: item.call_id || item.id || '',\n function: {\n name: item.name,\n arguments: item.arguments || {},\n },\n })\n }\n }\n\n if (content.length > 0) {\n output.push({\n role,\n content,\n })\n }\n }\n\n return output\n}\n\nexport const formatResponseGemini = (response: any): FormattedMessage[] => {\n const output: FormattedMessage[] = []\n\n if (response.candidates && Array.isArray(response.candidates)) {\n for (const candidate of response.candidates) {\n if (candidate.content && candidate.content.parts) {\n const content: FormattedContent = []\n\n for (const part of candidate.content.parts) {\n if (part.text) {\n content.push({ type: 'text', text: part.text })\n } else if (part.functionCall) {\n content.push({\n type: 'function',\n function: {\n name: part.functionCall.name,\n arguments: part.functionCall.args,\n },\n })\n }\n }\n\n if (content.length > 0) {\n output.push({\n role: 'assistant',\n content,\n })\n }\n } else if (candidate.text) {\n output.push({\n role: 'assistant',\n content: [{ type: 'text', text: candidate.text }],\n })\n }\n }\n } else if (response.text) {\n output.push({\n role: 'assistant',\n content: [{ type: 'text', text: response.text }],\n })\n }\n\n return output\n}\n\nexport const mergeSystemPrompt = (params: MessageCreateParams & MonitoringParams, provider: string): any => {\n if (provider == 'anthropic') {\n const messages = params.messages || []\n if (!(params as any).system) {\n return messages\n }\n const systemMessage = (params as any).system\n return [{ role: 'system', content: systemMessage }, ...messages]\n }\n return params.messages\n}\n\nexport const withPrivacyMode = (client: PostHog, privacyMode: boolean, input: any): any => {\n return (client as any).privacy_mode || privacyMode ? null : input\n}\n\nexport const truncate = (str: string): string => {\n try {\n const buffer = Buffer.from(str, STRING_FORMAT)\n if (buffer.length <= MAX_OUTPUT_SIZE) {\n return str\n }\n const truncatedBuffer = buffer.slice(0, MAX_OUTPUT_SIZE)\n return `${truncatedBuffer.toString(STRING_FORMAT)}... [truncated]`\n } catch (error) {\n console.error('Error truncating, likely not a string')\n return str\n }\n}\n\n/**\n * Extract available tool calls from the request parameters.\n * These are the tools provided to the LLM, not the tool calls in the response.\n */\nexport const extractAvailableToolCalls = (\n provider: string,\n params: any\n): ChatCompletionTool[] | AnthropicTool[] | GeminiTool[] | null => {\n if (provider === 'anthropic') {\n if (params.tools) {\n return params.tools\n }\n\n return null\n } else if (provider === 'gemini') {\n if (params.config && params.config.tools) {\n return params.config.tools\n }\n\n return null\n } else if (provider === 'openai') {\n if (params.tools) {\n return params.tools\n }\n\n return null\n } else if (provider === 'vercel') {\n if (params.tools) {\n return params.tools\n }\n\n return null\n }\n\n return null\n}\n\nexport type SendEventToPosthogParams = {\n client: PostHog\n distinctId?: string\n traceId: string\n model: string\n provider: string\n input: any\n output: any\n latency: number\n baseURL: string\n httpStatus: number\n usage?: TokenUsage\n params: (ChatCompletionCreateParamsBase | MessageCreateParams | ResponseCreateParams) & MonitoringParams\n isError?: boolean\n error?: string\n tools?: ChatCompletionTool[] | AnthropicTool[] | GeminiTool[] | null\n captureImmediate?: boolean\n}\n\nfunction sanitizeValues(obj: any): any {\n if (obj === undefined || obj === null) {\n return obj\n }\n const jsonSafe = JSON.parse(JSON.stringify(obj))\n if (typeof jsonSafe === 'string') {\n return Buffer.from(jsonSafe, STRING_FORMAT).toString(STRING_FORMAT)\n } else if (Array.isArray(jsonSafe)) {\n return jsonSafe.map(sanitizeValues)\n } else if (jsonSafe && typeof jsonSafe === 'object') {\n return Object.fromEntries(Object.entries(jsonSafe).map(([k, v]) => [k, sanitizeValues(v)]))\n }\n return jsonSafe\n}\n\nexport const sendEventToPosthog = async ({\n client,\n distinctId,\n traceId,\n model,\n provider,\n input,\n output,\n latency,\n baseURL,\n params,\n httpStatus = 200,\n usage = {},\n isError = false,\n error,\n tools,\n captureImmediate = false,\n}: SendEventToPosthogParams): Promise<void> => {\n if (!client.capture) {\n return Promise.resolve()\n }\n // sanitize input and output for UTF-8 validity\n const safeInput = sanitizeValues(input)\n const safeOutput = sanitizeValues(output)\n const safeError = sanitizeValues(error)\n\n let errorData = {}\n if (isError) {\n errorData = {\n $ai_is_error: true,\n $ai_error: safeError,\n }\n }\n let costOverrideData = {}\n if (params.posthogCostOverride) {\n const inputCostUSD = (params.posthogCostOverride.inputCost ?? 0) * (usage.inputTokens ?? 0)\n const outputCostUSD = (params.posthogCostOverride.outputCost ?? 0) * (usage.outputTokens ?? 0)\n costOverrideData = {\n $ai_input_cost_usd: inputCostUSD,\n $ai_output_cost_usd: outputCostUSD,\n $ai_total_cost_usd: inputCostUSD + outputCostUSD,\n }\n }\n\n const additionalTokenValues = {\n ...(usage.reasoningTokens ? { $ai_reasoning_tokens: usage.reasoningTokens } : {}),\n ...(usage.cacheReadInputTokens ? { $ai_cache_read_input_tokens: usage.cacheReadInputTokens } : {}),\n ...(usage.cacheCreationInputTokens ? { $ai_cache_creation_input_tokens: usage.cacheCreationInputTokens } : {}),\n }\n\n const properties = {\n $ai_provider: params.posthogProviderOverride ?? provider,\n $ai_model: params.posthogModelOverride ?? model,\n $ai_model_parameters: getModelParams(params),\n $ai_input: withPrivacyMode(client, params.posthogPrivacyMode ?? false, safeInput),\n $ai_output_choices: withPrivacyMode(client, params.posthogPrivacyMode ?? false, safeOutput),\n $ai_http_status: httpStatus,\n $ai_input_tokens: usage.inputTokens ?? 0,\n $ai_output_tokens: usage.outputTokens ?? 0,\n ...additionalTokenValues,\n $ai_latency: latency,\n $ai_trace_id: traceId,\n $ai_base_url: baseURL,\n ...params.posthogProperties,\n ...(distinctId ? {} : { $process_person_profile: false }),\n ...(tools ? { $ai_tools: tools } : {}),\n ...errorData,\n ...costOverrideData,\n }\n\n const event = {\n distinctId: distinctId ?? traceId,\n event: '$ai_generation',\n properties,\n groups: params.posthogGroups,\n }\n\n if (captureImmediate) {\n // await capture promise to send single event in serverless environments\n await client.captureImmediate(event)\n } else {\n client.capture(event)\n }\n}\n","// Type guards for safer type checking\n\nexport const isString = (value: unknown): value is string => {\n return typeof value === 'string'\n}\n\nexport const isObject = (value: unknown): value is Record<string, unknown> => {\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n}\n","import { isString, isObject } from './typeGuards'\n\nconst REDACTED_IMAGE_PLACEHOLDER = '[base64 image redacted]'\n\n// ============================================\n// Base64 Detection Helpers\n// ============================================\n\nconst isBase64DataUrl = (str: string): boolean => {\n return /^data:([^;]+);base64,/.test(str)\n}\n\nconst isValidUrl = (str: string): boolean => {\n try {\n new URL(str)\n return true\n } catch {\n // Not an absolute URL, check if it's a relative URL or path\n return str.startsWith('/') || str.startsWith('./') || str.startsWith('../')\n }\n}\n\nconst isRawBase64 = (str: string): boolean => {\n // Skip if it's a valid URL or path\n if (isValidUrl(str)) {\n return false\n }\n\n // Check if it's a valid base64 string\n // Base64 images are typically at least a few hundred chars, but we'll be conservative\n return str.length > 20 && /^[A-Za-z0-9+/]+=*$/.test(str)\n}\n\nexport function redactBase64DataUrl(str: string): string\nexport function redactBase64DataUrl(str: unknown): unknown\nexport function redactBase64DataUrl(str: unknown): unknown {\n if (!isString(str)) return str\n\n // Check for data URL format\n if (isBase64DataUrl(str)) {\n return REDACTED_IMAGE_PLACEHOLDER\n }\n\n // Check for raw base64 (Vercel sends raw base64 for inline images)\n if (isRawBase64(str)) {\n return REDACTED_IMAGE_PLACEHOLDER\n }\n\n return str\n}\n\n// ============================================\n// Common Message Processing\n// ============================================\n\ntype ContentTransformer = (item: unknown) => unknown\n\nconst processMessages = (messages: unknown, transformContent: ContentTransformer): unknown => {\n if (!messages) return messages\n\n const processContent = (content: unknown): unknown => {\n if (typeof content === 'string') return content\n\n if (!content) return content\n\n if (Array.isArray(content)) {\n return content.map(transformContent)\n }\n\n // Handle single object content\n return transformContent(content)\n }\n\n const processMessage = (msg: unknown): unknown => {\n if (!isObject(msg) || !('content' in msg)) return msg\n return { ...msg, content: processContent(msg.content) }\n }\n\n // Handle both arrays and single messages\n if (Array.isArray(messages)) {\n return messages.map(processMessage)\n }\n\n return processMessage(messages)\n}\n\n// ============================================\n// Provider-Specific Image Sanitizers\n// ============================================\n\nconst sanitizeOpenAIImage = (item: unknown): unknown => {\n if (!isObject(item)) return item\n\n // Handle image_url format\n if (item.type === 'image_url' && 'image_url' in item && isObject(item.image_url) && 'url' in item.image_url) {\n return {\n ...item,\n image_url: {\n ...item.image_url,\n url: redactBase64DataUrl(item.image_url.url),\n },\n }\n }\n\n return item\n}\n\nconst sanitizeOpenAIResponseImage = (item: unknown): unknown => {\n if (!isObject(item)) return item\n\n // Handle input_image format\n if (item.type === 'input_image' && 'image_url' in item) {\n return {\n ...item,\n image_url: redactBase64DataUrl(item.image_url),\n }\n }\n\n return item\n}\n\nconst sanitizeAnthropicImage = (item: unknown): unknown => {\n if (!isObject(item)) return item\n\n // Handle Anthropic's image format\n if (\n item.type === 'image' &&\n 'source' in item &&\n isObject(item.source) &&\n item.source.type === 'base64' &&\n 'data' in item.source\n ) {\n return {\n ...item,\n source: {\n ...item.source,\n data: REDACTED_IMAGE_PLACEHOLDER,\n },\n }\n }\n\n return item\n}\n\nconst sanitizeGeminiPart = (part: unknown): unknown => {\n if (!isObject(part)) return part\n\n // Handle Gemini's inline data format\n if ('inlineData' in part && isObject(part.inlineData) && 'data' in part.inlineData) {\n return {\n ...part,\n inlineData: {\n ...part.inlineData,\n data: REDACTED_IMAGE_PLACEHOLDER,\n },\n }\n }\n\n return part\n}\n\nconst processGeminiItem = (item: unknown): unknown => {\n if (!isObject(item)) return item\n\n // If it has parts, process them\n if ('parts' in item && item.parts) {\n const parts = Array.isArray(item.parts) ? item.parts.map(sanitizeGeminiPart) : sanitizeGeminiPart(item.parts)\n\n return { ...item, parts }\n }\n\n return item\n}\n\nconst sanitizeLangChainImage = (item: unknown): unknown => {\n if (!isObject(item)) return item\n\n // OpenAI style\n if (item.type === 'image_url' && 'image_url' in item && isObject(item.image_url) && 'url' in item.image_url) {\n return {\n ...item,\n image_url: {\n ...item.image_url,\n url: redactBase64DataUrl(item.image_url.url),\n },\n }\n }\n\n // Direct image with data field\n if (item.type === 'image' && 'data' in item) {\n return { ...item, data: redactBase64DataUrl(item.data) }\n }\n\n // Anthropic style\n if (item.type === 'image' && 'source' in item && isObject(item.source) && 'data' in item.source) {\n return {\n ...item,\n source: {\n ...item.source,\n data: redactBase64DataUrl(item.source.data),\n },\n }\n }\n\n // Google style\n if (item.type === 'media' && 'data' in item) {\n return { ...item, data: redactBase64DataUrl(item.data) }\n }\n\n return item\n}\n\n// Export individual sanitizers for tree-shaking\nexport const sanitizeOpenAI = (data: unknown): unknown => {\n return processMessages(data, sanitizeOpenAIImage)\n}\n\nexport const sanitizeOpenAIResponse = (data: unknown): unknown => {\n return processMessages(data, sanitizeOpenAIResponseImage)\n}\n\nexport const sanitizeAnthropic = (data: unknown): unknown => {\n return processMessages(data, sanitizeAnthropicImage)\n}\n\nexport const sanitizeGemini = (data: unknown): unknown => {\n // Gemini has a different structure with 'parts' directly on items instead of 'content'\n // So we need custom processing instead of using processMessages\n if (!data) return data\n\n if (Array.isArray(data)) {\n return data.map(processGeminiItem)\n }\n\n return processGeminiItem(data)\n}\n\nexport const sanitizeLangChain = (data: unknown): unknown => {\n return processMessages(data, sanitizeLangChainImage)\n}\n","import AnthropicOriginal from '@anthropic-ai/sdk'\nimport { PostHog } from 'posthog-node'\nimport { v4 as uuidv4 } from 'uuid'\nimport {\n formatResponseAnthropic,\n mergeSystemPrompt,\n MonitoringParams,\n sendEventToPosthog,\n extractAvailableToolCalls,\n} from '../utils'\nimport type { FormattedContentItem, FormattedTextContent, FormattedFunctionCall, FormattedMessage } from '../types'\n\ntype MessageCreateParamsNonStreaming = AnthropicOriginal.Messages.MessageCreateParamsNonStreaming\ntype MessageCreateParamsStreaming = AnthropicOriginal.Messages.MessageCreateParamsStreaming\ntype MessageCreateParams = AnthropicOriginal.Messages.MessageCreateParams\ntype Message = AnthropicOriginal.Messages.Message\ntype RawMessageStreamEvent = AnthropicOriginal.Messages.RawMessageStreamEvent\ntype MessageCreateParamsBase = AnthropicOriginal.Messages.MessageCreateParams\n\nimport type { APIPromise, RequestOptions } from '@anthropic-ai/sdk/core'\nimport type { Stream } from '@anthropic-ai/sdk/streaming'\nimport { sanitizeAnthropic } from '../sanitization'\n\ninterface ToolInProgress {\n block: FormattedFunctionCall\n inputString: string\n}\n\ninterface MonitoringAnthropicConfig {\n apiKey: string\n posthog: PostHog\n baseURL?: string\n}\n\nexport class PostHogAnthropic extends AnthropicOriginal {\n private readonly phClient: PostHog\n public messages: WrappedMessages\n\n constructor(config: MonitoringAnthropicConfig) {\n const { posthog, ...anthropicConfig } = config\n super(anthropicConfig)\n this.phClient = posthog\n this.messages = new WrappedMessages(this, this.phClient)\n }\n}\n\nexport class WrappedMessages extends AnthropicOriginal.Messages {\n private readonly phClient: PostHog\n\n constructor(parentClient: PostHogAnthropic, phClient: PostHog) {\n super(parentClient)\n this.phClient = phClient\n }\n\n public create(body: MessageCreateParamsNonStreaming, options?: RequestOptions): APIPromise<Message>\n public create(\n body: MessageCreateParamsStreaming & MonitoringParams,\n options?: RequestOptions\n ): APIPromise<Stream<RawMessageStreamEvent>>\n public create(\n body: MessageCreateParamsBase & MonitoringParams,\n options?: RequestOptions\n ): APIPromise<Stream<RawMessageStreamEvent> | Message>\n public create(\n body: MessageCreateParams & MonitoringParams,\n options?: RequestOptions\n ): APIPromise<Message> | APIPromise<Stream<RawMessageStreamEvent>> {\n const {\n posthogDistinctId,\n posthogTraceId,\n posthogProperties,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n posthogPrivacyMode = false,\n posthogGroups,\n posthogCaptureImmediate,\n ...anthropicParams\n } = body\n\n const traceId = posthogTraceId ?? uuidv4()\n const startTime = Date.now()\n\n const parentPromise = super.create(anthropicParams, options)\n\n if (anthropicParams.stream) {\n return parentPromise.then((value) => {\n let accumulatedContent = ''\n const contentBlocks: FormattedContentItem[] = []\n const toolsInProgress: Map<string, ToolInProgress> = new Map()\n let currentTextBlock: FormattedTextContent | null = null\n\n const usage: {\n inputTokens: number\n outputTokens: number\n cacheCreationInputTokens?: number\n cacheReadInputTokens?: number\n } = {\n inputTokens: 0,\n outputTokens: 0,\n cacheCreationInputTokens: 0,\n cacheReadInputTokens: 0,\n }\n if ('tee' in value) {\n const [stream1, stream2] = value.tee()\n ;(async () => {\n try {\n for await (const chunk of stream1) {\n // Handle content block start events\n if (chunk.type === 'content_block_start') {\n if (chunk.content_block?.type === 'text') {\n currentTextBlock = {\n type: 'text',\n text: '',\n }\n\n contentBlocks.push(currentTextBlock)\n } else if (chunk.content_block?.type === 'tool_use') {\n const toolBlock: FormattedFunctionCall = {\n type: 'function',\n id: chunk.content_block.id,\n function: {\n name: chunk.content_block.name,\n arguments: {},\n },\n }\n\n contentBlocks.push(toolBlock)\n\n toolsInProgress.set(chunk.content_block.id, {\n block: toolBlock,\n inputString: '',\n })\n\n currentTextBlock = null\n }\n }\n\n // Handle text delta events\n if ('delta' in chunk) {\n if ('text' in chunk.delta) {\n const delta = chunk?.delta?.text ?? ''\n\n accumulatedContent += delta\n\n if (currentTextBlock) {\n currentTextBlock.text += delta\n }\n }\n }\n\n // Handle tool input delta events\n if (chunk.type === 'content_block_delta' && chunk.delta?.type === 'input_json_delta') {\n const block = chunk.index !== undefined ? contentBlocks[chunk.index] : undefined\n const toolId = block?.type === 'function' ? block.id : undefined\n\n if (toolId && toolsInProgress.has(toolId)) {\n const tool = toolsInProgress.get(toolId)\n if (tool) {\n tool.inputString += chunk.delta.partial_json || ''\n }\n }\n }\n\n // Handle content block stop events\n if (chunk.type === 'content_block_stop') {\n currentTextBlock = null\n\n // Parse accumulated tool input\n if (chunk.index !== undefined) {\n const block = contentBlocks[chunk.index]\n\n if (block?.type === 'function' && block.id && toolsInProgress.has(block.id)) {\n const tool = toolsInProgress.get(block.id)\n if (tool) {\n try {\n block.function.arguments = JSON.parse(tool.inputString)\n } catch (e) {\n // Keep empty object if parsing fails\n console.error('Error parsing tool input:', e)\n }\n }\n toolsInProgress.delete(block.id)\n }\n }\n }\n\n if (chunk.type == 'message_start') {\n usage.inputTokens = chunk.message.usage.input_tokens ?? 0\n usage.cacheCreationInputTokens = chunk.message.usage.cache_creation_input_tokens ?? 0\n usage.cacheReadInputTokens = chunk.message.usage.cache_read_input_tokens ?? 0\n }\n if ('usage' in chunk) {\n usage.outputTokens = chunk.usage.output_tokens ?? 0\n }\n }\n\n const latency = (Date.now() - startTime) / 1000\n\n const availableTools = extractAvailableToolCalls('anthropic', anthropicParams)\n\n // Format output to match non-streaming version\n const formattedOutput: FormattedMessage[] =\n contentBlocks.length > 0\n ? [\n {\n role: 'assistant',\n content: contentBlocks,\n },\n ]\n : [\n {\n role: 'assistant',\n content: [{ type: 'text', text: accumulatedContent }],\n },\n ]\n\n await sendEventToPosthog({\n client: this.phClient,\n distinctId: posthogDistinctId,\n traceId,\n model: anthropicParams.model,\n provider: 'anthropic',\n input: sanitizeAnthropic(mergeSystemPrompt(anthropicParams, 'anthropic')),\n output: formattedOutput,\n latency,\n baseURL: (this as any).baseURL ?? '',\n params: body,\n httpStatus: 200,\n usage,\n tools: availableTools,\n captureImmediate: posthogCaptureImmediate,\n })\n } catch (error: any) {\n // error handling\n await sendEventToPosthog({\n client: this.phClient,\n distinctId: posthogDistinctId,\n traceId,\n model: anthropicParams.model,\n provider: 'anthropic',\n input: sanitizeAnthropic(mergeSystemPrompt(anthropicParams, 'anthropic')),\n output: [],\n latency: 0,\n baseURL: (this as any).baseURL ?? '',\n params: body,\n httpStatus: error?.status ? error.status : 500,\n usage: {\n inputTokens: 0,\n outputTokens: 0,\n },\n isError: true,\n error: JSON.stringify(error),\n captureImmediate: posthogCaptureImmediate,\n })\n }\n })()\n\n // Return the other stream to the user\n return stream2\n }\n return value\n }) as APIPromise<Stream<RawMessageStreamEvent>>\n } else {\n const wrappedPromise = parentPromise.then(\n async (result) => {\n if ('content' in result) {\n const latency = (Date.now() - startTime) / 1000\n\n const availableTools = extractAvailableToolCalls('anthropic', anthropicParams)\n\n await sendEventToPosthog({\n client: this.phClient,\n distinctId: posthogDistinctId,\n traceId,\n model: anthropicParams.model,\n provider: 'anthropic',\n input: sanitizeAnthropic(mergeSystemPrompt(anthropicParams, 'anthropic')),\n output: formatResponseAnthropic(result),\n latency,\n baseURL: (this as any).baseURL ?? '',\n params: body,\n httpStatus: 200,\n usage: {\n inputTokens: result.usage.input_tokens ?? 0,\n outputTokens: result.usage.output_tokens ?? 0,\n cacheCreationInputTokens: result.usage.cache_creation_input_tokens ?? 0,\n cacheReadInputTokens: result.usage.cache_read_input_tokens ?? 0,\n },\n tools: availableTools,\n captureImmediate: posthogCaptureImmediate,\n })\n }\n return result\n },\n async (error: any) => {\n await sendEventToPosthog({\n client: this.phClient,\n distinctId: posthogDistinctId,\n traceId,\n model: anthropicParams.model,\n provider: 'anthropic',\n input: sanitizeAnthropic(mergeSystemPrompt(anthropicParams, 'anthropic')),\n output: [],\n latency: 0,\n baseURL: (this as any).baseURL ?? '',\n params: body,\n httpStatus: error?.status ? error.status : 500,\n usage: {\n inputTokens: 0,\n outputTokens: 0,\n },\n isError: true,\n error: JSON.stringify(error),\n captureImmediate: posthogCaptureImmediate,\n })\n throw error\n }\n ) as APIPromise<Message>\n\n return wrappedPromise\n }\n }\n}\n\nexport default PostHogAnthropic\n\nexport { PostHogAnthropic as Anthropic }\n"],"names":["STRING_FORMAT","getModelParams","params","modelParams","paramKeys","key","undefined","formatResponseAnthropic","response","output","content","choice","type","text","push","name","id","function","arguments","input","length","role","mergeSystemPrompt","provider","messages","system","systemMessage","withPrivacyMode","client","privacyMode","privacy_mode","extractAvailableToolCalls","tools","sanitizeValues","obj","jsonSafe","JSON","parse","stringify","Buffer","from","toString","Array","isArray","map","Object","fromEntries","entries","k","v","sendEventToPosthog","distinctId","traceId","model","latency","baseURL","httpStatus","usage","isError","error","captureImmediate","capture","Promise","resolve","safeInput","safeOutput","safeError","errorData","$ai_is_error","$ai_error","costOverrideData","posthogCostOverride","inputCostUSD","inputCost","inputTokens","outputCostUSD","outputCost","outputTokens","$ai_input_cost_usd","$ai_output_cost_usd","$ai_total_cost_usd","additionalTokenValues","reasoningTokens","$ai_reasoning_tokens","cacheReadInputTokens","$ai_cache_read_input_tokens","cacheCreationInputTokens","$ai_cache_creation_input_tokens","properties","$ai_provider","posthogProviderOverride","$ai_model","posthogModelOverride","$ai_model_parameters","$ai_input","posthogPrivacyMode","$ai_output_choices","$ai_http_status","$ai_input_tokens","$ai_output_tokens","$ai_latency","$ai_trace_id","$ai_base_url","posthogProperties","$process_person_profile","$ai_tools","event","groups","posthogGroups","isObject","value","REDACTED_IMAGE_PLACEHOLDER","processMessages","transformContent","processContent","processMessage","msg","sanitizeAnthropicImage","item","source","data","sanitizeAnthropic","PostHogAnthropic","AnthropicOriginal","constructor","config","posthog","anthropicConfig","phClient","WrappedMessages","Messages","parentClient","create","body","options","posthogDistinctId","posthogTraceId","posthogCaptureImmediate","anthropicParams","uuidv4","startTime","Date","now","parentPromise","stream","then","accumulatedContent","contentBlocks","toolsInProgress","Map","currentTextBlock","stream1","stream2","tee","chunk","content_block","toolBlock","set","block","inputString","delta","index","toolId","has","tool","get","partial_json","e","console","delete","message","input_tokens","cache_creation_input_tokens","cache_read_input_tokens","output_tokens","availableTools","formattedOutput","status","wrappedPromise","result"],"mappings":"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"}
@@ -234,8 +234,6 @@ const sanitizeGemini = data => {
234
234
  return processGeminiItem(data);
235
235
  };
236
236
 
237
- // Types from @google/genai
238
-
239
237
  class PostHogGoogleGenAI {
240
238
  constructor(config) {
241
239
  const {
@@ -267,6 +265,7 @@ class WrappedModels {
267
265
  const response = await this.client.models.generateContent(geminiParams);
268
266
  const latency = (Date.now() - startTime) / 1000;
269
267
  const availableTools = extractAvailableToolCalls('gemini', geminiParams);
268
+ const metadata = response.usageMetadata;
270
269
  await sendEventToPosthog({
271
270
  client: this.phClient,
272
271
  distinctId: posthogDistinctId,
@@ -280,10 +279,10 @@ class WrappedModels {
280
279
  params: params,
281
280
  httpStatus: 200,
282
281
  usage: {
283
- inputTokens: response.usageMetadata?.promptTokenCount ?? 0,
284
- outputTokens: response.usageMetadata?.candidatesTokenCount ?? 0,
285
- reasoningTokens: response.usageMetadata?.thoughtsTokenCount ?? 0,
286
- cacheReadInputTokens: response.usageMetadata?.cachedContentTokenCount ?? 0
282
+ inputTokens: metadata?.promptTokenCount ?? 0,
283
+ outputTokens: metadata?.candidatesTokenCount ?? 0,
284
+ reasoningTokens: metadata?.thoughtsTokenCount ?? 0,
285
+ cacheReadInputTokens: metadata?.cachedContentTokenCount ?? 0
287
286
  },
288
287
  tools: availableTools,
289
288
  captureImmediate: posthogCaptureImmediate
@@ -325,7 +324,7 @@ class WrappedModels {
325
324
  } = params;
326
325
  const traceId = posthogTraceId ?? uuid.v4();
327
326
  const startTime = Date.now();
328
- let accumulatedContent = '';
327
+ const accumulatedContent = [];
329
328
  let usage = {
330
329
  inputTokens: 0,
331
330
  outputTokens: 0
@@ -333,21 +332,69 @@ class WrappedModels {
333
332
  try {
334
333
  const stream = await this.client.models.generateContentStream(geminiParams);
335
334
  for await (const chunk of stream) {
335
+ // Handle text content
336
336
  if (chunk.text) {
337
- accumulatedContent += chunk.text;
337
+ // Find if we already have a text item to append to
338
+ let lastTextItem;
339
+ for (let i = accumulatedContent.length - 1; i >= 0; i--) {
340
+ if (accumulatedContent[i].type === 'text') {
341
+ lastTextItem = accumulatedContent[i];
342
+ break;
343
+ }
344
+ }
345
+ if (lastTextItem && lastTextItem.type === 'text') {
346
+ lastTextItem.text += chunk.text;
347
+ } else {
348
+ accumulatedContent.push({
349
+ type: 'text',
350
+ text: chunk.text
351
+ });
352
+ }
338
353
  }
354
+
355
+ // Handle function calls from candidates
356
+ if (chunk.candidates && Array.isArray(chunk.candidates)) {
357
+ for (const candidate of chunk.candidates) {
358
+ if (candidate.content && candidate.content.parts) {
359
+ for (const part of candidate.content.parts) {
360
+ // Type-safe check for functionCall
361
+ if ('functionCall' in part) {
362
+ const funcCall = part.functionCall;
363
+ if (funcCall?.name) {
364
+ accumulatedContent.push({
365
+ type: 'function',
366
+ function: {
367
+ name: funcCall.name,
368
+ arguments: funcCall.args || {}
369
+ }
370
+ });
371
+ }
372
+ }
373
+ }
374
+ }
375
+ }
376
+ }
377
+
378
+ // Update usage metadata - handle both old and new field names
339
379
  if (chunk.usageMetadata) {
380
+ const metadata = chunk.usageMetadata;
340
381
  usage = {
341
- inputTokens: chunk.usageMetadata.promptTokenCount ?? 0,
342
- outputTokens: chunk.usageMetadata.candidatesTokenCount ?? 0,
343
- reasoningTokens: chunk.usageMetadata.thoughtsTokenCount ?? 0,
344
- cacheReadInputTokens: chunk.usageMetadata.cachedContentTokenCount ?? 0
382
+ inputTokens: metadata.promptTokenCount ?? 0,
383
+ outputTokens: metadata.candidatesTokenCount ?? 0,
384
+ reasoningTokens: metadata.thoughtsTokenCount ?? 0,
385
+ cacheReadInputTokens: metadata.cachedContentTokenCount ?? 0
345
386
  };
346
387
  }
347
388
  yield chunk;
348
389
  }
349
390
  const latency = (Date.now() - startTime) / 1000;
350
391
  const availableTools = extractAvailableToolCalls('gemini', geminiParams);
392
+
393
+ // Format output similar to formatResponseGemini
394
+ const output = accumulatedContent.length > 0 ? [{
395
+ role: 'assistant',
396
+ content: accumulatedContent
397
+ }] : [];
351
398
  await sendEventToPosthog({
352
399
  client: this.phClient,
353
400
  distinctId: posthogDistinctId,
@@ -355,10 +402,7 @@ class WrappedModels {
355
402
  model: geminiParams.model,
356
403
  provider: 'gemini',
357
404
  input: this.formatInputForPostHog(geminiParams.contents),
358
- output: [{
359
- content: accumulatedContent,
360
- role: 'assistant'
361
- }],
405
+ output,
362
406
  latency,
363
407
  baseURL: 'https://generativelanguage.googleapis.com',
364
408
  params: params,
@@ -408,22 +452,28 @@ class WrappedModels {
408
452
  };
409
453
  }
410
454
  if (item && typeof item === 'object') {
411
- if (item.text) {
455
+ const obj = item;
456
+ if ('text' in obj && obj.text) {
412
457
  return {
413
- role: item.role || 'user',
414
- content: item.text
458
+ role: obj.role || 'user',
459
+ content: obj.text
415
460
  };
416
461
  }
417
- if (item.content) {
462
+ if ('content' in obj && obj.content) {
418
463
  return {
419
- role: item.role || 'user',
420
- content: item.content
464
+ role: obj.role || 'user',
465
+ content: obj.content
421
466
  };
422
467
  }
423
- if (item.parts) {
468
+ if ('parts' in obj && Array.isArray(obj.parts)) {
424
469
  return {
425
- role: item.role || 'user',
426
- content: item.parts.map(part => part.text ? part.text : part)
470
+ role: obj.role || 'user',
471
+ content: obj.parts.map(part => {
472
+ if (part && typeof part === 'object' && 'text' in part) {
473
+ return part.text;
474
+ }
475
+ return part;
476
+ })
427
477
  };
428
478
  }
429
479
  }
@@ -434,16 +484,17 @@ class WrappedModels {
434
484
  });
435
485
  }
436
486
  if (contents && typeof contents === 'object') {
437
- if (contents.text) {
487
+ const obj = contents;
488
+ if ('text' in obj && obj.text) {
438
489
  return [{
439
490
  role: 'user',
440
- content: contents.text
491
+ content: obj.text
441
492
  }];
442
493
  }
443
- if (contents.content) {
494
+ if ('content' in obj && obj.content) {
444
495
  return [{
445
496
  role: 'user',
446
- content: contents.content
497
+ content: obj.content
447
498
  }];
448
499
  }
449
500
  }